1 /** 2 Only exists to test the wrapping functionality Contains functions 3 with regular D types that will get wrapped so they can be called by 4 the spreadsheet. 5 */ 6 7 module test.d_funcs; 8 9 version(unittest): 10 11 import xlld; 12 import std.datetime: DateTime; 13 14 15 /// 16 @Register(ArgumentText("Array to add"), 17 HelpTopic("Adds all cells in an array"), 18 FunctionHelp("Adds all cells in an array"), 19 ArgumentHelp(["The array to add"])) 20 double FuncAddEverything(double[][] args) nothrow @nogc { 21 import std.algorithm: fold; 22 import std.math: isNaN; 23 24 double ret = 0; 25 foreach(row; args) 26 ret += row.fold!((a, b) => b.isNaN ? 0.0 : a + b)(0.0); 27 return ret; 28 } 29 30 /// 31 double[][] FuncTripleEverything(double[][] args) nothrow { 32 double[][] ret; 33 ret.length = args.length; 34 foreach(i; 0 .. args.length) { 35 ret[i].length = args[i].length; 36 foreach(j; 0 .. args[i].length) 37 ret[i][j] = args[i][j] * 3; 38 } 39 40 return ret; 41 } 42 43 /// 44 double FuncAllLengths(string[][] args) nothrow @nogc { 45 import std.algorithm: fold; 46 47 double ret = 0; 48 foreach(row; args) 49 ret += row.fold!((a, b) => a + b.length)(0.0); 50 return ret; 51 } 52 53 /// 54 double[][] FuncLengths(string[][] args) nothrow { 55 double[][] ret; 56 57 ret.length = args.length; 58 foreach(i; 0 .. args.length) { 59 ret[i].length = args[i].length; 60 foreach(j; 0 .. args[i].length) 61 ret[i][j] = args[i][j].length; 62 } 63 64 return ret; 65 } 66 67 68 /// 69 string[][] FuncBob(string[][] args) nothrow { 70 string[][] ret; 71 72 ret.length = args.length; 73 foreach(i; 0 .. args.length) { 74 ret[i].length = args[i].length; 75 foreach(j; 0 .. args[i].length) 76 ret[i][j] = args[i][j] ~ "bob"; 77 } 78 79 return ret; 80 } 81 82 83 /// 84 double FuncDoubleSlice(double[] arg) nothrow @nogc { 85 return arg.length; 86 } 87 88 /// 89 double FuncStringSlice(string[] arg) nothrow @nogc { 90 return arg.length; 91 } 92 93 /// 94 double[] FuncSliceTimes3(double[] arg) nothrow { 95 import std.algorithm; 96 import std.array; 97 return arg.map!(a => a * 3).array; 98 } 99 100 /// 101 string[] StringsToStrings(string[] args) nothrow { 102 import std.algorithm; 103 import std.array; 104 return args.map!(a => a ~ "foo").array; 105 } 106 107 /// 108 string StringsToString(string[] args) nothrow { 109 import std..string; 110 return args.join(", "); 111 } 112 113 /// 114 string StringToString(string arg) nothrow { 115 return arg ~ "bar"; 116 } 117 118 private string shouldNotBeAProblem(string, string[]) nothrow { 119 return ""; 120 } 121 122 /// 123 string ManyToString(string arg0, string arg1, string arg2) nothrow { 124 return arg0 ~ arg1 ~ arg2; 125 } 126 127 // shouldn't get wrapped 128 double FuncThrows(double) { 129 throw new Exception("oops"); 130 } 131 132 /// 133 double FuncAsserts(double) { 134 assert(false); 135 } 136 137 138 /** 139 @Dispose is used to tell the framework how to free memory that is dynamically 140 allocated by the D function. After returning, the value is converted to an 141 Excel type sand the D value is freed using the lambda defined here. 142 In this example we're using TestAllocator to make sure that there are no 143 memory leaks. 144 */ 145 @Dispose!((ret) { 146 import xlld.test.util: gTestAllocator; 147 import std.experimental.allocator: dispose; 148 gTestAllocator.dispose(ret); 149 }) 150 151 /// 152 double[] FuncReturnArrayNoGc(double[] numbers) @nogc @safe nothrow { 153 import xlld.test.util: gTestAllocator; 154 import std.experimental.allocator: makeArray; 155 import std.algorithm: map; 156 157 try { 158 return () @trusted { return gTestAllocator.makeArray(numbers.map!(a => a * 2)); }(); 159 } catch(Exception _) { 160 return []; 161 } 162 } 163 164 165 /// 166 Any[][] DoubleArrayToAnyArray(double[][] values) @safe nothrow { 167 import std.experimental.allocator.mallocator: Mallocator; 168 import std.conv: to; 169 170 alias allocator = Mallocator.instance; 171 172 string third, fourth; 173 try { 174 third = values[1][0].to!string; 175 fourth = values[1][1].to!string; 176 } catch(Exception ex) { 177 third = "oops"; 178 fourth = "oops"; 179 } 180 181 return () @trusted { 182 with(allocatorContext(allocator)) { 183 try 184 return [ 185 [any(values[0][0] * 2), any(values[0][1] * 3)], 186 [any(third ~ "quux"), any(fourth ~ "toto")], 187 ]; 188 catch(Exception _) { 189 Any[][] empty; 190 return empty; 191 } 192 } 193 }(); 194 } 195 196 197 /// 198 double[] AnyArrayToDoubleArray(Any[][] values) nothrow { 199 return [values.length, values.length ? values[0].length : 0]; 200 } 201 202 203 /// 204 Any[][] AnyArrayToAnyArray(Any[][] values) nothrow { 205 return values; 206 } 207 208 /// 209 Any[][] FirstOfTwoAnyArrays(Any[][] a, Any[][]) nothrow { 210 return a; 211 } 212 213 /// 214 string[] EmptyStrings1D(Any) nothrow { 215 string[] empty; 216 return empty; 217 } 218 219 220 /// 221 string[][] EmptyStrings2D(Any) nothrow { 222 string[][] empty; 223 return empty; 224 } 225 226 /// 227 string[][] EmptyStringsHalfEmpty2D(Any) nothrow { 228 string[][] empty; 229 empty.length = 1; 230 assert(empty[0].length == 0); 231 return empty; 232 } 233 234 /// 235 int Twice(int i) @safe nothrow { 236 return i * 2; 237 } 238 239 /// 240 double FuncConstDouble(const double a) @safe nothrow { 241 return a; 242 } 243 244 double DateTimeToDouble(DateTime d) @safe nothrow { 245 return d.year * 2; 246 } 247 248 string DateTimesToString(DateTime[] ds) @safe nothrow { 249 import std.algorithm: map; 250 import std..string: join; 251 import std.conv: text; 252 return ds.map!(d => d.day.text).join(", "); 253 } 254 255 256 @Async 257 double AsyncDoubleToDouble(double d) @safe nothrow { 258 return d * 2; 259 } 260 261 import core.stdc.stdio; 262 double Overloaded(double d) @safe @nogc nothrow { 263 () @trusted { printf("double\n"); }(); 264 return d * 2; 265 } 266 267 double Overloaded(string s) @safe @nogc nothrow { 268 () @trusted { printf("string\n"); }(); 269 return s.length; 270 } 271 272 double NaN() { 273 return double.init; 274 } 275 276 int BoolToInt(bool b) { 277 return cast(int)b; 278 } 279 280 enum MyEnum { 281 foo, bar, baz, 282 } 283 284 string FuncMyEnumArg(MyEnum val) @safe { 285 import std.conv: text; 286 return "prefix_" ~ val.text; 287 } 288 289 MyEnum FuncMyEnumRet(int i) @safe { 290 return cast(MyEnum)i; 291 } 292 293 struct Point { 294 int x, y; 295 } 296 297 int FuncPointArg(Point p) @safe { 298 return p.x + p.y; 299 } 300 301 Point FuncPointRet(int x, int y) @safe { 302 return Point(x, y); 303 }