1 /*************************************************************************/
2 /*  collections_glue.cpp                                                 */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "collections_glue.h"
32 
33 #ifdef MONO_GLUE_ENABLED
34 
35 #include <mono/metadata/exception.h>
36 
37 #include "../mono_gd/gd_mono_cache.h"
38 #include "../mono_gd/gd_mono_class.h"
39 #include "../mono_gd/gd_mono_utils.h"
40 
godot_icall_Array_Ctor()41 Array *godot_icall_Array_Ctor() {
42 	return memnew(Array);
43 }
44 
godot_icall_Array_Dtor(Array * ptr)45 void godot_icall_Array_Dtor(Array *ptr) {
46 	memdelete(ptr);
47 }
48 
godot_icall_Array_At(Array * ptr,int index)49 MonoObject *godot_icall_Array_At(Array *ptr, int index) {
50 	if (index < 0 || index >= ptr->size()) {
51 		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
52 		return NULL;
53 	}
54 	return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
55 }
56 
godot_icall_Array_At_Generic(Array * ptr,int index,uint32_t type_encoding,GDMonoClass * type_class)57 MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) {
58 	if (index < 0 || index >= ptr->size()) {
59 		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
60 		return NULL;
61 	}
62 	return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
63 }
64 
godot_icall_Array_SetAt(Array * ptr,int index,MonoObject * value)65 void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
66 	if (index < 0 || index >= ptr->size()) {
67 		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
68 		return;
69 	}
70 	ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
71 }
72 
godot_icall_Array_Count(Array * ptr)73 int godot_icall_Array_Count(Array *ptr) {
74 	return ptr->size();
75 }
76 
godot_icall_Array_Add(Array * ptr,MonoObject * item)77 int godot_icall_Array_Add(Array *ptr, MonoObject *item) {
78 	ptr->append(GDMonoMarshal::mono_object_to_variant(item));
79 	return ptr->size();
80 }
81 
godot_icall_Array_Clear(Array * ptr)82 void godot_icall_Array_Clear(Array *ptr) {
83 	ptr->clear();
84 }
85 
godot_icall_Array_Contains(Array * ptr,MonoObject * item)86 MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
87 	return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
88 }
89 
godot_icall_Array_CopyTo(Array * ptr,MonoArray * array,int array_index)90 void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) {
91 	unsigned int count = ptr->size();
92 
93 	if (mono_array_length(array) < (array_index + count)) {
94 		MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
95 		GDMonoUtils::set_pending_exception(exc);
96 		return;
97 	}
98 
99 	for (unsigned int i = 0; i < count; i++) {
100 		MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i));
101 		mono_array_setref(array, array_index, boxed);
102 		array_index++;
103 	}
104 }
105 
godot_icall_Array_Duplicate(Array * ptr,MonoBoolean deep)106 Array *godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep) {
107 	return memnew(Array(ptr->duplicate(deep)));
108 }
109 
godot_icall_Array_IndexOf(Array * ptr,MonoObject * item)110 int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
111 	return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
112 }
113 
godot_icall_Array_Insert(Array * ptr,int index,MonoObject * item)114 void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
115 	if (index < 0 || index > ptr->size()) {
116 		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
117 		return;
118 	}
119 	ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item));
120 }
121 
godot_icall_Array_Remove(Array * ptr,MonoObject * item)122 MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
123 	int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
124 	if (idx >= 0) {
125 		ptr->remove(idx);
126 		return true;
127 	}
128 	return false;
129 }
130 
godot_icall_Array_RemoveAt(Array * ptr,int index)131 void godot_icall_Array_RemoveAt(Array *ptr, int index) {
132 	if (index < 0 || index >= ptr->size()) {
133 		GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
134 		return;
135 	}
136 	ptr->remove(index);
137 }
138 
godot_icall_Array_Resize(Array * ptr,int new_size)139 Error godot_icall_Array_Resize(Array *ptr, int new_size) {
140 	return ptr->resize(new_size);
141 }
142 
godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType * refltype,uint32_t * type_encoding,GDMonoClass ** type_class)143 void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
144 	MonoType *elem_type = mono_reflection_type_get_type(refltype);
145 
146 	*type_encoding = mono_type_get_type(elem_type);
147 	MonoClass *type_class_raw = mono_class_from_mono_type(elem_type);
148 	*type_class = GDMono::get_singleton()->get_class(type_class_raw);
149 }
150 
godot_icall_Array_ToString(Array * ptr)151 MonoString *godot_icall_Array_ToString(Array *ptr) {
152 	return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
153 }
154 
godot_icall_Dictionary_Ctor()155 Dictionary *godot_icall_Dictionary_Ctor() {
156 	return memnew(Dictionary);
157 }
158 
godot_icall_Dictionary_Dtor(Dictionary * ptr)159 void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
160 	memdelete(ptr);
161 }
162 
godot_icall_Dictionary_GetValue(Dictionary * ptr,MonoObject * key)163 MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
164 	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
165 	if (ret == NULL) {
166 		MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
167 #ifdef DEBUG_ENABLED
168 		CRASH_COND(!exc);
169 #endif
170 		GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
171 		GDMonoUtils::set_pending_exception((MonoException *)exc);
172 		return NULL;
173 	}
174 	return GDMonoMarshal::variant_to_mono_object(ret);
175 }
176 
godot_icall_Dictionary_GetValue_Generic(Dictionary * ptr,MonoObject * key,uint32_t type_encoding,GDMonoClass * type_class)177 MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) {
178 	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
179 	if (ret == NULL) {
180 		MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
181 #ifdef DEBUG_ENABLED
182 		CRASH_COND(!exc);
183 #endif
184 		GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
185 		GDMonoUtils::set_pending_exception((MonoException *)exc);
186 		return NULL;
187 	}
188 	return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
189 }
190 
godot_icall_Dictionary_SetValue(Dictionary * ptr,MonoObject * key,MonoObject * value)191 void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) {
192 	ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value);
193 }
194 
godot_icall_Dictionary_Keys(Dictionary * ptr)195 Array *godot_icall_Dictionary_Keys(Dictionary *ptr) {
196 	return memnew(Array(ptr->keys()));
197 }
198 
godot_icall_Dictionary_Values(Dictionary * ptr)199 Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
200 	return memnew(Array(ptr->values()));
201 }
202 
godot_icall_Dictionary_Count(Dictionary * ptr)203 int godot_icall_Dictionary_Count(Dictionary *ptr) {
204 	return ptr->size();
205 }
206 
godot_icall_Dictionary_Add(Dictionary * ptr,MonoObject * key,MonoObject * value)207 void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
208 	Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
209 	Variant *ret = ptr->getptr(varKey);
210 	if (ret != NULL) {
211 		GDMonoUtils::set_pending_exception(mono_get_exception_argument("key", "An element with the same key already exists"));
212 		return;
213 	}
214 	ptr->operator[](varKey) = GDMonoMarshal::mono_object_to_variant(value);
215 }
216 
godot_icall_Dictionary_Clear(Dictionary * ptr)217 void godot_icall_Dictionary_Clear(Dictionary *ptr) {
218 	ptr->clear();
219 }
220 
godot_icall_Dictionary_Contains(Dictionary * ptr,MonoObject * key,MonoObject * value)221 MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
222 	// no dupes
223 	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
224 	return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value);
225 }
226 
godot_icall_Dictionary_ContainsKey(Dictionary * ptr,MonoObject * key)227 MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
228 	return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
229 }
230 
godot_icall_Dictionary_Duplicate(Dictionary * ptr,MonoBoolean deep)231 Dictionary *godot_icall_Dictionary_Duplicate(Dictionary *ptr, MonoBoolean deep) {
232 	return memnew(Dictionary(ptr->duplicate(deep)));
233 }
234 
godot_icall_Dictionary_RemoveKey(Dictionary * ptr,MonoObject * key)235 MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
236 	return ptr->erase(GDMonoMarshal::mono_object_to_variant(key));
237 }
238 
godot_icall_Dictionary_Remove(Dictionary * ptr,MonoObject * key,MonoObject * value)239 MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
240 	Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
241 
242 	// no dupes
243 	Variant *ret = ptr->getptr(varKey);
244 	if (ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
245 		ptr->erase(varKey);
246 		return true;
247 	}
248 
249 	return false;
250 }
251 
godot_icall_Dictionary_TryGetValue(Dictionary * ptr,MonoObject * key,MonoObject ** value)252 MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
253 	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
254 	if (ret == NULL) {
255 		*value = NULL;
256 		return false;
257 	}
258 	*value = GDMonoMarshal::variant_to_mono_object(ret);
259 	return true;
260 }
261 
godot_icall_Dictionary_TryGetValue_Generic(Dictionary * ptr,MonoObject * key,MonoObject ** value,uint32_t type_encoding,GDMonoClass * type_class)262 MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
263 	Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
264 	if (ret == NULL) {
265 		*value = NULL;
266 		return false;
267 	}
268 	*value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
269 	return true;
270 }
271 
godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType * refltype,uint32_t * type_encoding,GDMonoClass ** type_class)272 void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
273 	MonoType *value_type = mono_reflection_type_get_type(refltype);
274 
275 	*type_encoding = mono_type_get_type(value_type);
276 	MonoClass *type_class_raw = mono_class_from_mono_type(value_type);
277 	*type_class = GDMono::get_singleton()->get_class(type_class_raw);
278 }
279 
godot_icall_Dictionary_ToString(Dictionary * ptr)280 MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
281 	return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
282 }
283 
godot_register_collections_icalls()284 void godot_register_collections_icalls() {
285 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor);
286 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor);
287 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At);
288 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", (void *)godot_icall_Array_At_Generic);
289 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt);
290 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count);
291 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add);
292 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear);
293 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains);
294 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo);
295 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", (void *)godot_icall_Array_Duplicate);
296 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf);
297 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert);
298 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
299 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
300 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", (void *)godot_icall_Array_Resize);
301 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo);
302 	mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", (void *)godot_icall_Array_ToString);
303 
304 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor);
305 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor);
306 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue);
307 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", (void *)godot_icall_Dictionary_GetValue_Generic);
308 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue);
309 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys);
310 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values);
311 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count);
312 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add);
313 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear);
314 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains);
315 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey);
316 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", (void *)godot_icall_Dictionary_Duplicate);
317 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey);
318 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove);
319 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
320 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", (void *)godot_icall_Dictionary_TryGetValue_Generic);
321 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", (void *)godot_icall_Dictionary_Generic_GetValueTypeInfo);
322 	mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", (void *)godot_icall_Dictionary_ToString);
323 }
324 
325 #endif // MONO_GLUE_ENABLED
326