1 /** 2 Godot's ref-counted wchar_t String class. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.core..string; 14 15 import core.stdc.stddef : wchar_t; 16 import godot.c; 17 import std.traits; 18 19 struct CharString 20 { 21 @nogc nothrow: 22 23 package(godot) godot_char_string _char_string; 24 25 immutable(char)* ptr() const 26 { 27 return cast(typeof(return))_godot_api.godot_char_string_get_data(&_char_string); 28 } 29 30 size_t length() const 31 { 32 return _godot_api.godot_char_string_length(&_char_string); 33 } 34 35 immutable(char)[] data() const 36 { 37 return ptr[0..length]; 38 } 39 40 ~this() 41 { 42 _godot_api.godot_char_string_destroy(&_char_string); 43 } 44 } 45 46 /** 47 This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necessary means for string handling. Strings are reference counted and use a copy-on-write approach, so passing them around is cheap in resources. 48 */ 49 struct String 50 { 51 @nogc nothrow: 52 53 package(godot) godot_string _godot_string; 54 55 /// postblit (Vector is CoW, so no data copying is done) 56 this(this) 57 { 58 godot_string other = _godot_string; 59 _godot_api.godot_string_new_copy(&_godot_string, &other); 60 } 61 62 package(godot) this(in godot_string str) 63 { 64 _godot_string = str; 65 } 66 67 /++ 68 wchar_t constructor. S can be a slice or a null-terminated pointer. 69 +/ 70 this(S)(in S str) if(isImplicitlyConvertible!(S, const(wchar_t)[]) || 71 isImplicitlyConvertible!(S, const(wchar_t)*)) 72 { 73 static if(isImplicitlyConvertible!(S, const(wchar_t)[])) 74 { 75 const(wchar_t)[] contents = str; 76 _godot_api.godot_string_new_with_wide_string(&_godot_string, contents.ptr, cast(int)contents.length); 77 } 78 else 79 { 80 import core.stdc.wchar_ : wcslen; 81 const(wchar_t)* contents = str; 82 _godot_api.godot_string_new_with_wide_string(&_godot_string, contents, cast(int)wcslen(contents)); 83 } 84 } 85 86 /++ 87 UTF-8 constructor. S can be a slice (like `string`) or a null-terminated pointer. 88 +/ 89 this(S)(in S str) if(isImplicitlyConvertible!(S, const(char)[]) || 90 isImplicitlyConvertible!(S, const(char)*)) 91 { 92 static if(isImplicitlyConvertible!(S, const(char)[])) 93 { 94 import std.experimental.allocator, std.experimental.allocator.mallocator; 95 char[] contents = Mallocator.instance.makeArray!char(str.length+1); 96 scope(exit) Mallocator.instance.deallocate(cast(void[])contents); 97 contents[0..str.length] = str; 98 contents[str.length] = '\0'; 99 _godot_api.godot_string_parse_utf8(&_godot_string, contents.ptr); 100 } 101 else 102 { 103 const(char)* contents = str; 104 _godot_api.godot_string_parse_utf8(&_godot_string, contents); 105 } 106 } 107 108 ~this() 109 { 110 _godot_api.godot_string_destroy(&_godot_string); 111 } 112 113 114 void opAssign(in String other) 115 { 116 _godot_api.godot_string_destroy(&_godot_string); 117 _godot_api.godot_string_new_copy(&_godot_string, &other._godot_string); 118 } 119 120 121 /+String substr(int p_from,int p_chars) const 122 { 123 return String.empty; // todo 124 } 125 126 alias opSlice = substr;+/ 127 128 129 ref wchar_t opIndex(in size_t idx) 130 { 131 return *_godot_api.godot_string_operator_index(&_godot_string, cast(int)idx); 132 } 133 134 wchar_t opIndex(in size_t idx) const 135 { 136 return *_godot_api.godot_string_operator_index(cast(godot_string*) &_godot_string, cast(int)idx); 137 } 138 139 /// Returns the length of the wchar_t array, minus the zero terminator. 140 size_t length() const 141 { 142 return _godot_api.godot_string_length(&_godot_string); 143 } 144 145 /// Returns: $(D true) if length is 0 146 bool empty() 147 { 148 return length == 0; 149 } 150 151 int opCmp(in ref String s) 152 { 153 auto equal = _godot_api.godot_string_operator_equal(&_godot_string, &s._godot_string); 154 if(equal) return 0; 155 auto less = _godot_api.godot_string_operator_less(&_godot_string, &s._godot_string); 156 return less?(-1):1; 157 } 158 159 String opBinary(string op : "~")(in String other) const 160 { 161 String ret = void; 162 ret._godot_string = _godot_api.godot_string_operator_plus(&_godot_string, &other._godot_string); 163 164 return ret; 165 } 166 167 void opOpAssign(string op : "~")(in String other) 168 { 169 _godot_string = _godot_api.godot_string_operator_plus(&_godot_string, &other._godot_string); 170 } 171 172 /// Returns a pointer to the wchar_t data. Always zero-terminated. 173 immutable(wchar_t)* ptr() const 174 { 175 return cast(typeof(return))_godot_api.godot_string_wide_str(&_godot_string); 176 } 177 178 /// Returns a slice of the wchar_t data without the zero terminator. 179 immutable(wchar_t)[] data() const 180 { 181 return ptr[0..length]; 182 } 183 alias toString = data; 184 185 CharString utf8() const 186 { 187 CharString ret = void; 188 ret._char_string = _godot_api.godot_string_utf8(&_godot_string); 189 return ret; 190 } 191 } 192 193 struct GodotStringLiteral(string data) 194 { 195 private static godot_string gs; 196 String str() const 197 { 198 static if(data.length) if(gs == godot_string.init) 199 { 200 _godot_api.godot_string_parse_utf8(&gs, data); 201 } 202 String ret = void; 203 _godot_api.godot_string_new_copy(&ret._godot_string, &gs); 204 return ret; 205 } 206 alias str this; 207 } 208 209 /++ 210 Create a GodotStringLiteral. 211 212 D $(D string) to Godot $(D String) conversion is expensive and cannot be done 213 at compile time. This literal does the conversion once the first time it's 214 needed, then caches the String, allowing it to implicitly convert to String at 215 no run time cost. 216 +/ 217 enum gs(string str) = GodotStringLiteral!str.init; 218 219 220 221 222 223