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