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 std.datetime: DateTime;
12     import std.typecons: Tuple;
13     import std.traits: Unqual;
14 
15     enum isUserStruct =
16         is(T == struct) &&
17         !is(Unqual!T == Any) &&
18         !is(Unqual!T == DateTime) &&
19         !is(Unqual!T: Tuple!A, A...)
20         ;
21 }
22 
23 
24 ///
25 __gshared immutable gDupMemoryException = new Exception("Failed to allocate memory in dup");
26 
27 
28 /**
29    Deep copy of an oper
30  */
31 from!"xlld.sdk.xlcall".XLOPER12 dup(A)(from!"xlld.sdk.xlcall".XLOPER12 oper, ref A allocator) @safe {
32 
33     import xlld.sdk.xlcall: XLOPER12, XlType;
34     import std.experimental.allocator: makeArray;
35 
36     XLOPER12 ret;
37 
38     ret.xltype = oper.xltype;
39 
40     switch(stripMemoryBitmask(oper.xltype)) with(XlType) {
41 
42         default:
43             ret = oper;
44             return ret;
45 
46         case xltypeStr:
47             const length = operStringLength(oper) + 1;
48 
49             () @trusted {
50                 ret.val.str = allocator.makeArray!wchar(length).ptr;
51                 if(ret.val.str is null)
52                     throw gDupMemoryException;
53             }();
54 
55             () @trusted { ret.val.str[0 .. length] = oper.val.str[0 .. length]; }();
56             return ret;
57 
58         case xltypeMulti:
59             () @trusted {
60                 ret.val.array.rows = oper.val.array.rows;
61                 ret.val.array.columns = oper.val.array.columns;
62                 const length = oper.val.array.rows * oper.val.array.columns;
63                 ret.val.array.lparray = allocator.makeArray!XLOPER12(length).ptr;
64 
65                 if(ret.val.array.lparray is null)
66                     throw gDupMemoryException;
67 
68                 foreach(i; 0 .. length) {
69                     ret.val.array.lparray[i] = oper.val.array.lparray[i].dup(allocator);
70                 }
71             }();
72 
73             return ret;
74     }
75 
76     assert(0);
77 }
78 
79 
80 
81 from!"xlld.sdk.xlcall".XlType stripMemoryBitmask(in from!"xlld.sdk.xlcall".XlType type) @safe @nogc pure nothrow {
82     import xlld.sdk.xlcall: XlType, xlbitXLFree, xlbitDLLFree;
83     return cast(XlType)(type & ~(xlbitXLFree | xlbitDLLFree));
84 }
85 
86 ///
87 ushort operStringLength(T)(in T value) {
88     import xlld.sdk.xlcall: XlType;
89     import nogc.exception: enforce;
90 
91     enforce(value.xltype == XlType.xltypeStr,
92             "Cannot calculate string length for oper of type ", value.xltype);
93 
94     return cast(ushort)value.val.str[0];
95 }
96 
97 
98 // can't be pure because to!double isn't pure
99 string toString(in from!"xlld.sdk.xlcall".XLOPER12 oper) @safe {
100     import xlld.sdk.xlcall: XlType;
101     import xlld.conv.misc: stripMemoryBitmask;
102     import std.conv: text;
103     import std.format: format;
104 
105     string ret;
106 
107     ret ~= "XLOPER12(";
108     switch(stripMemoryBitmask(oper.xltype)) {
109     default:
110         ret ~= oper.xltype.stripMemoryBitmask.text;
111         break;
112 
113     case XlType.xltypeSRef:
114         import xlld.func.xl: Coerced;
115         auto coerced = () @trusted { return Coerced(&oper); }();
116         return "SRef[ " ~ coerced.toString ~ " ]";
117 
118     case XlType.xltypeNum:
119         ret ~= format!"%.6f"(oper.val.num);
120         break;
121 
122     case XlType.xltypeStr:
123         ret ~= `"`;
124         () @trusted {
125             const ulong length = oper.val.str[0];
126             ret ~= text(oper.val.str[1 .. 1 + length]);
127         }();
128         ret ~= `"`;
129         break;
130 
131     case XlType.xltypeInt:
132         ret ~= text(oper.val.w);
133         break;
134 
135     case XlType.xltypeBool:
136         ret ~= text(oper.val.bool_);
137         break;
138 
139     case XlType.xltypeErr:
140         ret ~= "ERROR";
141         break;
142 
143     case XlType.xltypeBigData:
144         () @trusted {
145             ret ~= "BIG(";
146             ret ~= text(oper.val.bigdata.h.hdata);
147             ret ~= ", ";
148             ret ~= text(oper.val.bigdata.cbData);
149             ret ~= ")";
150         }();
151     }
152     ret ~= ")";
153     return ret;
154 }
155 
156 ///
157 __gshared immutable multiMemoryException = new Exception("Failed to allocate memory for multi oper");
158 
159 from!"xlld.sdk.xlcall".XLOPER12 multi(A)(int rows, int cols, ref A allocator) @trusted {
160     import xlld.sdk.xlcall: XLOPER12, XlType;
161 
162     auto ret = XLOPER12();
163 
164     ret.xltype = XlType.xltypeMulti;
165     ret.val.array.rows = rows;
166     ret.val.array.columns = cols;
167 
168     ret.val.array.lparray = cast(XLOPER12*)allocator.allocate(rows * cols * ret.sizeof).ptr;
169     if(ret.val.array.lparray is null)
170         throw multiMemoryException;
171 
172     return ret;
173 }