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