1 /*******************************************************************************
2 
3     Functions to help with type conversion.
4 
5     Copyright:
6         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
7         All rights reserved.
8 
9     License:
10         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
11         Alternatively, this file may be distributed under the terms of the Tango
12         3-Clause BSD License (see LICENSE_BSD.txt for details).
13 
14 *******************************************************************************/
15 
16 module ocean.core.TypeConvert;
17 
18 import ocean.meta.traits.Indirections;
19 import ocean.meta.types.Qualifiers;
20 import ocean.meta.types.Function;
21 import ocean.meta.types.Typedef;
22 
23 version (unittest) import ocean.core.Test;
24 
25 
26 /*******************************************************************************
27 
28     Trivial wrapper for a cast from any array to an array of immutable elements
29     (e.g. from any string to an immutable string), to make code more readable.
30     Its use is only legal if no one else has a reference to the contents of the
31     `input` array.  Cf. `std.exception.assumeUnique` in Phobos.
32 
33     Params:
34         input = slice whose contents to cast to immutable; this reference
35             will be nullified to prevent any further access from this
36             mutable handle
37 
38     Returns:
39         slice of immutable elements corresponding to the same segment of
40         memory referred to by `input`
41 
42     Note:
43         D1 does not allow overloading on rvalue vs lvalue, nor does it have
44         anything similar to D2's `auto ref` feature.  At the same time, to
45         match Phobos semantics we need to nullify the slice that gets cast
46         to immutable.  Because of this in D1 `assumeUnique` accepts only
47         rvalues: use temporary local variables to assign lvalues if any
48         need to be used with `assumeUnique`.
49 
50         D2 programs can use lvalues as well as rvalues.
51 
52     Credits:
53         This function is copied from phobos `std.exception.assumeUnique`
54         ((c) Andrei Alexandrescu, Boost license) with minor modifications.
55 
56 *******************************************************************************/
57 
58 public immutable(T)[] assumeUnique (T) (T[] input)
59 {
60     return .assumeUnique(input);
61 }
62 
63 unittest
64 {
65     auto s = assumeUnique("1234".dup);
66     static assert(is(typeof(s) == istring));
67     test!("==")(s, "1234");
68 }
69 
70 public immutable(T)[] assumeUnique (T) (ref T[] input)
71 {
72     auto tmp = input;
73     input = null;
74     return cast(immutable(T)[]) tmp;
75 }
76 
77 unittest
78 {
79     auto s1 = "aaa".dup;
80     auto s2 = assumeUnique(s1);
81     test!("==")(s2, "aaa");
82     test!("is")(s1, mstring.init);
83 }
84 
85 
86 /*******************************************************************************
87 
88     Casts an object of one class to another class. Using this function is safer
89     than a plain cast, as it also statically ensures that the variable being
90     cast from is a class or an interface.
91 
92     Params:
93         To = type to cast to (must be a class)
94         From = type to cast from (must be a class or interface)
95         value = object to be cast to type To
96 
97     Returns:
98         input parameter cast to type To. The returned object may be null if the
99         From cannot be downcast to To
100 
101 *******************************************************************************/
102 
103 public To downcast ( To, From ) ( From value )
104 {
105     static assert(is(To == class));
106     static assert(is(From == class) || is(From == interface));
107 
108     return cast(To)value;
109 }
110 
111 version (unittest)
112 {
113     class A { }
114     class B : A { }
115     interface I { }
116     class C : I { }
117 }
118 
119 unittest
120 {
121     // Basic type does not compile
122     static assert(!is(typeof({ int i; downcast!(Object)(i); })));
123 
124     // Pointer to object does not compile
125     static assert(!is(typeof({ Object* o; downcast!(Object)(o); })));
126 
127     // Object compiles
128     static assert(is(typeof({ Object o; downcast!(Object)(o); })));
129 
130     // Interface compiles
131     static assert(is(typeof({ I i; downcast!(Object)(i); })));
132 
133     // Downcast succeeds for derived class
134     {
135         A a = new B;
136         B b = downcast!(B)(a);
137         test!("!is")(cast(void*)b, null);
138     }
139 
140     // Downcast succeeds for derived interface
141     {
142         I i = new C;
143         C c = downcast!(C)(i);
144         test!("!is")(cast(void*)c, null);
145     }
146 
147     // Downcast fails for non-derived class
148     {
149         A a = new B;
150         C c = downcast!(C)(a);
151         test!("is")(cast(void*)c, null);
152     }
153 
154     // Downcast fails for non-derived interface
155     {
156         I i = new C;
157         B b = downcast!(B)(i);
158         test!("is")(cast(void*)b, null);
159     }
160 }
161 
162 
163 /*******************************************************************************
164 
165     Explicit cast function -- both from and to types must be specified by the
166     user and are statically ensured to be correct. This extra security can help
167     prevent refactoring errors.
168 
169     Usage:
170     ---
171         int i;
172         float f = castFrom!(int).to!(float)(i);
173     ---
174 
175     Params:
176         From = type to cast from
177 
178 ******************************************************************************/
179 
180 template castFrom ( From )
181 {
182 
183     /*************************************************************************
184 
185         Explicit cast function -- both from and to types must be specified by
186         the user and are statically ensured to be correct. This extra security
187         can help prevent refactoring errors.
188 
189         Usage:
190         ---
191             int i;
192             float f = castFrom!(int).to!(float)(i);
193         ---
194 
195         Params:
196             From = type to cast from
197             To = type to cast to
198             T = type of value being cast (statically checked to be == From)
199             value = value to be cast to type To
200 
201         Returns:
202             input parameter cast to type To
203 
204     **************************************************************************/
205 
206     To to ( To, T ) ( T value )
207     {
208         static assert(
209             is(From == T),
210             "the value to cast is not of specified type '" ~ From.stringof ~
211             "', it is of type '" ~ T.stringof ~ "'"
212         );
213 
214         static assert(
215             is(typeof(cast(To)value)),
216             "can't cast from '" ~ From.stringof ~ "' to '" ~ To.stringof ~ "'"
217         );
218 
219         return cast(To)value;
220     }
221 }
222 
223 unittest
224 {
225     // Mismatched From does not compile
226     static assert(!is(typeof({ int x; castFrom!(float).to!(char)(x); })));
227 
228     // Mismatched but implicitly castable From does not compile
229     static assert(!is(typeof({ double x; castFrom!(float).to!(char)(x); })));
230 
231     // Illegal cast does not compile
232     static assert(!is(typeof({ void* p; castFrom!(void*).to!(int[30])(p); })));
233 
234     // Valid case compiles
235     static assert(is(typeof({ int x; castFrom!(int).to!(float)(x); })));
236 }
237 
238 
239 /*******************************************************************************
240 
241     Creates a new array from the elements supplied as function arguments,
242     casting each of them to T.
243 
244     Params:
245         T = type of element of new array
246         original = original elements of a type that can be cast to T safely
247 
248 /******************************************************************************/
249 
250 template arrayOf (T)
251 {
252     T[] arrayOf (U...) (U original)
253     {
254         static assert (U.length > 0);
255         static assert (!hasIndirections!(U[0]));
256         static assert (!hasIndirections!(T));
257 
258         // workaround for dmd1 semantic analysis bug
259         auto unused = original[0];
260 
261         static istring generateCast ( )
262         {
263             istring result = "[ ";
264 
265             foreach (i, _; U)
266             {
267                 result ~= "cast(T) original[" ~ i.stringof ~ "]";
268                 if (i + 1 < U.length)
269                     result ~= ", ";
270             }
271 
272             return result ~ " ]";
273         }
274 
275         return mixin(generateCast());
276     }
277 }
278 
279 version (unittest)
280 {
281     static immutable _arrayOf_global_scope = arrayOf!(byte)(1, 2, 3);
282 }
283 
284 ///
285 unittest
286 {
287     auto arr = arrayOf!(hash_t)(1, 2, 3);
288     test!("==")(arr, [ cast(hash_t) 1, 2, 3 ][]);
289 }
290 
291 unittest
292 {
293     // ensure it works with Typedef structs in D2
294     mixin (Typedef!(hash_t, "Hash"));
295     auto arr = arrayOf!(Hash)(1, 2, 3);
296 
297     // ensure it works in CTFE
298     static immutable manifest = arrayOf!(long)(42, 44, 46);
299     static assert (manifest.length == 3);
300     static assert (manifest[0] == 42L);
301     static assert (manifest[1] == 44L);
302     static assert (manifest[2] == 46L);
303 
304     // reject stuff with indirections
305     static assert (!is(typeof(arrayOf!(int*)(1000))));
306     static assert (!is(typeof(arrayOf!(int)((int[]).init))));
307 }
308 
309 
310 /*******************************************************************************
311 
312     Generates delegate that stores specified `context` as a delegate context
313     pointer and, when called, forwards it to function `F` as a regular argument.
314 
315     Intended to be used as a performance optimization hack to create
316     no-allocation closures that only need to capture one pointer size argument.
317 
318     Params:
319         F = function to call when delegate is called, must take exactly one
320             void* argument which is the passed context
321         context = context pointer to forward to F when resulting delegate is
322             called
323 
324     Returns:
325         forged delegate that can be passed to any API expecting regular `T
326         delegate()` where T is the return type of F
327 
328 *******************************************************************************/
329 
330 ReturnTypeOf!(F) delegate() toContextDg ( alias F ) ( void* context )
331 {
332     static assert (is(typeof({ F((void*).init); })));
333 
334     // This code makes use of two facts:
335     //    1) The D ABI allows aggregate methods to be converted to delegates,
336     //       such that the delegate context pointer becomes the `this` pointer
337     //       of the aggregate
338     //    2) The compiler supports explicit modification of the .ptr member of a
339     //       delegate, without modifying the existing .functptr.
340 
341     static struct Fake
342     {
343         ReturnTypeOf!(F) method ( )
344         {
345             void* context = cast(void*) &this;
346 
347             // do real work via provided F function:
348             return F(context);
349         }
350     }
351 
352     auto dg = &Fake.init.method;
353     dg.ptr = context;
354     return dg;
355 }
356 
357 ///
358 unittest
359 {
360     static bool done = false;
361 
362     static void handler ( void* context )
363     {
364         test!("==")(cast(size_t) context, 42);
365         done = true;
366     }
367 
368     void delegate() dg = toContextDg!(handler)(cast(void*) 42);
369     test!("==")(cast(size_t) dg.ptr, 42);
370     dg();
371     test(done);
372 }
373 
374 /*******************************************************************************
375 
376     Helper function to wrap any callable type in a delegate. Most useful when
377     you need to pass function pointer as a delegate argument.
378 
379     This function allocates a closure class for a delegate.
380 
381     NB! toDg does not preserve any argument attributes of Func such as ref or
382     lazy.
383 
384     Params:
385         f = function or function pointer or delegate
386 
387     Returns:
388         delegate that internally calls f and does nothing else
389 
390 *******************************************************************************/
391 
392 ReturnTypeOf!(Func) delegate (ParametersOf!(Func)) toDg ( Func ) ( Func f )
393 {
394     static assert (
395         is(Func == ReturnTypeOf!(Func) function (ParametersOf!(Func))),
396         "toDg does not preserve argument attributes!"
397     );
398 
399     alias ParametersOf!(Func) ParameterTypes;
400 
401     class Closure
402     {
403         private Func func;
404 
405         this (Func func)
406         {
407             this.func = func;
408         }
409 
410         ReturnTypeOf!(Func) call (ParameterTypes args)
411         {
412             return this.func(args);
413         }
414     }
415 
416     auto closure = new Closure(f);
417 
418     return &closure.call;
419 }
420 
421 version (unittest)
422 {
423     int testToDgFoo() { return 42; }
424 
425     void testToDgBar(int a, int b)
426     {
427         assert (a == 3);
428         assert (b == 4);
429     }
430 
431     int testToDgBad(ref int x) { return x; }
432 }
433 
434 unittest
435 {
436     static assert (is(typeof(toDg(&testToDgFoo)) == int delegate()));
437     test (toDg(&testToDgFoo)() == 42);
438 
439     toDg(&testToDgBar)(3, 4);
440 
441     static assert(!is(typeof(toDg(&testToDgBad))));
442 }