1 /** 2 Structure to describe D classes with properties dynamically, to avoid generating Wren code ahead of time. Also saves some D code for properties. 3 4 Copyright: Guillaume Piolat 2021. 5 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 */ 7 module dplug.wren.describe; 8 9 import core.stdc.stdlib: malloc, free; 10 import dplug.core.vec; 11 12 nothrow @nogc: 13 14 // For the usage of WrenSupport, describe D classes in a way that can be generated at compile-time. 15 16 /// Note: WrenSupport must be able to generate the module, foreign classes, and foreign methods from this description. 17 class ScriptExportClass 18 { 19 nothrow @nogc: 20 public: 21 22 this(TypeInfo_Class classInfo) 23 { 24 _concreteClassInfo = classInfo; 25 26 // build wren identifier 27 string fullName = concreteClassInfo.name; 28 int LEN = cast(int)fullName.length; 29 30 // try to find rightmost '.' 31 string strippedName = fullName; 32 for(int n = LEN - 1; n >= 0; --n) 33 { 34 if (fullName[n] == '.') 35 { 36 strippedName = fullName[n+1..$]; 37 break; 38 } 39 } 40 41 _wrenClassName = convertDStringToCString(strippedName); 42 } 43 44 ~this() 45 { 46 free(_wrenClassName); 47 } 48 49 /// The full D identifier of the class, with module identifiers. 50 /// eg: dplug.pbkwidgets.knob.UIKnob 51 string fullClassName() 52 { 53 return concreteClassInfo.name; 54 } 55 56 /// Its .classinfo 57 TypeInfo_Class concreteClassInfo() 58 { 59 return _concreteClassInfo; 60 } 61 62 ScriptPropertyDesc[] properties() 63 { 64 return _properties[]; 65 } 66 67 /// The identifier of the class in Wren code. It is stripped from module identifiers. 68 /// Zero-terminated. 69 /// eg: "UIKnob" 70 const(char)* wrenClassNameZ() 71 { 72 return _wrenClassName; 73 } 74 75 void addProperty(ScriptPropertyDesc prop) 76 { 77 prop.nth = cast(int)_properties.length; 78 _properties ~= prop; 79 } 80 81 private: 82 83 char* _wrenClassName; 84 85 /// Its .classinfo 86 TypeInfo_Class _concreteClassInfo; // the D ClassInfo of the D class named by fullClassName() 87 88 89 Vec!ScriptPropertyDesc _properties; 90 } 91 92 /// All possible types of properties. 93 enum ScriptPropertyType 94 { 95 bool_, 96 97 byte_, 98 ubyte_, 99 short_, 100 ushort_, 101 int_, 102 uint_, 103 104 float_, 105 double_, 106 107 // Color types from dplug:graphics 108 RGBA, 109 } 110 111 struct ScriptPropertyDesc 112 { 113 nothrow @nogc: 114 public: 115 // type enumeration 116 ScriptPropertyType type; 117 118 /// Byte offset in the class. 119 int offset; 120 121 /// Number of the property in the _properties array. 122 int nth; 123 124 /// The D identifier of the property. 125 /// Not owned, has to be compile-time. 126 string identifier; 127 128 size_t sizeInInstance() 129 { 130 return SCRIPT_PROPERTY_SIZES[type]; 131 } 132 133 private: 134 } 135 136 137 private: 138 139 static immutable size_t[ScriptPropertyType.max+1] SCRIPT_PROPERTY_SIZES = 140 [ 1, 1, 1, 2, 2, 4, 4, 4, 8, 4]; 141 142 143 /// Allocated a zero-terminated C string from a D string. A copy is always made, and has to be released with free. 144 char* convertDStringToCString(const(char)[] cstr) nothrow @nogc 145 { 146 assert(cstr !is null); 147 size_t len = cstr.length; 148 char* copy = cast(char*) malloc(len + 1); 149 copy[0..len] = cstr[0..len]; 150 copy[len] = '\0'; 151 return copy; 152 }