1 module autowrap.csharp.csharp; 2 3 import scriptlike : interp, _interp_text; 4 5 import autowrap.csharp.common : LibraryName, RootNamespace, getDLangInterfaceType, OutputFileName; 6 import autowrap.reflection : isModule, Modules; 7 8 import std.ascii : newline; 9 import std.meta: allSatisfy; 10 import std.string : format; 11 12 private string[string] returnTypes; 13 private CSharpNamespace[string] namespaces; 14 private csharpRange rangeDef; 15 16 enum string voidTypeString = "void"; 17 enum string stringTypeString = "string"; 18 enum string wstringTypeString = "wstring"; 19 enum string dstringTypeString = "dstring"; 20 enum string boolTypeString = "bool"; 21 enum string dateTimeTypeString = "std.datetime.date.DateTime"; 22 enum string sysTimeTypeString = "std.datetime.systime.SysTime"; 23 enum string dateTypeString = "std.datetime.date.Date"; 24 enum string timeOfDayTypeString = "std.datetime.date.TimeOfDay"; 25 enum string durationTypeString = "core.time.Duration"; 26 enum string uuidTypeString = "UUID"; 27 enum string charTypeString = "char"; 28 enum string wcharTypeString = "wchar"; 29 enum string dcharTypeString = "dchar"; 30 enum string ubyteTypeString = "ubyte"; 31 enum string byteTypeString = "byte"; 32 enum string ushortTypeString = "ushort"; 33 enum string shortTypeString = "short"; 34 enum string uintTypeString = "uint"; 35 enum string intTypeString = "int"; 36 enum string ulongTypeString = "ulong"; 37 enum string longTypeString = "long"; 38 enum string floatTypeString = "float"; 39 enum string doubleTypeString = "double"; 40 enum string sliceTypeString = "slice"; 41 42 enum string dllImportString = " [DllImport(\"%1$s\", EntryPoint = \"%2$s\", CallingConvention = CallingConvention.Cdecl)]" ~ newline; 43 enum string externFuncString = " internal static extern %1$s %2$s(%3$s);" ~ newline; 44 45 enum int fileReservationSize = 33_554_432; 46 enum int aggregateReservationSize = 32_768; 47 48 //Class used for language built-in reference semantics. 49 private final class CSharpNamespace { 50 public string namespace; 51 public string functions; 52 public CSharpAggregate[string] aggregates; 53 54 public this(string ns) { 55 namespace = ns; 56 functions = string.init; 57 } 58 59 public override string toString() { 60 string ret; 61 foreach(csns; namespaces.byValue()) { 62 ret ~= "namespace " ~ csns.namespace ~ " { 63 using System; 64 using System.CodeDom.Compiler; 65 using System.Collections.Generic; 66 using System.Linq; 67 using System.Reflection; 68 using System.Runtime.InteropServices; 69 using Autowrap; 70 71 public static class Functions { 72 " ~ csns.functions ~ " 73 }" ~ newline ~ newline; 74 foreach(agg; aggregates.byValue()) { 75 ret ~= agg.toString(); 76 } 77 ret ~= "}" ~ newline; 78 } 79 return cast(immutable)ret; 80 } 81 } 82 83 //Class used for language built-in reference semantics. 84 private final class CSharpAggregate { 85 public string name; 86 public bool isStruct; 87 public string constructors; 88 public string functions; 89 public string methods; 90 public string properties; 91 92 public this (string name, bool isStruct) { 93 this.name = name; 94 this.isStruct = isStruct; 95 this.constructors = string.init; 96 this.functions = string.init; 97 this.methods = string.init; 98 this.properties = string.init; 99 } 100 101 public override string toString() { 102 import autowrap.csharp.common : camelToPascalCase; 103 104 char[] ret; 105 ret.reserve(aggregateReservationSize); 106 ret ~= " [GeneratedCodeAttribute(\"Autowrap\", \"1.0.0.0\")]" ~ newline; 107 if (isStruct) { 108 ret ~= " [StructLayout(LayoutKind.Sequential)]" ~ newline; 109 ret ~= mixin(interp!" public struct ${camelToPascalCase(this.name)} {${newline}"); 110 } else { 111 ret ~= mixin(interp!" public class ${camelToPascalCase(this.name)} : DLangObject {${newline}"); 112 ret ~= mixin(interp!" public static implicit operator IntPtr(${camelToPascalCase(this.name)} ret) { return ret.DLangPointer; }${newline}"); 113 ret ~= mixin(interp!" public static implicit operator ${camelToPascalCase(this.name)}(IntPtr ret) { return new ${camelToPascalCase(this.name)}(ret); }${newline}"); 114 } 115 if (functions != string.init) ret ~= functions ~ newline; 116 if (constructors != string.init) ret ~= constructors ~ newline; 117 if (methods != string.init) ret ~= methods ~ newline; 118 if (properties != string.init) ret ~= properties; 119 ret ~= " }" ~ newline ~ newline; 120 return cast(immutable)ret; 121 } 122 } 123 124 public struct csharpRange { 125 public string constructors = string.init; 126 public string enumerators = string.init; 127 public string functions = string.init; 128 public string getters = string.init; 129 public string setters = string.init; 130 public string appendValues = string.init; 131 public string appendArrays = string.init; 132 public string sliceEnd = string.init; 133 public string sliceRange = string.init; 134 135 public string toString() { 136 immutable string boilerplate = import("Ranges.cs"); 137 return boilerplate.format(functions, constructors, getters, setters, sliceEnd, sliceRange, appendValues, appendArrays, enumerators); 138 } 139 } 140 141 public string generateCSharp(Modules...)(LibraryName libraryName, RootNamespace rootNamespace) if(allSatisfy!(isModule, Modules)) { 142 import core.time : Duration; 143 import autowrap.csharp.common : isDateTimeType; 144 import autowrap.reflection : AllAggregates; 145 146 generateSliceBoilerplate(libraryName.value); 147 148 alias aggregates = AllAggregates!Modules; 149 static foreach(agg; aggregates) { 150 static if (!(isDateTimeType!agg)) { 151 generateRangeDef!agg(libraryName.value); 152 generateConstructors!agg(libraryName.value); 153 generateMethods!agg(libraryName.value); 154 generateProperties!agg(libraryName.value); 155 generateFields!agg(libraryName.value); 156 } 157 } 158 159 generateFunctions!Modules(libraryName.value); 160 161 char[] ret; 162 ret.reserve(fileReservationSize); 163 foreach(csns; namespaces.byValue()) { 164 ret ~= csns.toString(); 165 } 166 167 ret ~= newline ~ writeCSharpBoilerplate(libraryName.value, rootNamespace.value); 168 169 return cast(immutable)ret; 170 } 171 172 private void generateConstructors(T)(string libraryName) if (is(T == class) || is(T == struct)) { 173 import autowrap.csharp.common : getDLangInterfaceName; 174 import std.traits : moduleName, fullyQualifiedName, hasMember, Parameters, ParameterIdentifierTuple; 175 import std.meta: AliasSeq; 176 import std.algorithm : among; 177 178 alias fqn = fullyQualifiedName!T; 179 const string aggName = __traits(identifier, T); 180 CSharpAggregate csagg = getAggregate(getCSharpName(moduleName!T), getCSharpName(aggName), !is(T == class)); 181 182 static if(hasMember!(T, "__ctor") && __traits(getProtection, __traits(getMember, T, "__ctor")).among("export", "public")) { 183 alias constructors = AliasSeq!(__traits(getOverloads, T, "__ctor")); 184 } else { 185 alias constructors = AliasSeq!(); 186 } 187 188 //Generate constructor methods 189 foreach(c; constructors) { 190 alias paramNames = ParameterIdentifierTuple!c; 191 alias paramTypes = Parameters!c; 192 const string interfaceName = getDLangInterfaceName(fqn, "__ctor"); 193 const string methodName = getCSharpMethodInterfaceName(aggName, "__ctor"); 194 string ctor = dllImportString.format(libraryName, interfaceName); 195 ctor ~= mixin(interp!" private static extern ${getDLangReturnType(aggName, is(T == class))} dlang_${methodName}("); 196 static foreach(pc; 0..paramNames.length) { 197 if (is(paramTypes[pc] == class)) { 198 ctor ~= mixin(interp!"IntPtr ${paramNames[pc]}, "); 199 } else { 200 ctor ~= mixin(interp!"${is(paramTypes[pc] == bool) ? \"[MarshalAs(UnmanagedType.Bool)]\" : string.init}${getDLangInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 201 } 202 } 203 if (paramNames.length > 0) { 204 ctor = ctor[0..$-2]; 205 } 206 ctor ~= ");" ~ newline; 207 ctor ~= mixin(interp!" public ${getCSharpName(aggName)}("); 208 static foreach(pc; 0..paramNames.length) { 209 ctor ~= mixin(interp!"${getCSharpInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 210 } 211 if (paramNames.length > 0) { 212 ctor = ctor[0..$-2]; 213 } 214 if (is(T == class)) { 215 ctor ~= mixin(interp!") : base(dlang_${methodName}("); 216 static foreach(pc; 0..paramNames.length) { 217 static if (is(paramTypes[pc] == string)) { 218 ctor ~= mixin(interp!"SharedFunctions.CreateString(${paramNames[pc]}), "); 219 } else static if (is(paramTypes[pc] == wstring)) { 220 ctor ~= mixin(interp!"SharedFunctions.CreateWString(${paramNames[pc]}), "); 221 } else static if (is(paramTypes[pc] == dstring)) { 222 ctor ~= mixin(interp!"SharedFunctions.CreateDString(${paramNames[pc]}), "); 223 } else { 224 ctor ~= mixin(interp!"${paramNames[pc]}, "); 225 } 226 } 227 if (paramNames.length > 0) { 228 ctor = ctor[0..$-2]; 229 } 230 ctor ~= ")"; 231 } 232 ctor ~= ") { }" ~ newline; 233 csagg.constructors ~= ctor; 234 } 235 if (is(T == class)) { 236 csagg.constructors ~= mixin(interp!" internal ${getCSharpName(aggName)}(IntPtr ptr) : base(ptr) { }${newline}"); 237 } 238 } 239 240 private void generateMethods(T)(string libraryName) if (is(T == class) || is(T == interface) || is(T == struct)) { 241 import autowrap.csharp.common : camelToPascalCase, getDLangInterfaceName; 242 import std.traits : moduleName, isArray, fullyQualifiedName, isFunction, functionAttributes, FunctionAttribute, ReturnType, Parameters, ParameterIdentifierTuple; 243 import std.conv : to; 244 245 alias fqn = fullyQualifiedName!T; 246 const string aggName = __traits(identifier, T); 247 CSharpAggregate csagg = getAggregate(getCSharpName(moduleName!T), getCSharpName(aggName), !is(T == class)); 248 249 foreach(m; __traits(allMembers, T)) { 250 if (m == "__ctor" || m == "toHash" || m == "opEquals" || m == "opCmp" || m == "factory") { 251 continue; 252 } 253 const string methodName = camelToPascalCase(cast(string)m); 254 const string methodInterfaceName = getCSharpMethodInterfaceName(aggName, cast(string)m); 255 256 static if (is(typeof(__traits(getMember, T, m)))) { 257 foreach(oc, mo; __traits(getOverloads, T, m)) { 258 static if(isFunction!mo) { 259 string exp = string.init; 260 enum bool isProperty = cast(bool)(functionAttributes!mo & FunctionAttribute.property); 261 alias returnType = ReturnType!mo; 262 alias returnTypeStr = fullyQualifiedName!returnType; 263 alias paramTypes = Parameters!mo; 264 alias paramNames = ParameterIdentifierTuple!mo; 265 const string interfaceName = getDLangInterfaceName(fqn, m) ~ to!string(oc); 266 267 exp ~= dllImportString.format(libraryName, interfaceName); 268 exp ~= " private static extern "; 269 if (!is(returnType == void)) { 270 exp ~= getDLangReturnType(returnTypeStr, is(returnType == class)); 271 } else { 272 exp ~= "return_void_error"; 273 } 274 exp ~= mixin(interp!" dlang_${methodInterfaceName}("); 275 if (is(T == struct)) { 276 exp ~= mixin(interp!"ref ${getDLangInterfaceType(fqn)} __obj__, "); 277 } else if (is(T == class) || is(T == interface)) { 278 exp ~= "IntPtr __obj__, "; 279 } 280 static foreach(pc; 0..paramNames.length) { 281 if (is(paramTypes[pc] == class)) { 282 exp ~= mixin(interp!"IntPtr ${paramNames[pc]}, "); 283 } else { 284 exp ~= mixin(interp!"${getDLangInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 285 } 286 } 287 exp = exp[0..$-2]; 288 exp ~= ");" ~ newline; 289 if (!isProperty) { 290 exp ~= mixin(interp!" public ${methodName == \"ToString\" ? \"override \" : string.init}${getCSharpInterfaceType(returnTypeStr)} ${methodName}("); 291 static foreach(pc; 0..paramNames.length) { 292 if (is(paramTypes[pc] == string) || is(paramTypes[pc] == wstring) || is(paramTypes[pc] == dstring)) { 293 exp ~= mixin(interp!"${getCSharpInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 294 } else if (isArray!(paramTypes[pc])) { 295 exp ~= mixin(interp!"Range<${getCSharpInterfaceType(fullyQualifiedName!(paramTypes[pc]))}> ${paramNames[pc]}, "); 296 } else { 297 exp ~= mixin(interp!"${getCSharpInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 298 } 299 } 300 if (paramNames.length > 0) { 301 exp = exp[0..$-2]; 302 } 303 exp ~= ") {" ~ newline; 304 exp ~= mixin(interp!" var dlang_ret = dlang_${methodInterfaceName}(${is(T == struct) ? \"ref \" : string.init}this, "); 305 static foreach(pc; 0..paramNames.length) { 306 static if (is(paramTypes[pc] == string)) { 307 exp ~= mixin(interp!"SharedFunctions.CreateString(${paramNames[pc]}), "); 308 } else static if (is(paramTypes[pc] == wstring)) { 309 exp ~= mixin(interp!"SharedFunctions.CreateWstring(${paramNames[pc]}), "); 310 } else static if (is(paramTypes[pc] == dstring)) { 311 exp ~= mixin(interp!"SharedFunctions.CreateDstring(${paramNames[pc]}), "); 312 } else { 313 exp ~= paramNames[pc] ~ ", "; 314 } 315 } 316 exp = exp[0..$-2]; 317 exp ~= ");" ~ newline; 318 if (!is(returnType == void)) { 319 if (is(returnType == string)) { 320 exp ~= " return SharedFunctions.SliceToString(dlang_ret, DStringType._string);" ~ newline; 321 } else if (is(returnType == wstring)) { 322 exp ~= " return SharedFunctions.SliceToString(dlang_ret, DStringType._wstring);" ~ newline; 323 } else if (is(returnType == dstring)) { 324 exp ~= " return SharedFunctions.SliceToString(dlang_ret, DStringType._dstring);" ~ newline; 325 } else { 326 exp ~= " return dlang_ret;" ~ newline; 327 } 328 } 329 exp ~= " }" ~ newline; 330 } 331 csagg.methods ~= exp; 332 } 333 } 334 } 335 } 336 } 337 338 private void generateProperties(T)(string libraryName) if (is(T == class) || is(T == interface) || is(T == struct)) { 339 import autowrap.csharp.common : camelToPascalCase; 340 import std.traits : moduleName, isArray, fullyQualifiedName, functionAttributes, FunctionAttribute, ReturnType, Parameters; 341 342 alias fqn = fullyQualifiedName!T; 343 const string aggName = __traits(identifier, T); 344 CSharpAggregate csagg = getAggregate(getCSharpName(moduleName!T), getCSharpName(aggName), !is(T == class)); 345 346 foreach(m; __traits(allMembers, T)) { 347 if (m == "__ctor" || m == "toHash" || m == "opEquals" || m == "opCmp" || m == "factory") { 348 continue; 349 } 350 const string methodName = camelToPascalCase(cast(string)m); 351 const string methodInterfaceName = getCSharpMethodInterfaceName(aggName, cast(string)m); 352 353 static if (is(typeof(__traits(getMember, T, m)))) { 354 const olc = __traits(getOverloads, T, m).length; 355 static if(olc > 0 && olc <= 2) { 356 bool isProperty = false; 357 bool propertyGet = false; 358 bool propertySet = false; 359 foreach(mo; __traits(getOverloads, T, m)) { 360 static if (cast(bool)(functionAttributes!mo & FunctionAttribute.property)) { 361 isProperty = true; 362 alias returnType = ReturnType!mo; 363 alias paramTypes = Parameters!mo; 364 if (paramTypes.length == 0) { 365 propertyGet = true; 366 } else { 367 propertySet = true; 368 } 369 } 370 } 371 372 if (isProperty) { 373 string prop = string.init; 374 alias propertyType = ReturnType!(__traits(getOverloads, T, m)[0]); 375 if (is(propertyType == string) || is(propertyType == wstring) || is(propertyType == dstring)) { 376 prop = mixin(interp!" public string ${methodName} { "); 377 } else if (isArray!(propertyType)) { 378 prop = mixin(interp!" public Range<${getCSharpInterfaceType(fullyQualifiedName!propertyType)}> ${methodName} { "); 379 } else { 380 prop = mixin(interp!" public ${getCSharpInterfaceType(fullyQualifiedName!propertyType)} ${methodName} { "); 381 } 382 if (propertyGet) { 383 if (is(propertyType == string)) { 384 prop ~= mixin(interp!"get => SharedFunctions.SliceToString(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this), DStringType._string);"); 385 } else if (is(propertyType == wstring)) { 386 prop ~= mixin(interp!"get => SharedFunctions.SliceToString(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this), DStringType._wstring);"); 387 } else if (is(propertyType == dstring)) { 388 prop ~= mixin(interp!"get => SharedFunctions.SliceToString(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this), DStringType._dstring);"); 389 } else if (is(propertyType == string[])) { 390 prop ~= mixin(interp!"get => new Range<string>(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this), DStringType._string); "); 391 } else if (is(propertyType == wstring[])) { 392 prop ~= mixin(interp!"get => new Range<string>(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this), DStringType._wstring); "); 393 } else if (is(propertyType == dstring[])) { 394 prop ~= mixin(interp!"get => new Range<string>(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this), DStringType._dstring); "); 395 } else if (isArray!(propertyType)) { 396 prop ~= mixin(interp!"get => new Range<${getCSharpInterfaceType(fullyQualifiedName!propertyType)}>(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this), DStringType.None); "); 397 } else if (is(propertyType == class)) { 398 prop ~= mixin(interp!"get => new ${getCSharpInterfaceType(fullyQualifiedName!propertyType)}(dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this)); "); 399 } else { 400 prop ~= mixin(interp!"get => dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this); "); 401 } 402 } 403 if (propertySet) { 404 if (is(propertyType == string)) { 405 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(this, SharedFunctions.CreateString(value));"); 406 } else if (is(propertyType == wstring)) { 407 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(this, SharedFunctions.CreateWstring(value));"); 408 } else if (is(propertyType == dstring)) { 409 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(this, SharedFunctions.CreateDstring(value));"); 410 } else if (is(propertyType == string[])) { 411 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this, value.ToSlice(DStringType._string)); "); 412 } else if (is(propertyType == wstring[])) { 413 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this, value.ToSlice(DStringType._wstring)); "); 414 } else if (is(propertyType == dstring[])) { 415 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this, value.ToSlice(DStringType._dstring)); "); 416 } else if (isArray!(propertyType)) { 417 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this, value.ToSlice()); "); 418 } else { 419 prop ~= mixin(interp!"set => dlang_${methodInterfaceName}(${is(T == class) ? string.init : \"ref \"}this, value); "); 420 } 421 } 422 prop ~= "}" ~ newline; 423 csagg.properties ~= prop; 424 } 425 } 426 } 427 } 428 } 429 430 private void generateFields(T)(string libraryName) if (is(T == class) || is(T == interface) || is(T == struct)) { 431 import autowrap.csharp.common : getDLangInterfaceName; 432 import std.traits : moduleName, isArray, fullyQualifiedName, Fields, FieldNameTuple; 433 434 alias fqn = fullyQualifiedName!T; 435 const string aggName = __traits(identifier, T); 436 CSharpAggregate csagg = getAggregate(getCSharpName(moduleName!T), getCSharpName(aggName), !is(T == class)); 437 438 alias fieldTypes = Fields!T; 439 alias fieldNames = FieldNameTuple!T; 440 441 if (is(T == class) || is(T == interface)) { 442 static foreach(fc; 0..fieldTypes.length) { 443 static if (is(typeof(__traits(getMember, T, fieldNames[fc])))) { 444 csagg.properties ~= dllImportString.format(libraryName, getDLangInterfaceName(fqn, fieldNames[fc] ~ "_get")); 445 csagg.properties ~= mixin(interp!" private static extern ${getDLangReturnType(fullyQualifiedName!(fieldTypes[fc]), true)} dlang_${fieldNames[fc]}_get(IntPtr ptr);${newline}"); 446 if (is(fieldTypes[fc] == bool)) { 447 csagg.properties ~= dllImportString.format(libraryName, getDLangInterfaceName(fqn, fieldNames[fc] ~ "_set")); 448 csagg.properties ~= mixin(interp!" private static extern void dlang_${fieldNames[fc]}_set(IntPtr ptr, [MarshalAs(UnmanagedType.Bool)] ${getDLangInterfaceType(fullyQualifiedName!(fieldTypes[fc]))} value);${newline}"); 449 } else if (is(fieldTypes[fc] == class)) { 450 csagg.properties ~= dllImportString.format(libraryName, getDLangInterfaceName(fqn, fieldNames[fc] ~ "_set")); 451 csagg.properties ~= mixin(interp!" private static extern void dlang_${fieldNames[fc]}_set(IntPtr ptr, IntPtr value);${newline}"); 452 } else { 453 csagg.properties ~= dllImportString.format(libraryName, getDLangInterfaceName(fqn, fieldNames[fc] ~ "_set")); 454 csagg.properties ~= mixin(interp!" private static extern void dlang_${fieldNames[fc]}_set(IntPtr ptr, ${getDLangInterfaceType(fullyQualifiedName!(fieldTypes[fc]))} value);${newline}"); 455 } 456 457 if (is(fieldTypes[fc] == string)) { 458 csagg.properties ~= mixin(interp!" public string ${getCSharpName(fieldNames[fc])} { get => SharedFunctions.SliceToString(dlang_${fieldNames[fc]}_get(this), DStringType._string); set => dlang_${fieldNames[fc]}_set(this, SharedFunctions.CreateString(value)); }${newline}"); 459 } else if (is(fieldTypes[fc] == wstring)) { 460 csagg.properties ~= mixin(interp!" public string ${getCSharpName(fieldNames[fc])} { get => SharedFunctions.SliceToString(dlang_${fieldNames[fc]}_get(this), DStringType._wstring); set => dlang_${fieldNames[fc]}_set(this, SharedFunctions.CreateWstring(value)); }${newline}"); 461 } else if (is(fieldTypes[fc] == dstring)) { 462 csagg.properties ~= mixin(interp!" public string ${getCSharpName(fieldNames[fc])} { get => SharedFunctions.SliceToString(dlang_${fieldNames[fc]}_get(this), DStringType._dstring); set => dlang_${fieldNames[fc]}_set(this, SharedFunctions.CreateDstring(value)); }${newline}"); 463 } else if (is(fieldTypes[fc] == string[])) { 464 csagg.properties ~= mixin(interp!" public Range<string> ${getCSharpName(fieldNames[fc])} { get => new Range<string>(dlang_${fieldNames[fc]}_get(this), DStringType._string); set => dlang_${fieldNames[fc]}_set(this, value.ToSlice(DStringType._string)); }${newline}"); 465 } else if (is(fieldTypes[fc] == wstring[])) { 466 csagg.properties ~= mixin(interp!" public Range<string> ${getCSharpName(fieldNames[fc])} { get => new Range<string>(dlang_${fieldNames[fc]}_get(this), DStringType._wstring); set => dlang_${fieldNames[fc]}_set(this, value.ToSlice(DStringType._wstring)); }${newline}"); 467 } else if (is(fieldTypes[fc] == dstring[])) { 468 csagg.properties ~= mixin(interp!" public Range<string> ${getCSharpName(fieldNames[fc])} { get => new Range<string>(dlang_${fieldNames[fc]}_get(this), DStringType._dstring); set => dlang_${fieldNames[fc]}_set(this, value.ToSlice(DStringType._dstring)); }${newline}"); 469 } else if (isArray!(fieldTypes[fc])) { 470 csagg.properties ~= mixin(interp!" public Range<${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))}> ${getCSharpName(fieldNames[fc])} { get => new Range<${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))}>(dlang_${fieldNames[fc]}_get(this), DStringType.None); set => dlang_${fieldNames[fc]}_set(this, value.ToSlice()); }${newline}"); 471 } else if (is(fieldTypes[fc] == class)) { 472 csagg.properties ~= mixin(interp!" public ${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))} ${getCSharpName(fieldNames[fc])} { get => new ${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))}(dlang_${fieldNames[fc]}_get(this)); set => dlang_${fieldNames[fc]}_set(this, value); }${newline}"); 473 } else { 474 csagg.properties ~= mixin(interp!" public ${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))} ${getCSharpName(fieldNames[fc])} { get => dlang_${fieldNames[fc]}_get(this); set => dlang_${fieldNames[fc]}_set(this, value); }${newline}"); 475 } 476 } 477 } 478 } else if(is(T == struct)) { 479 static foreach(fc; 0..fieldTypes.length) { 480 static if (is(typeof(__traits(getMember, T, fieldNames[fc])))) { 481 if (isArray!(fieldTypes[fc])) { 482 csagg.properties ~= mixin(interp!" private slice _${getCSharpName(fieldNames[fc])};${newline}"); 483 if (is(fieldTypes[fc] == string)) { 484 csagg.properties ~= mixin(interp!" public string ${getCSharpName(fieldNames[fc])} { get => SharedFunctions.SliceToString(_${getCSharpName(fieldNames[fc])}, DStringType._string); set => _${getCSharpName(fieldNames[fc])} = SharedFunctions.CreateString(value); }${newline}"); 485 } else if (is(fieldTypes[fc] == wstring)) { 486 csagg.properties ~= mixin(interp!" public string ${getCSharpName(fieldNames[fc])} { get => SharedFunctions.SliceToString(_${getCSharpName(fieldNames[fc])}, DStringType._wstring); set => _${getCSharpName(fieldNames[fc])} = SharedFunctions.CreateWstring(value); }${newline}"); 487 } else if (is(fieldTypes[fc] == dstring)) { 488 csagg.properties ~= mixin(interp!" public string ${getCSharpName(fieldNames[fc])} { get => SharedFunctions.SliceToString(_${getCSharpName(fieldNames[fc])}, DStringType._dstring); set => _${getCSharpName(fieldNames[fc])} = SharedFunctions.CreateDstring(value); }${newline}"); 489 } else if (is(fieldTypes[fc] == string[])) { 490 csagg.properties ~= mixin(interp!" public Range<string> ${getCSharpName(fieldNames[fc])} { get => new Range<string>(_${fieldNames[fc]}, DStringType._string); set => _${fieldNames[fc]} = value.ToSlice(DStringType._string); }${newline}"); 491 } else if (is(fieldTypes[fc] == wstring[])) { 492 csagg.properties ~= mixin(interp!" public Range<string> ${getCSharpName(fieldNames[fc])} { get => new Range<string>(_${fieldNames[fc]}, DStringType._wstring); set => _${fieldNames[fc]} = value.ToSlice(DStringType._wstring); }${newline}"); 493 } else if (is(fieldTypes[fc] == dstring[])) { 494 csagg.properties ~= mixin(interp!" public Range<string> ${getCSharpName(fieldNames[fc])} { get => new Range<string>(_${fieldNames[fc]}, DStringType._dstring); set => _${fieldNames[fc]} = value.ToSlice(DStringType._dstring); }${newline}"); 495 } else { 496 csagg.properties ~= mixin(interp!" public Range<${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))}> ${getCSharpName(fieldNames[fc])} { get => new Range<${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))}>(_${fieldNames[fc]}, DStringType.None); set => _${fieldNames[fc]} = value.ToSlice(); }${newline}"); 497 } 498 } else if (is(fieldTypes[fc] == bool)) { 499 csagg.properties ~= mixin(interp!" [MarshalAs(UnmanagedType.U1)] public ${getDLangInterfaceType(fullyQualifiedName!(fieldTypes[fc]))} ${getCSharpName(fieldNames[fc])};${newline}"); 500 } else if (is(fieldTypes[fc] == class)) { 501 csagg.properties ~= mixin(interp!" private IntPtr _${getCSharpName(fieldNames[fc])};${newline}"); 502 csagg.properties ~= mixin(interp!" public ${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))} ${getCSharpName(fieldNames[fc])} { get => new ${getCSharpInterfaceType(fullyQualifiedName!(fieldTypes[fc]))}(_${fieldNames[fc]}); set => _${fieldNames[fc]} = value); }${newline}"); 503 } else { 504 csagg.properties ~= mixin(interp!" public ${getDLangInterfaceType(fullyQualifiedName!(fieldTypes[fc]))} ${getCSharpName(fieldNames[fc])};${newline}"); 505 } 506 } 507 } 508 } 509 } 510 511 private void generateFunctions(Modules...)(string libraryName) if(allSatisfy!(isModule, Modules)) { 512 import autowrap.csharp.common : getDLangInterfaceName; 513 import autowrap.reflection: AllFunctions; 514 import std.traits : isArray, fullyQualifiedName, ReturnType, Parameters, ParameterIdentifierTuple; 515 516 foreach(func; AllFunctions!Modules) { 517 alias modName = func.moduleName; 518 alias funcName = func.name; 519 CSharpNamespace ns = getNamespace(getCSharpName(modName)); 520 521 alias returnType = ReturnType!(__traits(getMember, func.module_, func.name)); 522 alias returnTypeStr = fullyQualifiedName!(ReturnType!(__traits(getMember, func.module_, func.name))); 523 alias paramTypes = Parameters!(__traits(getMember, func.module_, func.name)); 524 alias paramNames = ParameterIdentifierTuple!(__traits(getMember, func.module_, func.name)); 525 const string interfaceName = getDLangInterfaceName(modName, null, funcName); 526 const string methodName = getCSharpMethodInterfaceName(null, funcName); 527 string retType = getDLangReturnType(returnTypeStr, is(returnType == class)); 528 string funcStr = dllImportString.format(libraryName, interfaceName) ~ newline; 529 funcStr ~= mixin(interp!" private static extern ${retType} dlang_${methodName}("); 530 static foreach(pc; 0..paramNames.length) { 531 funcStr ~= mixin(interp!"${is(paramTypes[pc] == bool) ? \"[MarshalAs(UnmanagedType.Bool)]\" : string.init}${getDLangInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 532 } 533 if (paramNames.length > 0) { 534 funcStr = funcStr[0..$-2]; 535 } 536 funcStr ~= ");" ~ newline; 537 if (is(returnType == string) || is(returnType == wstring) || is(returnType == dstring)) { 538 funcStr ~= mixin(interp!" public static string ${methodName}("); 539 } else if (isArray!(returnType)) { 540 funcStr ~= mixin(interp!" public static Range<${getCSharpInterfaceType(returnTypeStr)}> ${methodName}("); 541 } else { 542 funcStr ~= mixin(interp!" public static ${getCSharpInterfaceType(returnTypeStr)} ${methodName}("); 543 } 544 static foreach(pc; 0..paramNames.length) { 545 if (is(paramTypes[pc] == string) || is(paramTypes[pc] == wstring) || is(paramTypes[pc] == dstring)) { 546 funcStr ~= mixin(interp!"${getCSharpInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 547 } else if (isArray!(paramTypes[pc])) { 548 funcStr ~= mixin(interp!"Range<${getCSharpInterfaceType(fullyQualifiedName!(paramTypes[pc]))}> ${paramNames[pc]}, "); 549 } else { 550 funcStr ~= mixin(interp!"${getCSharpInterfaceType(fullyQualifiedName!(paramTypes[pc]))} ${paramNames[pc]}, "); 551 } 552 } 553 if (paramNames.length > 0) { 554 funcStr = funcStr[0..$-2]; 555 } 556 funcStr ~= ") {" ~ newline; 557 funcStr ~= mixin(interp!" var dlang_ret = dlang_${methodName}("); 558 static foreach(pc; 0..paramNames.length) { 559 if (is(paramTypes[pc] == string)) { 560 funcStr ~= mixin(interp!"SharedFunctions.CreateString(${paramNames[pc]}), "); 561 } else if (is(paramTypes[pc] == wstring)) { 562 funcStr ~= mixin(interp!"SharedFunctions.CreateWString(${paramNames[pc]}), "); 563 } else if (is(paramTypes[pc] == dstring)) { 564 funcStr ~= mixin(interp!"SharedFunctions.CreateDString(${paramNames[pc]}), "); 565 } else if (isArray!(paramTypes[pc])) { 566 funcStr ~= mixin(interp!"${paramNames[pc]}.ToSlice(), "); 567 } else { 568 funcStr ~= mixin(interp!"${paramNames[pc]}, "); 569 } 570 } 571 if (paramNames.length > 0) { 572 funcStr = funcStr[0..$-2]; 573 } 574 funcStr ~= ");" ~ newline; 575 if (is(returnType == void)) { 576 funcStr ~= " dlang_ret.EnsureValid();" ~ newline; 577 } else { 578 if (is(returnType == string)) { 579 funcStr ~= " return SharedFunctions.SliceToString(dlang_ret, DStringType._string);" ~ newline; 580 } else if (is(returnType == wstring)) { 581 funcStr ~= " return SharedFunctions.SliceToString(dlang_ret, DStringType._wstring);" ~ newline; 582 } else if (is(returnType == dstring)) { 583 funcStr ~= " return SharedFunctions.SliceToString(dlang_ret, DStringType._dstring);" ~ newline; 584 } else if (is(returnType == string[])) { 585 funcStr ~= mixin(interp!" return new Range<string>(dlang_ret, DStringType._string);${newline}"); 586 } else if (is(returnType == wstring[])) { 587 funcStr ~= mixin(interp!" return new Range<string>(dlang_ret, DStringType._wstring);${newline}"); 588 } else if (is(returnType == dstring[])) { 589 funcStr ~= mixin(interp!" return new Range<string>(dlang_ret, DStringType._dstring);${newline}"); 590 } else if (isArray!(returnType)) { 591 funcStr ~= mixin(interp!" return new Range<${getCSharpInterfaceType(returnTypeStr)}>(dlang_ret, DStringType.None);${newline}"); 592 } else { 593 funcStr ~= " return dlang_ret;" ~ newline; 594 } 595 } 596 funcStr ~= " }" ~ newline; 597 ns.functions ~= funcStr; 598 } 599 } 600 601 private string getDLangInterfaceType(string type) { 602 if (type[$-2..$] == "[]") return "slice"; 603 604 switch(type) { 605 //Types that require special marshalling types 606 case voidTypeString: return "void"; 607 case stringTypeString: return "slice"; 608 case wstringTypeString: return "slice"; 609 case dstringTypeString: return "slice"; 610 case sysTimeTypeString: return "datetime"; 611 case dateTimeTypeString: return "datetime"; 612 case timeOfDayTypeString: return "datetime"; 613 case dateTypeString: return "datetime"; 614 case durationTypeString: return "datetime"; 615 case boolTypeString: return "bool"; 616 617 //Types that can be marshalled by default 618 case charTypeString: return "byte"; 619 case wcharTypeString: return "char"; 620 case dcharTypeString: return "uint"; 621 case ubyteTypeString: return "byte"; 622 case byteTypeString: return "sbyte"; 623 case ushortTypeString: return "ushort"; 624 case shortTypeString: return "short"; 625 case uintTypeString: return "uint"; 626 case intTypeString: return "int"; 627 case ulongTypeString: return "ulong"; 628 case longTypeString: return "long"; 629 case floatTypeString: return "float"; 630 case doubleTypeString: return "double"; 631 default: return getCSharpName(type); 632 } 633 } 634 635 private string getCSharpInterfaceType(string type) { 636 if (type[$-2..$] == "[]") type = type[0..$-2]; 637 638 switch (type) { 639 //Types that require special marshalling types 640 case voidTypeString: return "void"; 641 case stringTypeString: return "string"; 642 case wstringTypeString: return "string"; 643 case dstringTypeString: return "string"; 644 case sysTimeTypeString: return "DateTimeOffset"; 645 case dateTimeTypeString: return "DateTime"; 646 case timeOfDayTypeString: return "DateTime"; 647 case dateTypeString: return "DateTime"; 648 case durationTypeString: return "TimeSpan"; 649 case boolTypeString: return "bool"; 650 651 //Types that can be marshalled by default 652 case charTypeString: return "byte"; 653 case wcharTypeString: return "char"; 654 case dcharTypeString: return "uint"; 655 case ubyteTypeString: return "byte"; 656 case byteTypeString: return "sbyte"; 657 case ushortTypeString: return "ushort"; 658 case shortTypeString: return "short"; 659 case uintTypeString: return "uint"; 660 case intTypeString: return "int"; 661 case ulongTypeString: return "ulong"; 662 case longTypeString: return "long"; 663 case floatTypeString: return "float"; 664 case doubleTypeString: return "double"; 665 default: return getCSharpName(type); 666 } 667 } 668 669 private string getDLangReturnType(string type, bool isClass) { 670 import std.algorithm : among; 671 672 string rtname = getReturnErrorTypeName(getDLangInterfaceType(type)); 673 //These types have predefined C# types. 674 if (type.among(dateTypeString, dateTimeTypeString, sysTimeTypeString, timeOfDayTypeString, durationTypeString, 675 voidTypeString, boolTypeString, stringTypeString, wstringTypeString, dstringTypeString) || rtname == "return_slice_error") { 676 return rtname; 677 } 678 679 string typeStr = " [GeneratedCodeAttribute(\"Autowrap\", \"1.0.0.0\")] 680 [StructLayout(LayoutKind.Sequential)] 681 internal struct " ~ rtname ~ " { 682 private void EnsureValid() { 683 var errStr = SharedFunctions.SliceToString(_error, DStringType._wstring); 684 if (!string.IsNullOrEmpty(errStr)) throw new DLangException(errStr); 685 } 686 "; 687 688 if (isClass) { 689 typeStr ~= mixin(interp!" public static implicit operator IntPtr(${rtname} ret) { ret.EnsureValid(); return ret._value; }${newline}"); 690 typeStr ~= " private IntPtr _value;" ~ newline; 691 } else { 692 typeStr ~= mixin(interp!" public static implicit operator ${getCSharpInterfaceType(type)}(${rtname} ret) { ret.EnsureValid(); return ret._value; }${newline}"); 693 typeStr ~= mixin(interp!" private ${getCSharpInterfaceType(type)} _value;${newline}"); 694 } 695 typeStr ~= " private slice _error;" ~ newline; 696 typeStr ~= " }" ~ newline ~ newline; 697 698 if ((rtname in returnTypes) is null) { 699 returnTypes[rtname] = typeStr; 700 } 701 return rtname; 702 } 703 704 private string getCSharpMethodInterfaceName(string aggName, string funcName) { 705 import autowrap.csharp.common : camelToPascalCase; 706 import std.string : split; 707 import std.string : replace; 708 709 if (aggName == "DateTime" || aggName == "DateTimeOffset" || aggName == "TimeSpan") { 710 aggName = "Datetime"; 711 } 712 713 string name = string.init; 714 if (aggName !is null && aggName != string.init) { 715 name ~= camelToPascalCase(aggName) ~ "_"; 716 } 717 name ~= camelToPascalCase(funcName); 718 return name.replace(".", "_"); 719 } 720 721 private string getReturnErrorTypeName(string aggName) { 722 import std.string : split; 723 import std.array : join; 724 return mixin(interp!"return_${aggName.split(\".\").join(\"_\")}_error"); 725 } 726 727 private string getCSharpName(string dlangName) { 728 import autowrap.csharp.common : camelToPascalCase; 729 import std.algorithm : map; 730 import std.string : split; 731 import std.array : join; 732 return dlangName.split(".").map!camelToPascalCase.join("."); 733 } 734 735 private CSharpNamespace getNamespace(string name) { 736 return namespaces.require(name, new CSharpNamespace(name)); 737 } 738 739 private CSharpAggregate getAggregate(string namespace, string name, bool isStruct) { 740 CSharpNamespace ns = namespaces.require(namespace, new CSharpNamespace(namespace)); 741 return ns.aggregates.require(name, new CSharpAggregate(name, isStruct)); 742 } 743 744 private void generateRangeDef(T)(string libraryName) { 745 import autowrap.csharp.common : getDLangSliceInterfaceName; 746 import std.traits : fullyQualifiedName; 747 748 alias fqn = fullyQualifiedName!T; 749 const string csn = getCSharpName(fqn); 750 751 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "Create")); 752 rangeDef.functions ~= externFuncString.format("return_slice_error", getCSharpMethodInterfaceName(fqn, "Create"), "IntPtr capacity"); 753 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "Slice")); 754 rangeDef.functions ~= externFuncString.format("return_slice_error", getCSharpMethodInterfaceName(fqn, "Slice"), "slice dslice, IntPtr begin, IntPtr end"); 755 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "AppendSlice")); 756 rangeDef.functions ~= externFuncString.format("return_slice_error", getCSharpMethodInterfaceName(fqn, "AppendSlice"), "slice dslice, slice array"); 757 rangeDef.constructors ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) this._slice = RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Create\")}(new IntPtr(capacity));${newline}"); 758 rangeDef.sliceEnd ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) return new Range<T>(RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Slice\")}(_slice, new IntPtr(begin), _slice.length), DStringType.None);${newline}"); 759 rangeDef.sliceRange ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) return new Range<T>(RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Slice\")}(_slice, new IntPtr(begin), new IntPtr(end)), DStringType.None);${newline}"); 760 rangeDef.setters ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Set\")}(_slice, new IntPtr(i), (${getCSharpInterfaceType(fqn)})(object)value);${newline}"); 761 rangeDef.appendValues ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) { this._slice = RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"AppendValue\")}(this._slice, (${getCSharpInterfaceType(fqn)})(object)value); }${newline}"); 762 rangeDef.appendArrays ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) { range._slice = RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"AppendSlice\")}(range._slice, source._slice); return range; }${newline}"); 763 if (is(T == class) || is(T == interface)) { 764 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "Get")); 765 rangeDef.functions ~= externFuncString.format(getDLangReturnType(fqn, true), getCSharpMethodInterfaceName(fqn, "Get"), "slice dslice, IntPtr index"); 766 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "Set")); 767 rangeDef.functions ~= externFuncString.format("return_void_error", getCSharpMethodInterfaceName(fqn, "Set"), "slice dslice, IntPtr index, IntPtr value"); 768 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "AppendValue")); 769 rangeDef.functions ~= externFuncString.format("return_slice_error", getCSharpMethodInterfaceName(fqn, "AppendValue"), "slice dslice, IntPtr value"); 770 rangeDef.getters ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) return (T)(object)new ${getCSharpInterfaceType(fqn)}(RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Get\")}(_slice, new IntPtr(i)));${newline}"); 771 rangeDef.enumerators ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) yield return (T)(object)new ${getCSharpInterfaceType(fqn)}(RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Get\")}(_slice, new IntPtr(i)));${newline}"); 772 } else { 773 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "Get")); 774 rangeDef.functions ~= externFuncString.format(getDLangReturnType(fqn, false), getCSharpMethodInterfaceName(fqn, "Get"), "slice dslice, IntPtr index"); 775 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "Set")); 776 rangeDef.functions ~= externFuncString.format("return_void_error", getCSharpMethodInterfaceName(fqn, "Set"), mixin(interp!"slice dslice, IntPtr index, ${getDLangInterfaceType(fqn)} value")); 777 rangeDef.functions ~= dllImportString.format(libraryName, getDLangSliceInterfaceName(fqn, "AppendValue")); 778 rangeDef.functions ~= externFuncString.format("return_slice_error", getCSharpMethodInterfaceName(fqn, "AppendValue"), mixin(interp!"slice dslice, ${getDLangInterfaceType(fqn)} value")); 779 rangeDef.getters ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) return (T)(object)(${getCSharpInterfaceType(fqn)})RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Get\")}(_slice, new IntPtr(i));${newline}"); 780 rangeDef.enumerators ~= mixin(interp!" else if (typeof(T) == typeof(${getCSharpInterfaceType(fqn)})) yield return (T)(object)(${getCSharpInterfaceType(fqn)})RangeFunctions.${getCSharpMethodInterfaceName(fqn, \"Get\")}(_slice, new IntPtr(i));${newline}"); 781 } 782 } 783 784 private void generateSliceBoilerplate(string libraryName) { 785 import std.datetime: DateTime, SysTime, Duration; 786 787 void generateStringBoilerplate(string dlangType, string csharpType) { 788 rangeDef.enumerators ~= mixin(interp!" else if (typeof(T) == typeof(string) && _strings == null && _type == DStringType._${dlangType}) yield return (T)(object)SharedFunctions.SliceToString(RangeFunctions.${csharpType}_Get(_slice, new IntPtr(i)), DStringType._${dlangType});${newline}"); 789 rangeDef.getters ~= mixin(interp!" else if (typeof(T) == typeof(string) && _strings == null && _type == DStringType._${dlangType}) return (T)(object)SharedFunctions.SliceToString(RangeFunctions.${csharpType}_Get(_slice, new IntPtr(i)), DStringType._${dlangType});${newline}"); 790 rangeDef.setters ~= mixin(interp!" else if (typeof(T) == typeof(string) && _strings == null && _type == DStringType._${dlangType}) RangeFunctions.${csharpType}_Set(_slice, new IntPtr(i), SharedFunctions.Create${csharpType}((string)(object)value));${newline}"); 791 rangeDef.sliceEnd ~= mixin(interp!" else if (typeof(T) == typeof(string) && _strings == null && _type == DStringType._${dlangType}) return new Range<T>(RangeFunctions.${csharpType}_Slice(_slice, new IntPtr(begin), _slice.length), _type);${newline}"); 792 rangeDef.sliceRange ~= mixin(interp!" else if (typeof(T) == typeof(string) && _strings == null && _type == DStringType._${dlangType}) return new Range<T>(RangeFunctions.${csharpType}_Slice(_slice, new IntPtr(begin), new IntPtr(end)), _type);${newline}"); 793 rangeDef.appendValues ~= mixin(interp!" else if (typeof(T) == typeof(string) && _strings == null && _type == DStringType._${dlangType}) { _slice = RangeFunctions.${csharpType}_AppendValue(_slice, SharedFunctions.Create${csharpType}((string)(object)value)); }${newline}"); 794 rangeDef.appendArrays ~= mixin(interp!" else if (typeof(T) == typeof(string) && range._strings == null && range._type == DStringType._${dlangType}) { range._slice = RangeFunctions.${csharpType}_AppendSlice(range._slice, source._slice); return range; }${newline}"); 795 796 rangeDef.functions ~= dllImportString.format(libraryName, mixin(interp!"autowrap_csharp_${csharpType}_Create")); 797 rangeDef.functions ~= externFuncString.format("return_slice_error", csharpType ~ "_Create", "IntPtr capacity"); 798 rangeDef.functions ~= dllImportString.format(libraryName, mixin(interp!"autowrap_csharp_${csharpType}_Get")); 799 rangeDef.functions ~= externFuncString.format("return_slice_error", csharpType ~ "_Get", "slice dslice, IntPtr index"); 800 rangeDef.functions ~= dllImportString.format(libraryName, mixin(interp!"autowrap_csharp_${csharpType}_Set")); 801 rangeDef.functions ~= externFuncString.format("return_void_error", csharpType ~ "_Set", "slice dslice, IntPtr index, slice value"); 802 rangeDef.functions ~= dllImportString.format(libraryName, mixin(interp!"autowrap_csharp_${csharpType}_Slice")); 803 rangeDef.functions ~= externFuncString.format("return_slice_error", csharpType ~ "_Slice", "slice dslice, IntPtr begin, IntPtr end"); 804 rangeDef.functions ~= dllImportString.format(libraryName, mixin(interp!"autowrap_csharp_${csharpType}_AppendValue")); 805 rangeDef.functions ~= externFuncString.format("return_slice_error", csharpType ~ "_AppendValue", "slice dslice, slice value"); 806 rangeDef.functions ~= dllImportString.format(libraryName, mixin(interp!"autowrap_csharp_${csharpType}_AppendSlice")); 807 rangeDef.functions ~= externFuncString.format("return_slice_error", csharpType ~ "_AppendSlice", "slice dslice, slice array"); 808 } 809 810 //bool 811 rangeDef.functions ~= dllImportString.format(libraryName, "autowrap_csharp_Bool_Create"); 812 rangeDef.functions ~= externFuncString.format("return_slice_error", "Bool_Create", "IntPtr capacity"); 813 rangeDef.functions ~= dllImportString.format(libraryName, "autowrap_csharp_Bool_Get"); 814 rangeDef.functions ~= " [return: MarshalAs(UnmanagedType.Bool)]" ~ newline; 815 rangeDef.functions ~= externFuncString.format("return_bool_error", "Bool_Get", "slice dslice, IntPtr index"); 816 rangeDef.functions ~= dllImportString.format(libraryName, "autowrap_csharp_Bool_Set"); 817 rangeDef.functions ~= externFuncString.format("return_void_error", "Bool_Set", "slice dslice, IntPtr index, [MarshalAs(UnmanagedType.Bool)] bool value"); 818 rangeDef.functions ~= dllImportString.format(libraryName, "autowrap_csharp_Bool_Slice"); 819 rangeDef.functions ~= externFuncString.format("return_slice_error", "Bool_Slice", "slice dslice, IntPtr begin, IntPtr end"); 820 rangeDef.functions ~= dllImportString.format(libraryName, "autowrap_csharp_Bool_AppendValue"); 821 rangeDef.functions ~= externFuncString.format("return_slice_error", "Bool_AppendValue", "slice dslice, [MarshalAs(UnmanagedType.Bool)] bool value"); 822 rangeDef.functions ~= dllImportString.format(libraryName, "autowrap_csharp_Bool_AppendSlice"); 823 rangeDef.functions ~= externFuncString.format("return_slice_error", "Bool_AppendSlice", "slice dslice, slice array"); 824 rangeDef.constructors ~= " if (typeof(T) == typeof(bool)) this._slice = RangeFunctions.Bool_Create(new IntPtr(capacity));" ~ newline; 825 rangeDef.enumerators ~= " if (typeof(T) == typeof(bool)) yield return (T)(object)RangeFunctions.Bool_Get(_slice, new IntPtr(i));" ~ newline; 826 rangeDef.getters ~= " if (typeof(T) == typeof(bool)) return (T)(object)RangeFunctions.Bool_Get(_slice, new IntPtr(i));" ~ newline; 827 rangeDef.setters ~= " if (typeof(T) == typeof(bool)) RangeFunctions.Bool_Set(_slice, new IntPtr(i), (bool)(object)value);" ~ newline; 828 rangeDef.sliceEnd ~= " if (typeof(T) == typeof(bool)) return new Range<T>(RangeFunctions.Bool_Slice(_slice, new IntPtr(begin), _slice.length), DStringType.None);" ~ newline; 829 rangeDef.sliceRange ~= " if (typeof(T) == typeof(bool)) return new Range<T>(RangeFunctions.Bool_Slice(_slice, new IntPtr(begin), new IntPtr(end)), DStringType.None);" ~ newline; 830 rangeDef.appendValues ~= " if (typeof(T) == typeof(bool)) { this._slice = RangeFunctions.Bool_AppendValue(this._slice, (bool)(object)value); }" ~ newline; 831 rangeDef.appendArrays ~= " if (typeof(T) == typeof(bool)) { range._slice = RangeFunctions.Bool_AppendSlice(range._slice, source._slice); return range; }" ~ newline; 832 833 rangeDef.enumerators ~= " else if (typeof(T) == typeof(string) && _strings != null && _type == DStringType.None) yield return (T)(object)_strings[(int)i];" ~ newline; 834 rangeDef.getters ~= " else if (typeof(T) == typeof(string) && _strings != null && _type == DStringType.None) return (T)(object)_strings[(int)i];" ~ newline; 835 rangeDef.setters ~= " else if (typeof(T) == typeof(string) && _strings != null && _type == DStringType.None) _strings[(int)i] = (string)(object)value;" ~ newline; 836 rangeDef.sliceEnd ~= " else if (typeof(T) == typeof(string) && _strings != null && _type == DStringType.None) return new Range<T>((IEnumerable<T>)_strings.Skip((int)begin));" ~ newline; 837 rangeDef.sliceRange ~= " else if (typeof(T) == typeof(string) && _strings != null && _type == DStringType.None) return new Range<T>((IEnumerable<T>)_strings.Skip((int)begin).Take((int)end - (int)begin));" ~ newline; 838 rangeDef.appendValues ~= " else if (typeof(T) == typeof(string) && this._strings != null && this._type == DStringType.None) { this._strings.Add((string)(object)value); }" ~ newline; 839 rangeDef.appendArrays ~= " else if (typeof(T) == typeof(string) && range._strings != null && range._type == DStringType.None) { foreach(T s in source) range._strings.Add((string)(object)s); return range; }" ~ newline; 840 841 generateStringBoilerplate("string", "String"); 842 generateStringBoilerplate("wstring", "Wstring"); 843 generateStringBoilerplate("dstring", "Dstring"); 844 845 generateRangeDef!byte(libraryName); 846 generateRangeDef!ubyte(libraryName); 847 generateRangeDef!short(libraryName); 848 generateRangeDef!ushort(libraryName); 849 generateRangeDef!int(libraryName); 850 generateRangeDef!uint(libraryName); 851 generateRangeDef!long(libraryName); 852 generateRangeDef!ulong(libraryName); 853 generateRangeDef!float(libraryName); 854 generateRangeDef!double(libraryName); 855 856 generateRangeDef!DateTime(libraryName); 857 generateRangeDef!SysTime(libraryName); 858 generateRangeDef!Duration(libraryName); 859 } 860 861 private string writeCSharpBoilerplate(string libraryName, string rootNamespace) { 862 string returnTypesStr = string.init; 863 foreach(string rt; returnTypes.byValue) { 864 returnTypesStr ~= rt; 865 } 866 immutable string boilerplate = import("Boilerplate.cs"); 867 return boilerplate.format(libraryName, rootNamespace, returnTypesStr, rangeDef.toString()); 868 }