1 module autowrap.csharp.common;
2 
3 public import std.datetime : DateTime, SysTime, Date, TimeOfDay, Duration;
4 public import std.range.primitives;
5 public import std.traits : Unqual;
6 
7 public enum isDateTimeType(T) = is(T == Unqual!Date) || is(T == Unqual!DateTime) || is(T == Unqual!SysTime) || is(T == Unqual!TimeOfDay) || is(T == Unqual!Duration);
8 public enum isDateTimeArrayType(T) = is(T == Unqual!(Date[])) || is(T == Unqual!(DateTime[])) || is(T == Unqual!(SysTime[])) || is(T == Unqual!(TimeOfDay[])) || is(T == Unqual!(Duration[]));
9 
10 enum string[] excludedMethods = ["toHash", "opEquals", "opCmp", "factory", "__ctor"];
11 
12 
13 package string getDLangInterfaceName(string moduleName, string aggName, string funcName) {
14     import std.algorithm : map;
15     import std..string : split;
16     import std.array : join;
17 
18     string name = "autowrap_csharp_";
19     name ~= moduleName.split(".").map!camelToPascalCase.join("_");
20 
21     if (aggName != string.init) {
22         name ~= camelToPascalCase(aggName) ~ "_";
23     }
24     name ~= camelToPascalCase(funcName);
25     return name;
26 }
27 
28 package string getDLangInterfaceName(string fqn, string funcName) {
29     import std.algorithm : map;
30     import std..string : split;
31     import std.array : join;
32     string name = "autowrap_csharp_";
33 
34     name ~= fqn.split(".").map!camelToPascalCase.join("_");
35     name ~= camelToPascalCase(funcName);
36     return name;
37 }
38 
39 package string getDLangSliceInterfaceName(string fqn, string funcName) {
40     import std.algorithm : map, among;
41     import std..string : split;
42     import std.array : join;
43 
44     string name = "autowrap_csharp_slice_";
45 
46     if (fqn.among("core.time.Duration", "autowrap.csharp.dlang.Marshalled_Duration"))
47         fqn = "Autowrap_Csharp_Boilerplate_Marshalled_Duration";
48     else if (fqn.among("std.datetime.date.DateTime", "std.datetime.date.Date", "std.datetime.date.TimeOfDay",
49                   "autowrap.csharp.dlang.Marshalled_std_datetime_date")) {
50         fqn = "Autowrap_Csharp_Boilerplate_Marshalled_std_datetime_date";
51     }
52     else if (fqn == "std.datetime.systime.SysTime")
53         fqn = "Autowrap_Csharp_Boilerplate_Marshalled_std_datetime_systime";
54 
55     name ~= fqn.split(".").map!camelToPascalCase.join("_");
56     name ~= camelToPascalCase(funcName);
57     return name;
58 }
59 
60 public string camelToPascalCase(string camel) {
61     import std.uni : toUpper;
62     import std.conv : to;
63     import std.range : dropOne;
64     return to!string(camel.front.toUpper()) ~ camel.dropOne();
65 }
66 
67 package template verifySupported(T)
68 {
69     static if(isSupportedType!T)
70         enum verifySupported = true;
71     else
72     {
73         pragma(msg, T.stringof ~ " is not currently supported by autowrap's C#");
74         enum verifySupported = false;
75     }
76 }
77 
78 package template numDefaultArgs(alias func)
79 {
80     import std.meta : Filter;
81     import std.traits : ParameterDefaults;
82 
83     enum numDefaultArgs = Filter!(isNotVoid, ParameterDefaults!func).length;
84 
85     private static template isNotVoid(values...)
86         if(values.length == 1)
87     {
88         enum isNotVoid = !is(values[0] == void);
89     }
90 }
91 
92 // Unfortunately, while these tests have been tested on their own, they don't
93 // currently run as part of autowrap's tests, because dub test doesn't work for
94 // the csharp folder, and the top level one does not run them.
95 unittest
96 {
97     import std.meta : AliasSeq;
98 
99     static void foo1() {}
100     static void foo2(int) {}
101     static void foo3(int, string) {}
102     static void foo4(int, string, int) {}
103 
104     foreach(f; AliasSeq!(foo1, foo2, foo3, foo4))
105         static assert(numDefaultArgs!f == 0);
106 
107     static void foo5(int i = 42) {}
108     static void foo6(int, string s = "hello") {}
109     static void foo7(int, string, int j = 97) {}
110 
111     foreach(f; AliasSeq!(foo5, foo6, foo7))
112         static assert(numDefaultArgs!f == 1);
113 
114     static void foo9(int i = 42, string s = "hello") {}
115     static void foo10(int, string s = "hello", int j = 97) {}
116 
117     foreach(f; AliasSeq!(foo9, foo10))
118         static assert(numDefaultArgs!f == 2);
119 
120     static void foo11(int i = 42, string s = "hello", int j = 97) {}
121 
122     static assert(numDefaultArgs!foo11 == 3);
123 }
124 
125 package template isFunctionType(T)
126 {
127     static if (is(T == function) || is(T == delegate))
128         enum isFunctionType = true;
129     else
130     {
131         import std.traits : isFunctionPointer;
132         enum isFunctionType = isFunctionPointer!T;
133     }
134 }
135 
136 package template isSupportedType(T)
137 {
138     import std.range.primitives : ElementType;
139     import std.traits : isBoolean, isDynamicArray, isIntegral, isSomeChar, Unqual, ReturnType, Parameters;
140 
141     static if(isIntegral!T || isBoolean!T || isSomeChar!T ||
142               is(Unqual!T == float) || is(Unqual!T == double) || is(T == void))
143     {
144         enum isSupportedType = true;
145     }
146     else static if(isDynamicArray!T)
147     {
148         alias E = ElementType!T;
149         enum isSupportedType = is(E == string) || is(E == wstring) || is(E == dstring) ||
150                                !isDynamicArray!E && isSupportedType!E;
151     }
152     else static if(is(T == struct) || is(T == class) || is(T == interface))
153     {
154         import std.datetime.timezone : TimeZone;
155         import std.traits : TemplateOf;
156         enum isSupportedType = !is(typeof(TemplateOf!T)) && !is(Unqual!T == TimeZone);
157     }
158     else static if (isFunctionType!T)
159     {
160         enum isSupportedType = isSupportedType!(ReturnType!T) && isSupportedTypes!(Parameters!T);
161     }
162     else
163         enum isSupportedType = false;
164 }
165 
166 package template isSupportedTypes(T...)
167 {
168     static if (T.length == 0)
169         enum isSupportedTypes = true;
170     else
171         enum isSupportedTypes = isSupportedType!(T[0]) && isSupportedTypes!(T[1..$]);
172 }
173 
174 // Unfortunately, while these tests have been tested on their own, they don't
175 // currently run as part of autowrap's tests, because dub test doesn't work for
176 // the csharp folder, and the top level one does not run them.
177 unittest
178 {
179     import std.meta : AliasSeq;
180     import std.typecons : Tuple;
181 
182     static struct S {}
183     static class C {}
184 
185     foreach(T; AliasSeq!(byte, ubyte, const ubyte, immutable ubyte, short, ushort, int, uint, long, ulong,
186                          float, double, bool, char, wchar, dchar, string, wstring, dstring, S, S[], C, int[],
187                          string[], wstring[], dstring[], void))
188     {
189         static assert(isSupportedType!T, T.stringof);
190     }
191     foreach(T; AliasSeq!(int*, int*[], int[][], int[][][], int[int], cfloat, cdouble, creal, ifloat, idouble, ireal,
192                          Tuple!int, Tuple!(string, string)))
193     {
194         static assert(!isSupportedType!T, T.stringof);
195     }
196 }