1 /**
2    Miscelleanous functions that assist in type conversions.
3  */
4 module xlld.conv.misc;
5 
6 import xlld.from;
7 
8 ///
9 template isUserStruct(T) {
10     import xlld.any: Any;
11     import xlld.sdk.xlcall: XLOPER12;
12     import std.datetime: DateTime;
13     import std.typecons: Tuple;
14     import std.traits: Unqual;
15     import std.range.primitives: isInputRange;
16 
17     enum isUserStruct =
18         is(T == struct)
19         && !is(Unqual!T == Any)
20         && !is(Unqual!T == DateTime)
21         && !is(Unqual!T: Tuple!A, A...)
22         && !is(Unqual!T == XLOPER12)
23         && !isVector!T
24         && !isInputRange!T
25         ;
26 }
27 
28 template isVector(T) {
29     version(Have_automem) {
30         import automem.vector: Vector;
31         import std.traits: Unqual;
32         enum isVector = is(Unqual!T == Vector!(E,  A), E, A);
33     } else
34         enum isVector = false;
35 }
36 
37 
38 template isSomeString(T) {
39     import std.traits: isSomeString_ = isSomeString, Unqual;
40     enum isSomeString =
41         isSomeString_!T
42         || (isVector!T && is(Unqual!(typeof(T.init[0])) == char))
43         ;
44 }
45 
46 
47 template isTuple(T) {
48     import std.typecons: Tuple;
49     import std.traits: Unqual;
50     enum isTuple = is(Unqual!T: Tuple!A, A...);
51 }
52 
53 
54 template isSequence(T) {
55     import std.traits: isArray;
56     enum isSequence = isArray!T || isTuple!T || isVector!T;
57 }
58 
59 ///
60 __gshared immutable gDupMemoryException = new Exception("Failed to allocate memory in dup");
61 
62 
63 /**
64    Deep copy of an oper
65  */
66 from!"xlld.sdk.xlcall".XLOPER12 dup(A)(from!"xlld.sdk.xlcall".XLOPER12 oper, ref A allocator) @safe {
67 
68     import xlld.sdk.xlcall: XLOPER12, XlType;
69     import std.experimental.allocator: makeArray;
70 
71     XLOPER12 ret;
72 
73     ret.xltype = oper.xltype;
74 
75     switch(stripMemoryBitmask(oper.xltype)) with(XlType) {
76 
77         default:
78             ret = oper;
79             return ret;
80 
81         case xltypeStr:
82             const length = operStringLength(oper) + 1;
83 
84             () @trusted {
85                 ret.val.str = allocator.makeArray!wchar(length).ptr;
86                 if(ret.val.str is null)
87                     throw gDupMemoryException;
88             }();
89 
90             () @trusted { ret.val.str[0 .. length] = oper.val.str[0 .. length]; }();
91             return ret;
92 
93         case xltypeMulti:
94             () @trusted {
95                 ret.val.array.rows = oper.val.array.rows;
96                 ret.val.array.columns = oper.val.array.columns;
97                 const length = oper.val.array.rows * oper.val.array.columns;
98                 ret.val.array.lparray = allocator.makeArray!XLOPER12(length).ptr;
99 
100                 if(ret.val.array.lparray is null)
101                     throw gDupMemoryException;
102 
103                 foreach(i; 0 .. length) {
104                     ret.val.array.lparray[i] = oper.val.array.lparray[i].dup(allocator);
105                 }
106             }();
107 
108             return ret;
109     }
110 
111     assert(0);
112 }
113 
114 
115 
116 from!"xlld.sdk.xlcall".XlType stripMemoryBitmask(in from!"xlld.sdk.xlcall".XlType type) @safe @nogc pure nothrow {
117     import xlld.sdk.xlcall: XlType, xlbitXLFree, xlbitDLLFree;
118     return cast(XlType)(type & ~(xlbitXLFree | xlbitDLLFree));
119 }
120 
121 ///
122 ushort operStringLength(T)(in T value) {
123     import xlld.sdk.xlcall: XlType;
124     import nogc.exception: enforce;
125 
126     enforce(value.xltype.stripMemoryBitmask == XlType.xltypeStr,
127             "Cannot calculate string length for oper of type ", cast(int) value.xltype);
128 
129     return cast(ushort) value.val.str[0];
130 }
131 
132 
133 // can't be pure because to!double isn't pure
134 string toString(in from!"xlld.sdk.xlcall".XLOPER12 oper) @safe {
135     import xlld.sdk.xlcall: XlType;
136     import xlld.conv.misc: stripMemoryBitmask;
137     import std.conv: text;
138     import std.format: format;
139 
140     string ret;
141 
142     ret ~= "XLOPER12(";
143     switch(stripMemoryBitmask(oper.xltype)) {
144     default:
145         ret ~= oper.xltype.stripMemoryBitmask.text;
146         break;
147 
148     case XlType.xltypeSRef:
149         import xlld.func.xl: Coerced;
150         auto coerced = () @trusted { return Coerced(&oper); }();
151         return "SRef[ " ~ coerced.toString ~ " ]";
152 
153     case XlType.xltypeNum:
154         ret ~= format!"%.6f"(oper.val.num);
155         break;
156 
157     case XlType.xltypeStr:
158         ret ~= `"`;
159         () @trusted {
160             const ulong length = oper.val.str[0];
161             ret ~= text(oper.val.str[1 .. 1 + length]);
162         }();
163         ret ~= `"`;
164         break;
165 
166     case XlType.xltypeInt:
167         ret ~= text(oper.val.w);
168         break;
169 
170     case XlType.xltypeBool:
171         ret ~= text(oper.val.bool_);
172         break;
173 
174     case XlType.xltypeErr:
175         ret ~= "ERROR";
176         break;
177 
178     case XlType.xltypeBigData:
179         () @trusted {
180             ret ~= "BIG(";
181             ret ~= text(oper.val.bigdata.h.hdata);
182             ret ~= ", ";
183             ret ~= text(oper.val.bigdata.cbData);
184             ret ~= ")";
185         }();
186     }
187     ret ~= ")";
188     return ret;
189 }
190 
191 ///
192 __gshared immutable multiMemoryException = new Exception("Failed to allocate memory for multi oper");
193 
194 /// Returns an array XLOPER12
195 from!"xlld.sdk.xlcall".XLOPER12 multi(A)(int rows, int cols, ref A allocator) @trusted {
196     import xlld.sdk.xlcall: XLOPER12, XlType;
197 
198     auto ret = XLOPER12();
199 
200     ret.xltype = XlType.xltypeMulti;
201     () @trusted {
202         ret.val.array.rows = rows;
203         ret.val.array.columns = cols;
204     }();
205 
206     auto slice = allocator.allocate(rows * cols * ret.sizeof);
207     ret.val.array.lparray = () @trusted { return cast(XLOPER12*) slice.ptr; }();
208 
209     if(ret.val.array.lparray is null)
210         throw multiMemoryException;
211 
212     return ret;
213 }