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 }