1 /**
2    Interface for registering worksheet functions with Excel
3  */
4 module xlld.worksheet;
5 
6 /**
7  Simple wrapper struct for a value. Provides a type-safe way
8  of making sure positional arguments match the intended semantics,
9  which is important given that nearly all of the arguments for
10  worksheet function registration are of the same type: wstring
11  ST is short for "SmallType".
12  */
13 private mixin template ST(string name, T = wstring) {
14     mixin(`struct ` ~ name ~ `{ T value; }`);
15 }
16 
17 struct Procedure {
18     wstring value;
19     string toString() @safe pure const {
20         import std.conv: to;
21         return value.to!string;
22     }
23 }
24 
25 mixin ST!"TypeText";
26 mixin ST!"FunctionText";
27 mixin ST!"ArgumentText";
28 mixin ST!"MacroType";
29 mixin ST!"Category";
30 mixin ST!"ShortcutText";
31 mixin ST!"HelpTopic";
32 mixin ST!"FunctionHelp";
33 mixin ST!("ArgumentHelp", wstring[]);
34 
35 
36 /**
37    The arguments used to register a worksheet function with the spreadsheet.
38  */
39 struct WorksheetFunction {
40     // the first few parameters have to be set, the others are optional
41     Procedure procedure;
42     TypeText typeText;
43     FunctionText functionText;
44     Optional optional;
45     alias optional this; //for ease of use
46 
47     /**
48        Returns an array suitable for use with spreadsheet registration
49      */
50     const(wstring)[] toStringArray() @safe pure const nothrow {
51         return
52             [
53                 procedure.value, typeText.value,
54                 functionText.value, argumentText.value,
55                 macroType.value, category.value,
56                 shortcutText.value, helpTopic.value, functionHelp.value
57             ] ~ argumentHelp.value;
58     }
59 }
60 
61 // helper template to type-check variadic template constructor below
62 private alias toType(alias U) = typeof(U);
63 
64 /**
65    Optional arguments that can be set by a function author, but don't necessarily
66    have to be.
67  */
68 struct Optional {
69     ArgumentText argumentText;
70     MacroType macroType = MacroType("1"w);
71     Category category;
72     ShortcutText shortcutText;
73     HelpTopic helpTopic;
74     FunctionHelp functionHelp;
75     ArgumentHelp argumentHelp;
76 
77     this(T...)(T args) {
78         import std.meta: staticIndexOf, staticMap, allSatisfy, AliasSeq;
79         import std.conv: text;
80 
81         static assert(T.length <= this.tupleof.length, "Too many arguments for Optional/Register");
82 
83         // myTypes: ArgumentText, MacroType, ...
84         alias myTypes = staticMap!(toType, AliasSeq!(this.tupleof));
85         enum isOneOfMyTypes(U) = staticIndexOf!(U, myTypes) != -1;
86         static assert(allSatisfy!(isOneOfMyTypes, T),
87                       text("Unknown types passed to Optional/Register constructor. ",
88                            "Has to be one of:\n", myTypes.stringof));
89 
90         // loop over whatever was given and set each of our members based on the
91         // type of the parameter instead of by position
92         foreach(ref member; this.tupleof) {
93             enum index = staticIndexOf!(typeof(member), T);
94             static if(index != -1)
95                 member = args[index];
96         }
97     }
98 }
99 
100 /**
101     A user-facing name to use as an UDA to decorate D functions.
102     Any arguments passed to its constructor will be used to register
103     the function with the spreadsheet.
104 */
105 alias Register = Optional;
106 
107 
108 struct Dispose(alias function_) {
109     alias dispose = function_;
110 }