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 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", "autowrap.csharp.dlang.Marshalled_Duration"))
58         fqn = "Autowrap_Csharp_Boilerplate_Marshalled_Duration";
59     else if (fqn.among("std.datetime.date.DateTime", "std.datetime.date.Date", "std.datetime.date.TimeOfDay",
60                   "autowrap.csharp.dlang.Marshalled_std_datetime_date")) {
61         fqn = "Autowrap_Csharp_Boilerplate_Marshalled_std_datetime_date";
62     }
63     else if (fqn == "std.datetime.systime.SysTime")
64         fqn = "Autowrap_Csharp_Boilerplate_Marshalled_std_datetime_systime";
65 
66     name ~= fqn.split(".").map!camelToPascalCase.join("_");
67     name ~= camelToPascalCase(funcName);
68     return name;
69 }
70 
71 public string camelToPascalCase(string camel) {
72     import std.uni : toUpper;
73     import std.conv : to;
74     import std.range : dropOne;
75     return to!string(camel.front.toUpper()) ~ camel.dropOne();
76 }
77 
78 package template verifySupported(T)
79 {
80     static if(isSupportedType!T)
81         enum verifySupported = true;
82     else
83     {
84         pragma(msg, T.stringof ~ " is not currently supported by autowrap's C#");
85         enum verifySupported = false;
86     }
87 }
88 
89 package template numDefaultArgs(alias func)
90 {
91     import std.meta : Filter;
92     import std.traits : ParameterDefaults;
93 
94     enum numDefaultArgs = Filter!(isNotVoid, ParameterDefaults!func).length;
95 
96     private static template isNotVoid(values...)
97         if(values.length == 1)
98     {
99         enum isNotVoid = !is(values[0] == void);
100     }
101 }
102 
103 // Unfortunately, while these tests have been tested on their own, they don't
104 // currently run as part of autowrap's tests, because dub test doesn't work for
105 // the csharp folder, and the top level one does not run them.
106 unittest
107 {
108     import std.meta : AliasSeq;
109 
110     static void foo1() {}
111     static void foo2(int) {}
112     static void foo3(int, string) {}
113     static void foo4(int, string, int) {}
114 
115     foreach(f; AliasSeq!(foo1, foo2, foo3, foo4))
116         static assert(numDefaultArgs!f == 0);
117 
118     static void foo5(int i = 42) {}
119     static void foo6(int, string s = "hello") {}
120     static void foo7(int, string, int j = 97) {}
121 
122     foreach(f; AliasSeq!(foo5, foo6, foo7))
123         static assert(numDefaultArgs!f == 1);
124 
125     static void foo9(int i = 42, string s = "hello") {}
126     static void foo10(int, string s = "hello", int j = 97) {}
127 
128     foreach(f; AliasSeq!(foo9, foo10))
129         static assert(numDefaultArgs!f == 2);
130 
131     static void foo11(int i = 42, string s = "hello", int j = 97) {}
132 
133     static assert(numDefaultArgs!foo11 == 3);
134 }
135 
136 package template isSupportedType(T)
137 {
138     import std.range.primitives : ElementType;
139     import std.traits : isBoolean, isDynamicArray, isIntegral, isSomeChar, Unqual;
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
159         enum isSupportedType = false;
160 }
161 
162 // Unfortunately, while these tests have been tested on their own, they don't
163 // currently run as part of autowrap's tests, because dub test doesn't work for
164 // the csharp folder, and the top level one does not run them.
165 unittest
166 {
167     import std.meta : AliasSeq;
168     import std.typecons : Tuple;
169 
170     static struct S {}
171     static class C {}
172 
173     foreach(T; AliasSeq!(byte, ubyte, const ubyte, immutable ubyte, short, ushort, int, uint, long, ulong,
174                          float, double, bool, char, wchar, dchar, string, wstring, dstring, S, S[], C, int[],
175                          string[], wstring[], dstring[], void))
176     {
177         static assert(isSupportedType!T, T.stringof);
178     }
179     foreach(T; AliasSeq!(int*, int*[], int[][], int[][][], int[int], cfloat, cdouble, creal, ifloat, idouble, ireal,
180                          Tuple!int, Tuple!(string, string)))
181     {
182         static assert(!isSupportedType!T, T.stringof);
183     }
184 }