1 module godot.stringname; 2 3 import std.traits; 4 import std.exception : assumeWontThrow; 5 import godot.builtins; 6 import godot.poolarrays; 7 import godot.abi; 8 import godot.abi.gdextension; 9 import godot.string; 10 11 import godot.variant; 12 13 /// Initializes an empty StringName 14 alias stringName = StringName.makeEmpty; 15 16 struct StringName { 17 //@nogc nothrow: 18 19 package(godot) union _StringName { 20 godot_string _godot_string_name; 21 StringName_Bind _bind; 22 } 23 24 package(godot) _StringName _stringName; 25 alias _stringName this; 26 27 this(String s) { 28 this = _bind.new2(s); 29 } 30 31 this(this) { 32 33 } 34 35 this(string s) { 36 auto str = String(s); 37 this(str); 38 } 39 40 /++ 41 Numeric constructor. S can be a built-in numeric type. 42 +/ 43 this(S)(in S num) if (isNumeric!S) { 44 import std.conv : text; 45 this(num.text); 46 } 47 48 deprecated("Default struct ctor is not allowed, please use `stringName()` instead") 49 @disable this(); 50 51 //this(ref const StringName s) 52 //{ 53 // this = _bind.new1(s); 54 //} 55 56 void _defaultCtor() { 57 this = StringName_Bind.new0(); 58 } 59 60 static StringName makeEmpty() { 61 StringName sn = void; 62 sn._defaultCtor(); 63 return sn; 64 } 65 66 /// Returns the length of the char32_t array, minus the zero terminator. 67 size_t length() const { 68 auto len = _godot_api.string_to_utf8_chars(&_godot_string_name, null, 0); 69 return len; 70 //return _godot_api.string_length(&_godot_string); 71 } 72 73 /// Returns: $(D true) if length is 0 74 bool empty() const { 75 return length == 0; 76 } 77 78 /// Returns a pointer to the wchar_t data. Always zero-terminated. 79 immutable(char32_t)* ptr() const { 80 return cast(immutable(char32_t)*) _godot_api.string_operator_index_const( 81 &_godot_string_name, 0); 82 } 83 84 /// Returns a slice of the char32_t data without the zero terminator. 85 dstring data() const { 86 // in godot-cpp there is actually no such things like data(), ptr() and length() for StringName 87 return cast(typeof(return)) ptr[0 .. length]; 88 } 89 90 package(godot) this(in godot_string strname) { 91 _godot_string_name = strname; 92 } 93 94 /++ 95 char constructor. S can be a slice (like `string`) or a null-terminated pointer. 96 +/ 97 this(S)(in S str) 98 if (isImplicitlyConvertible!(S, const(char)[]) || 99 isImplicitlyConvertible!(S, const(char)*)) { 100 static if (isImplicitlyConvertible!(S, const(char)[])) { 101 const(char)[] contents = str; 102 _godot_api.string_new_with_latin1_chars_and_len(&_godot_string_name, contents.ptr, cast( 103 int) contents.length); 104 } else { 105 import core.stdc.string : strlen; 106 107 const(char)* contents = str; 108 _godot_api.string_new_with_latin1_chars_and_len(&_godot_string_name, contents, cast(int) strlen( 109 contents)); 110 } 111 } 112 113 ~this() { 114 //_bind._destructor(); 115 _godot_string_name = _godot_string_name.init; 116 } 117 118 void opAssign(in StringName other) { 119 //if (&_godot_string_name) 120 // _bind._destructor(); 121 122 _godot_string_name = other._godot_string_name; 123 } 124 125 void opAssign(in string other) { 126 //if (&_godot_string_name) 127 // _bind._destructor(); 128 godot_string gs; 129 _godot_api.string_new_with_utf8_chars_and_len(&gs, other.ptr, cast(int) other.length); 130 _godot_string_name = gs; 131 } 132 133 bool opEquals(in StringName other) const { 134 if (_godot_string_name == other._godot_string_name) 135 return true; 136 // FIXME: no idea if there is actually such thing 137 //return _godot_api.string_name_operator_equal(&_godot_string_name, &other._godot_string_name); 138 return false; 139 } 140 141 String opCast(T : String)() const { 142 return String(_godot_string_name); 143 } 144 145 GDExtensionStringNamePtr opCast(T = GDExtensionStringNamePtr)() const { 146 return cast(GDExtensionStringNamePtr) &_godot_string_name; 147 } 148 149 @trusted 150 hash_t toHash() const nothrow { 151 return cast(hash_t) assumeWontThrow(_bind.hash()); 152 //static if(hash_t.sizeof == uint.sizeof) return _godot_api.string_hash(&_godot_string); 153 //else return _godot_api.string_hash64(&_godot_string); 154 } 155 156 } 157 158 /** 159 * Constructs Godot String Name from str 160 * Params: 161 * str = string to convert from 162 * Returns: Godot String Name 163 */ 164 StringName toGodotStringName(string str) { 165 // FIXME: this is going to be slow as hell 166 godot_string gs; 167 _godot_api.string_new_with_utf8_chars_and_len(&gs, str.ptr, cast(int) str.length); 168 String* p = cast(String*)&gs; 169 return StringName(*p); 170 } 171 172 /** 173 * Constructs string from str 174 * Params: 175 * str = Godot String Name 176 * Returns: D string 177 */ 178 string toDStringName(StringName str) { 179 // FIXME: this is going to be slow as hell 180 import std.conv: to; 181 return str.data.to!string; 182 } 183 184 struct GodotStringNameLiteral(string data) { 185 private __gshared godot_string gs; 186 StringName str() const { 187 static if (data.length) 188 if (gs == godot_string.init) { 189 synchronized { 190 if (gs == godot_string.init) 191 _godot_api.string_new_with_utf8_chars_and_len(&gs, data.ptr, cast(int) data 192 .length); 193 } 194 } 195 // a pointer so it won't destroy itself ahead of time 196 String* p = cast(String*)&gs; 197 //String ret = void; 198 //_godot_api.variant_new_copy(&ret._godot_string, &gs); 199 //return ret; 200 return StringName(*p); 201 } 202 203 static if (data.length) { 204 shared static ~this() { 205 //if(gs != godot_string.init) _godot_api.variant_destroy(&gs); 206 } 207 } 208 alias str this; 209 } 210 211 /++ 212 Create a GodotStringNameLiteral. 213 214 D $(D string) to Godot $(D StringName) conversion is expensive and cannot be done 215 at compile time. This literal does the conversion once the first time it's 216 needed, then caches the StringName, allowing it to implicitly convert to StringName at 217 no run time cost. 218 +/ 219 enum gn(string str) = GodotStringNameLiteral!str.init;