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     const bool opEquals(const WorksheetFunction rhs) @safe pure { return optional == rhs.optional; }
62 }
63 
64 // helper template to type-check variadic template constructor below
65 private alias toType(alias U) = typeof(U);
66 
67 /**
68    Optional arguments that can be set by a function author, but don't necessarily
69    have to be.
70  */
71 struct Optional {
72     ArgumentText argumentText;
73     MacroType macroType = MacroType("1"w);
74     Category category;
75     ShortcutText shortcutText;
76     HelpTopic helpTopic;
77     FunctionHelp functionHelp;
78     ArgumentHelp argumentHelp;
79 
80     this(T...)(T args) {
81         import std.meta: staticIndexOf, staticMap, allSatisfy, AliasSeq;
82         import std.conv: text;
83 
84         static assert(T.length <= this.tupleof.length, "Too many arguments for Optional/Register");
85 
86         // myTypes: ArgumentText, MacroType, ...
87         alias myTypes = staticMap!(toType, AliasSeq!(this.tupleof));
88         enum isOneOfMyTypes(U) = staticIndexOf!(U, myTypes) != -1;
89         static assert(allSatisfy!(isOneOfMyTypes, T),
90                       text("Unknown types passed to Optional/Register constructor. ",
91                            "Has to be one of:\n", myTypes.stringof));
92 
93         // loop over whatever was given and set each of our members based on the
94         // type of the parameter instead of by position
95         foreach(ref member; this.tupleof) {
96             enum index = staticIndexOf!(typeof(member), T);
97             static if(index != -1)
98                 member = args[index];
99         }
100     }
101 }
102 
103 /**
104     A user-facing name to use as an UDA to decorate D functions.
105     Any arguments passed to its constructor will be used to register
106     the function with the spreadsheet.
107 */
108 alias Register = Optional;
109 alias Excel = Optional;
110 
111 
112 ///
113 struct Dispose(alias function_) {
114     alias dispose = function_;
115 }