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 const(char)[] contents = str; 95 _godot_api.godot_string_parse_utf8_with_len(&_godot_string, contents.ptr, cast(int)contents.length); 96 } 97 else 98 { 99 const(char)* contents = str; 100 _godot_api.godot_string_parse_utf8(&_godot_string, contents); 101 } 102 } 103 104 ~this() 105 { 106 _godot_api.godot_string_destroy(&_godot_string); 107 } 108 109 110 void opAssign(in String other) 111 { 112 _godot_api.godot_string_destroy(&_godot_string); 113 _godot_api.godot_string_new_copy(&_godot_string, &other._godot_string); 114 } 115 116 117 /+String substr(int p_from,int p_chars) const 118 { 119 return String.empty; // todo 120 } 121 122 alias opSlice = substr;+/ 123 124 125 ref wchar_t opIndex(in size_t idx) 126 { 127 return *_godot_api.godot_string_operator_index(&_godot_string, cast(int)idx); 128 } 129 130 wchar_t opIndex(in size_t idx) const 131 { 132 return *_godot_api.godot_string_operator_index(cast(godot_string*) &_godot_string, cast(int)idx); 133 } 134 135 /// Returns the length of the wchar_t array, minus the zero terminator. 136 size_t length() const 137 { 138 return _godot_api.godot_string_length(&_godot_string); 139 } 140 141 /// Returns: $(D true) if length is 0 142 bool empty() 143 { 144 return length == 0; 145 } 146 147 int opCmp(in ref String s) 148 { 149 auto equal = _godot_api.godot_string_operator_equal(&_godot_string, &s._godot_string); 150 if(equal) return 0; 151 auto less = _godot_api.godot_string_operator_less(&_godot_string, &s._godot_string); 152 return less?(-1):1; 153 } 154 155 String opBinary(string op : "~")(in String other) const 156 { 157 String ret = void; 158 ret._godot_string = _godot_api.godot_string_operator_plus(&_godot_string, &other._godot_string); 159 160 return ret; 161 } 162 163 void opOpAssign(string op : "~")(in String other) 164 { 165 _godot_string = _godot_api.godot_string_operator_plus(&_godot_string, &other._godot_string); 166 } 167 168 /// Returns a pointer to the wchar_t data. Always zero-terminated. 169 immutable(wchar_t)* ptr() const 170 { 171 return cast(typeof(return))_godot_api.godot_string_wide_str(&_godot_string); 172 } 173 174 /// Returns a slice of the wchar_t data without the zero terminator. 175 immutable(wchar_t)[] data() const 176 { 177 return ptr[0..length]; 178 } 179 alias toString = data; 180 181 CharString utf8() const 182 { 183 CharString ret = void; 184 ret._char_string = _godot_api.godot_string_utf8(&_godot_string); 185 return ret; 186 } 187 } 188 189 struct GodotStringLiteral(string data) 190 { 191 private __gshared godot_string gs; 192 String str() const 193 { 194 static if(data.length) if(gs == godot_string.init) 195 { 196 synchronized 197 { 198 if(gs == godot_string.init) _godot_api.godot_string_parse_utf8_with_len(&gs, data.ptr, cast(int)data.length); 199 } 200 } 201 String ret = void; 202 _godot_api.godot_string_new_copy(&ret._godot_string, &gs); 203 return ret; 204 } 205 static if(data.length) 206 { 207 shared static ~this() 208 { 209 if(gs != godot_string.init) _godot_api.godot_string_destroy(&gs); 210 } 211 } 212 alias str this; 213 } 214 215 /++ 216 Create a GodotStringLiteral. 217 218 D $(D string) to Godot $(D String) conversion is expensive and cannot be done 219 at compile time. This literal does the conversion once the first time it's 220 needed, then caches the String, allowing it to implicitly convert to String at 221 no run time cost. 222 +/ 223 enum gs(string str) = GodotStringLiteral!str.init; 224 225 226 227 228 229