1 /** 2 Necessary boilerplate for C#/.NET. 3 4 To wrap all functions/return/parameter types and struct/class definitions from 5 a list of modules, write this in a "main" module and generate mylib.{so,dll}: 6 7 ------ 8 mixin wrapCSharp("mylib", Modules("module1", "module2", ...)); 9 ------ 10 */ 11 module autowrap.csharp.boilerplate; 12 13 import autowrap.common; 14 import autowrap.reflection; 15 import autowrap.csharp; 16 17 import core.time; 18 import core.memory; 19 import std.conv; 20 import std.datetime : DateTime, SysTime, Date, TimeOfDay, SimpleTimeZone, LocalTime; 21 import std.meta : Unqual; 22 import std.string; 23 import std.traits; 24 import std.utf; 25 26 extern(C) export struct returnValue(T) { 27 T value; 28 wstring error; 29 30 this(T value) nothrow { 31 this.value = value; 32 static if (isArray!(T) || is(T == class) || is(T == interface)) { 33 if (this.value !is null) { 34 pinPointer(cast(void*)this.error.ptr); 35 } 36 } 37 this.error = null; 38 } 39 40 this(Exception error) nothrow { 41 this.value = T.init; 42 try { 43 this.error = to!wstring(error.toString()); 44 } catch(Exception ex) { 45 this.error = "Unhandled Exception while marshalling exception data. You should never see this error."; 46 } 47 pinPointer(cast(void*)this.error.ptr); 48 } 49 } 50 51 extern(C) export struct returnVoid { 52 wstring error = null; 53 54 this(Exception error) nothrow { 55 try { 56 this.error = to!wstring(error.toString()); 57 } catch(Exception ex) { 58 this.error = "Unhandled Exception while marshalling exception data. You should never see this error."; 59 } 60 pinPointer(cast(void*)this.error.ptr); 61 } 62 } 63 64 extern(C) export struct datetime { 65 long ticks; 66 long offset; 67 68 public this(Duration value) { 69 this.ticks = value.total!"hnsecs"; 70 this.offset = 0; 71 } 72 73 public this(DateTime value) { 74 this.ticks = SysTime(value).stdTime; 75 this.offset = 0; 76 } 77 78 public this(Date value) { 79 this.ticks = SysTime(value).stdTime; 80 this.offset = 0; 81 } 82 83 public this(TimeOfDay value) { 84 import core.time : Duration, hours, minutes, seconds; 85 Duration t = hours(value.hour) + minutes(value.minute) + seconds(value.second); 86 this.ticks = t.total!"hnsecs"; 87 this.offset = 0; 88 } 89 90 public this(SysTime value) { 91 this.ticks = value.stdTime; 92 this.offset = value.utcOffset.total!"hnsecs"; 93 } 94 } 95 96 public void pinPointer(void* ptr) nothrow { 97 GC.setAttr(ptr, GC.BlkAttr.NO_MOVE); 98 GC.addRoot(ptr); 99 } 100 101 public datetime toDatetime(T)(T value) 102 if (isDateTimeType!T) { 103 return datetime(value); 104 } 105 106 public datetime[] toDatetime1DArray(T)(T[] value) 107 if (isDateTimeType!T) { 108 import std.algorithm : map; 109 import std.array : array; 110 return value.map!datetime.array; 111 } 112 113 public T fromDatetime(T)(datetime value) if (is(Unqual!T == SysTime)) { 114 return SysTime(value.ticks, cast(immutable)new SimpleTimeZone(hnsecs(value.offset))); 115 } 116 117 public T fromDatetime(T)(datetime value) if (is(Unqual!T == DateTime)) { 118 return cast(T)SysTime(value.ticks, LocalTime()); 119 } 120 121 public T fromDatetime(T)(datetime value) if (is(Unqual!T == Date) || is(Unqual!T == TimeOfDay)) { 122 return cast(T)SysTime(value.ticks, cast(immutable)new SimpleTimeZone(hnsecs(0))); 123 } 124 125 public T fromDatetime(T)(datetime value) if (is(Unqual!T == Duration)) { 126 return hnsecs(value.ticks); 127 } 128 129 public T[] fromDatetime1DArray(T)(datetime[] value) 130 if (isDateTimeType!T) { 131 import std.algorithm : map; 132 import std.array : array; 133 return value.map!(fromDatetime!T).array; 134 } 135 136 public string wrapCSharp(in Modules modules, OutputFileName outputFile, LibraryName libraryName, RootNamespace rootNamespace) @safe pure { 137 import std.format : format; 138 import std.algorithm: map; 139 import std.array: join; 140 import autowrap.common; 141 import autowrap.csharp.boilerplate; 142 143 if(!__ctfe) return null; 144 145 const modulesList = modules.value.map!(a => a.toString).join(", "); 146 147 return q{ 148 import core.memory : GC; 149 import std.conv : to; 150 import std.utf : toUTF8, toUTF16, toUTF32; 151 import std.typecons; 152 import std.string : fromStringz; 153 import autowrap.csharp.boilerplate; 154 import autowrap.csharp.dlang : wrapDLang; 155 156 extern(C) export void autowrap_csharp_release(void* ptr) nothrow { 157 GC.clrAttr(ptr, GC.BlkAttr.NO_MOVE); 158 GC.removeRoot(ptr); 159 } 160 161 extern(C) export string autowrap_csharp_createString(wchar* str) nothrow { 162 string temp = toUTF8(to!wstring(str.fromStringz())); 163 pinPointer(cast(void*)temp.ptr); 164 return temp; 165 } 166 167 extern(C) export wstring autowrap_csharp_createWString(wchar* str) nothrow { 168 wstring temp = toUTF16(to!wstring(str.fromStringz())); 169 pinPointer(cast(void*)temp.ptr); 170 return temp; 171 } 172 173 extern(C) export dstring autowrap_csharp_createDString(wchar* str) nothrow { 174 dstring temp = toUTF32(to!wstring(str.fromStringz())); 175 pinPointer(cast(void*)temp.ptr); 176 return temp; 177 } 178 179 mixin(wrapDLang!(%1$s)); 180 181 //Insert DllMain for Windows only. 182 version(Windows) { 183 %2$s 184 } 185 186 void main() { 187 import std.stdio; 188 string generated = generateCSharp!(%1$s)(LibraryName("%3$s"), RootNamespace("%4$s")); 189 auto f = File("%5$s", "w"); 190 f.writeln(generated); 191 } 192 }.format(modulesList, dllMainMixinStr(), libraryName.value, rootNamespace.value, outputFile.value); 193 }