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