1 /*******************************************************************************
2 
3     Static reflection templates specific to various function-like types
4 
5     NB: because this module is often used as purely compile-time dependency it
6         used built-in asserts instead of `ocean.core.Test` to reduce amount of
7         cyclic imports. `ocean.meta` modules in general are not supposed to
8         import anything outside of `ocean.meta`.
9 
10     Copyright:
11         Copyright (c) 2017 dunnhumby Germany GmbH. All rights reserved.
12 
13     License:
14         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
15         Alternatively, this file may be distributed under the terms of the Tango
16         3-Clause BSD License (see LICENSE_BSD.txt for details).
17 
18 *******************************************************************************/
19 
20 module ocean.meta.types.Function;
21 
22 import ocean.meta.AliasSeq;
23 import ocean.meta.traits.Basic;
24 import ocean.meta.types.Typedef;
25 
26 /*******************************************************************************
27 
28     Evaluates to a compile-time sequence representing the parameters of
29     Callable
30 
31     Params:
32         Callable = callable type (function/delegate/function pointer) or
33             function symbol. Represented by variadic template of length 1 to
34             accept both types and function symbols.
35 
36 *******************************************************************************/
37 
38 public template ParametersOf ( Callable... )
39 {
40     static assert (Callable.length == 1);
41 
42     static if (is(Callable[0] Params == function))
43         alias AliasSeq!(Params) ParametersOf;
44     else static if (is(typeof(Callable[0]) Params == function))
45         alias AliasSeq!(Params) ParametersOf;
46     else static if (is(Callable[0] TDgPtr == delegate))
47         alias AliasSeq!(ParametersOf!(TDgPtr)) ParametersOf;
48     else static if (is(Callable[0] TFunc == TFunc*))
49         alias AliasSeq!(ParametersOf!(TFunc)) ParametersOf;
50     else static if (isTypedef!(Callable[0]))
51         alias ParametersOf!(TypedefBaseType!(Callable[0])) ParametersOf;
52     else
53         static assert (false, "Argument is not a function");
54 }
55 
56 ///
57 unittest
58 {
59     void foo(int x, ref double y, char[] z) {}
60     alias ParametersOf!(typeof(foo)) Params;
61 
62     static assert (Params.length == 3);
63     static assert (is(Params[0] == int));
64     static assert (is(Params[1] == double));
65     static assert (is(Params[2] == char[]));
66 }
67 
68 unittest
69 {
70     void foo(int x, ref double y, char[] z) {}
71     alias ParametersOf!(typeof(&foo)) Params;
72 
73     static assert (Params.length == 3);
74     static assert (is(Params[0] == int));
75     static assert (is(Params[1] == double));
76     static assert (is(Params[2] == char[]));
77 }
78 
79 unittest
80 {
81     void delegate(int x, ref double y, char[] z) dg;
82     alias ParametersOf!(typeof(dg)) Params;
83 
84     static assert (Params.length == 3);
85     static assert (is(Params[0] == int));
86     static assert (is(Params[1] == double));
87     static assert (is(Params[2] == char[]));
88 }
89 
90 /*******************************************************************************
91 
92     Deduces return type of a callable
93 
94     Params:
95         Callable = callable type (function/delegate/function pointer) or
96             function symbol. Represented by variadic template of length 1 to
97             accept both types and function symbols.
98 
99     Returns:
100         evaluates to return type of the callable
101 
102 *******************************************************************************/
103 
104 public template ReturnTypeOf ( Callable... )
105 {
106     static assert (Callable.length == 1);
107 
108     static if (is(typeof(Callable[0]) == function))
109     {
110         alias typeof({
111                 ParametersOf!(Callable[0]) args;
112                 return Callable[0](args);
113             } ()) ReturnTypeOf;
114     }
115     else
116     {
117         alias typeof({
118                 ParametersOf!(Callable[0]) args;
119                 Callable[0] call;
120                 return call(args);
121             } ()) ReturnTypeOf;
122     }
123 }
124 
125 ///
126 unittest
127 {
128     static assert (is(ReturnTypeOf!(void function()) == void));
129     static assert (is(ReturnTypeOf!(int function(char)) == int));
130     static assert (is(ReturnTypeOf!(int delegate(char)) == int));
131 
132     double foo ( char[], int ) { return 0; }
133     static assert (is(ReturnTypeOf!(foo) == double));
134     static assert (is(ReturnTypeOf!(typeof(&foo)) == double));
135 
136     static assert (is(ReturnTypeOf!(int delegate(ref int)) == int));
137 }
138 
139 unittest
140 {
141     mixin (Typedef!(int, "MyType"));
142     MyType foo2() { return MyType.init; }
143     static assert (is(ReturnTypeOf!(foo2) == MyType));
144 
145     mixin (Typedef!(double function(), "MyFuncType"));
146     alias ReturnTypeOf!(MyFuncType) X;
147     static assert (is(ReturnTypeOf!(MyFuncType) == double));
148 }