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 isSupportedType(T)
126 {
127     import std.range.primitives : ElementType;
128     import std.traits : isBoolean, isDynamicArray, isIntegral, isSomeChar, Unqual;
129 
130     static if(isIntegral!T || isBoolean!T || isSomeChar!T ||
131               is(Unqual!T == float) || is(Unqual!T == double) || is(T == void))
132     {
133         enum isSupportedType = true;
134     }
135     else static if(isDynamicArray!T)
136     {
137         alias E = ElementType!T;
138         enum isSupportedType = is(E == string) || is(E == wstring) || is(E == dstring) ||
139                                !isDynamicArray!E && isSupportedType!E;
140     }
141     else static if(is(T == struct) || is(T == class) || is(T == interface))
142     {
143         import std.datetime.timezone : TimeZone;
144         import std.traits : TemplateOf;
145         enum isSupportedType = !is(typeof(TemplateOf!T)) && !is(Unqual!T == TimeZone);
146     }
147     else
148         enum isSupportedType = false;
149 }
150 
151 // Unfortunately, while these tests have been tested on their own, they don't
152 // currently run as part of autowrap's tests, because dub test doesn't work for
153 // the csharp folder, and the top level one does not run them.
154 unittest
155 {
156     import std.meta : AliasSeq;
157     import std.typecons : Tuple;
158 
159     static struct S {}
160     static class C {}
161 
162     foreach(T; AliasSeq!(byte, ubyte, const ubyte, immutable ubyte, short, ushort, int, uint, long, ulong,
163                          float, double, bool, char, wchar, dchar, string, wstring, dstring, S, S[], C, int[],
164                          string[], wstring[], dstring[], void))
165     {
166         static assert(isSupportedType!T, T.stringof);
167     }
168     foreach(T; AliasSeq!(int*, int*[], int[][], int[][][], int[int], cfloat, cdouble, creal, ifloat, idouble, ireal,
169                          Tuple!int, Tuple!(string, string)))
170     {
171         static assert(!isSupportedType!T, T.stringof);
172     }
173 }