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