1 /**
2    Easier calling of Excel12f
3  */
4 module xlld.func.framework;
5 
6 ///
7 __gshared immutable excel12Exception = new Exception("Error calling Excel12f");
8 
9 /**
10    D version of Excel12f. "D version" in the sense that the types
11    are all D types. Avoids having to manually convert to XLOPER12.
12    e.g. excel12(xlfFoo, 1.0, 2.0);
13 
14    Returns a value of type T to specified at compile time which
15    must be freed with xlld.memorymanager: autoFreeAllocator
16  */
17 T excel12(T, A...)(int xlfn, auto ref A args) @trusted {
18     import xlld.memorymanager: gTempAllocator, autoFreeAllocator;
19     import xlld.conv.from: fromXlOper;
20     import xlld.conv: toXlOper;
21     import xlld.sdk.xlcall: XLOPER12, LPXLOPER12, xlretSuccess;
22     import xlld.sdk.framework: Excel12f;
23     import std.meta: allSatisfy;
24     import std.traits: Unqual;
25     import std.experimental.allocator.gc_allocator: GCAllocator;
26     import std.experimental.allocator.mallocator: Mallocator;
27 
28     // doubles never need the allocator anyway, so we use Mallocator
29     // to guarantee @nogc when needed
30     enum nogc(T) = is(Unqual!T == double);
31     static if(allSatisfy!(nogc, A))
32         alias allocator = Mallocator.instance;
33     else
34         alias allocator = GCAllocator.instance;
35 
36     XLOPER12[A.length] operArgs;
37     LPXLOPER12[A.length] operArgPtrs;
38 
39     foreach(i, _; A) {
40         operArgs[i] = args[i].toXlOper(allocator);
41         operArgPtrs[i] = &operArgs[i];
42     }
43 
44     XLOPER12 result;
45     if(Excel12f(xlfn, &result, operArgPtrs) != xlretSuccess)
46         throw excel12Exception;
47 
48     return result.fromXlOper!T(autoFreeAllocator);
49 }
50 
51 /**
52    Version of excel12 that avoids automatic memory management
53    by asking the caller to supply a compile-time function
54    to call on the result.
55  */
56 auto excel12Then(alias F, A...)(int xlfn, auto ref A args) {
57     import std.traits: Parameters, Unqual, isArray, ReturnType;
58     import std.experimental.allocator: dispose;
59     import xlld.memorymanager: autoFreeAllocator;
60 
61     static assert(Parameters!F.length == 1, "Must pass function of one argument");
62     alias T = Parameters!F[0];
63     auto excelRet = excel12!T(xlfn, args);
64     static if(is(ReturnType!F == void))
65         F(excelRet);
66     else
67         auto ret = F(excelRet);
68 
69     static if(isArray!T) {
70         import std.range: ElementType;
71         alias RealType = Unqual!(ElementType!T)[];
72     } else
73         alias RealType = Unqual!T;
74 
75     void freeRet(U)() @trusted {
76         autoFreeAllocator.dispose(cast(U)excelRet);
77     }
78 
79     static if(__traits(compiles, freeRet!RealType()))
80         freeRet!RealType();
81 
82     static if(!is(ReturnType!F == void))
83         return ret;
84 }