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