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