Merge pull request #26662 from neikeq/csharp-collection-changes
C#: Collections breaking changes and improvements
This commit is contained in:
commit
74719b8748
|
@ -571,7 +571,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
|
|||
|
||||
MonoException *exc = NULL;
|
||||
|
||||
MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, (MonoObject **)&exc);
|
||||
MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, &exc);
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
|
@ -595,7 +595,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
|
|||
MonoString *file_name;
|
||||
int file_line_num;
|
||||
MonoString *method_decl;
|
||||
invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, (MonoObject **)&exc);
|
||||
invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, &exc);
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
|
@ -625,7 +625,7 @@ void CSharpLanguage::frame() {
|
|||
|
||||
if (task_scheduler) {
|
||||
MonoException *exc = NULL;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, (MonoObject **)&exc);
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, &exc);
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
|
@ -2166,7 +2166,8 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
|
|||
CRASH_NOW();
|
||||
}
|
||||
|
||||
Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type);
|
||||
GDMonoMarshal::ExportInfo export_info;
|
||||
Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type, &export_info);
|
||||
|
||||
if (!p_member->has_attribute(CACHED_CLASS(ExportAttribute))) {
|
||||
r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
|
@ -2191,6 +2192,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
|
|||
ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String());
|
||||
return false;
|
||||
} else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) {
|
||||
// TODO: Move to ExportInfo?
|
||||
variant_type = Variant::INT;
|
||||
hint = PROPERTY_HINT_ENUM;
|
||||
|
||||
|
@ -2257,6 +2259,11 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
|
|||
|
||||
hint = PROPERTY_HINT_RESOURCE_TYPE;
|
||||
hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class);
|
||||
} else if (variant_type == Variant::ARRAY && export_info.array.element_type != Variant::NIL) {
|
||||
hint = PROPERTY_HINT_TYPE_STRING;
|
||||
hint_string = itos(export_info.array.element_type) + ":";
|
||||
} else if (variant_type == Variant::DICTIONARY && export_info.dictionary.key_type != Variant::NIL && export_info.dictionary.value_type != Variant::NIL) {
|
||||
// TODO: There is no hint for this yet
|
||||
} else {
|
||||
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
|
||||
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable
|
||||
public class Array : IList, IDisposable
|
||||
{
|
||||
ArraySafeHandle safeHandle;
|
||||
bool disposed = false;
|
||||
|
@ -38,6 +38,14 @@ namespace Godot.Collections
|
|||
safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
|
||||
}
|
||||
|
||||
public Array(IEnumerable collection) : this()
|
||||
{
|
||||
if (collection == null)
|
||||
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
|
||||
|
||||
MarshalUtils.EnumerableToArray(collection, GetPtr());
|
||||
}
|
||||
|
||||
internal Array(ArraySafeHandle handle)
|
||||
{
|
||||
safeHandle = handle;
|
||||
|
@ -56,6 +64,13 @@ namespace Godot.Collections
|
|||
return safeHandle.DangerousGetHandle();
|
||||
}
|
||||
|
||||
public Error Resize(int newSize)
|
||||
{
|
||||
return godot_icall_Array_Resize(GetPtr(), newSize);
|
||||
}
|
||||
|
||||
// IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposed)
|
||||
|
@ -70,62 +85,55 @@ namespace Godot.Collections
|
|||
disposed = true;
|
||||
}
|
||||
|
||||
// IList
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public bool IsFixedSize => false;
|
||||
|
||||
public object this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return godot_icall_Array_At(GetPtr(), index);
|
||||
}
|
||||
set
|
||||
{
|
||||
godot_icall_Array_SetAt(GetPtr(), index, value);
|
||||
}
|
||||
get => godot_icall_Array_At(GetPtr(), index);
|
||||
set => godot_icall_Array_SetAt(GetPtr(), index, value);
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return godot_icall_Array_Count(GetPtr());
|
||||
}
|
||||
}
|
||||
public int Add(object value) => godot_icall_Array_Add(GetPtr(), value);
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value);
|
||||
|
||||
public void Add(object item)
|
||||
{
|
||||
godot_icall_Array_Add(GetPtr(), item);
|
||||
}
|
||||
public void Clear() => godot_icall_Array_Clear(GetPtr());
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
godot_icall_Array_Clear(GetPtr());
|
||||
}
|
||||
public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value);
|
||||
|
||||
public bool Contains(object item)
|
||||
{
|
||||
return godot_icall_Array_Contains(GetPtr(), item);
|
||||
}
|
||||
public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value);
|
||||
|
||||
public void CopyTo(object[] array, int arrayIndex)
|
||||
public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value);
|
||||
|
||||
public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index);
|
||||
|
||||
// ICollection
|
||||
|
||||
public int Count => godot_icall_Array_Count(GetPtr());
|
||||
|
||||
public object SyncRoot => this;
|
||||
|
||||
public bool IsSynchronized => false;
|
||||
|
||||
public void CopyTo(System.Array array, int index)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
|
||||
|
||||
if (arrayIndex < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
|
||||
|
||||
// Internal call may throw ArgumentException
|
||||
godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex);
|
||||
godot_icall_Array_CopyTo(GetPtr(), array, index);
|
||||
}
|
||||
|
||||
public IEnumerator<object> GetEnumerator()
|
||||
// IEnumerable
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
int count = Count;
|
||||
|
||||
|
@ -135,36 +143,6 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public int IndexOf(object item)
|
||||
{
|
||||
return godot_icall_Array_IndexOf(GetPtr(), item);
|
||||
}
|
||||
|
||||
public void Insert(int index, object item)
|
||||
{
|
||||
godot_icall_Array_Insert(GetPtr(), index, item);
|
||||
}
|
||||
|
||||
public bool Remove(object item)
|
||||
{
|
||||
return godot_icall_Array_Remove(GetPtr(), item);
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
godot_icall_Array_RemoveAt(GetPtr(), index);
|
||||
}
|
||||
|
||||
public Error Resize(int newSize)
|
||||
{
|
||||
return godot_icall_Array_Resize(GetPtr(), newSize);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Array_Ctor();
|
||||
|
||||
|
@ -184,7 +162,7 @@ namespace Godot.Collections
|
|||
internal extern static int godot_icall_Array_Count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Add(IntPtr ptr, object item);
|
||||
internal extern static int godot_icall_Array_Add(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Clear(IntPtr ptr);
|
||||
|
@ -193,7 +171,7 @@ namespace Godot.Collections
|
|||
internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex);
|
||||
internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
|
||||
|
@ -231,6 +209,14 @@ namespace Godot.Collections
|
|||
objectArray = new Array();
|
||||
}
|
||||
|
||||
public Array(IEnumerable<T> collection)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
|
||||
|
||||
objectArray = new Array(collection);
|
||||
}
|
||||
|
||||
public Array(Array array)
|
||||
{
|
||||
objectArray = array;
|
||||
|
@ -246,11 +232,23 @@ namespace Godot.Collections
|
|||
objectArray = new Array(handle);
|
||||
}
|
||||
|
||||
internal IntPtr GetPtr()
|
||||
{
|
||||
return objectArray.GetPtr();
|
||||
}
|
||||
|
||||
public static explicit operator Array(Array<T> from)
|
||||
{
|
||||
return from.objectArray;
|
||||
}
|
||||
|
||||
public Error Resize(int newSize)
|
||||
{
|
||||
return objectArray.Resize(newSize);
|
||||
}
|
||||
|
||||
// IList<T>
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
|
@ -263,6 +261,23 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
return objectArray.IndexOf(item);
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
objectArray.Insert(index, item);
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
objectArray.RemoveAt(index);
|
||||
}
|
||||
|
||||
// ICollection<T>
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
|
@ -317,6 +332,13 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
return Array.godot_icall_Array_Remove(GetPtr(), item);
|
||||
}
|
||||
|
||||
// IEnumerable<T>
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
int count = objectArray.Count;
|
||||
|
@ -327,39 +349,9 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
return objectArray.IndexOf(item);
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
objectArray.Insert(index, item);
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
return objectArray.Remove(item);
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
objectArray.RemoveAt(index);
|
||||
}
|
||||
|
||||
public Error Resize(int newSize)
|
||||
{
|
||||
return objectArray.Resize(newSize);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
internal IntPtr GetPtr()
|
||||
{
|
||||
return objectArray.GetPtr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,9 +29,7 @@ namespace Godot.Collections
|
|||
}
|
||||
|
||||
public class Dictionary :
|
||||
IDictionary<object, object>,
|
||||
ICollection<KeyValuePair<object, object>>,
|
||||
IEnumerable<KeyValuePair<object, object>>,
|
||||
IDictionary,
|
||||
IDisposable
|
||||
{
|
||||
DictionarySafeHandle safeHandle;
|
||||
|
@ -42,6 +40,14 @@ namespace Godot.Collections
|
|||
safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
|
||||
}
|
||||
|
||||
public Dictionary(IDictionary dictionary) : this()
|
||||
{
|
||||
if (dictionary == null)
|
||||
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
|
||||
|
||||
MarshalUtils.IDictionaryToDictionary(dictionary, GetPtr());
|
||||
}
|
||||
|
||||
internal Dictionary(DictionarySafeHandle handle)
|
||||
{
|
||||
safeHandle = handle;
|
||||
|
@ -74,19 +80,9 @@ namespace Godot.Collections
|
|||
disposed = true;
|
||||
}
|
||||
|
||||
public object this[object key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return godot_icall_Dictionary_GetValue(GetPtr(), key);
|
||||
}
|
||||
set
|
||||
{
|
||||
godot_icall_Dictionary_SetValue(GetPtr(), key, value);
|
||||
}
|
||||
}
|
||||
// IDictionary
|
||||
|
||||
public ICollection<object> Keys
|
||||
public ICollection Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -95,7 +91,7 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public ICollection<object> Values
|
||||
public ICollection Values
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -104,97 +100,97 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
public bool IsFixedSize => false;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public object this[object key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return godot_icall_Dictionary_Count(GetPtr());
|
||||
}
|
||||
get => godot_icall_Dictionary_GetValue(GetPtr(), key);
|
||||
set => godot_icall_Dictionary_SetValue(GetPtr(), key, value);
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value);
|
||||
|
||||
public void Add(object key, object value)
|
||||
{
|
||||
godot_icall_Dictionary_Add(GetPtr(), key, value);
|
||||
}
|
||||
public void Clear() => godot_icall_Dictionary_Clear(GetPtr());
|
||||
|
||||
public void Add(KeyValuePair<object, object> item)
|
||||
{
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
godot_icall_Dictionary_Clear(GetPtr());
|
||||
}
|
||||
public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this);
|
||||
|
||||
public bool Contains(KeyValuePair<object, object> item)
|
||||
{
|
||||
return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value);
|
||||
}
|
||||
public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key);
|
||||
|
||||
public bool ContainsKey(object key)
|
||||
{
|
||||
return godot_icall_Dictionary_ContainsKey(GetPtr(), key);
|
||||
}
|
||||
// ICollection
|
||||
|
||||
public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
|
||||
public object SyncRoot => this;
|
||||
|
||||
public bool IsSynchronized => false;
|
||||
|
||||
public int Count => godot_icall_Dictionary_Count(GetPtr());
|
||||
|
||||
public void CopyTo(System.Array array, int index)
|
||||
{
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
// TODO Can be done with single internal call
|
||||
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
|
||||
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
|
||||
|
||||
Array keys = (Array)Keys;
|
||||
Array values = (Array)Values;
|
||||
int count = Count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// TODO 2 internal calls, can reduce to 1
|
||||
array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]);
|
||||
arrayIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
|
||||
{
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
Array keys = (Array)Keys;
|
||||
Array values = (Array)Values;
|
||||
int count = Count;
|
||||
if (array.Length < (index + count))
|
||||
throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// TODO 2 internal calls, can reduce to 1
|
||||
yield return new KeyValuePair<object, object>(keys[i], values[i]);
|
||||
array.SetValue(new DictionaryEntry(keys[i], values[i]), index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(object key)
|
||||
{
|
||||
return godot_icall_Dictionary_RemoveKey(GetPtr(), key);
|
||||
}
|
||||
// IEnumerable
|
||||
|
||||
public bool Remove(KeyValuePair<object, object> item)
|
||||
{
|
||||
return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public bool TryGetValue(object key, out object value)
|
||||
private class DictionaryEnumerator : IDictionaryEnumerator
|
||||
{
|
||||
object retValue;
|
||||
bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue);
|
||||
value = found ? retValue : default(object);
|
||||
return found;
|
||||
}
|
||||
Array keys;
|
||||
Array values;
|
||||
int count;
|
||||
int index = -1;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
public DictionaryEnumerator(Dictionary dictionary)
|
||||
{
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
keys = (Array)dictionary.Keys;
|
||||
values = (Array)dictionary.Values;
|
||||
count = dictionary.Count;
|
||||
}
|
||||
|
||||
public object Current => Entry;
|
||||
|
||||
public DictionaryEntry Entry =>
|
||||
// TODO 2 internal calls, can reduce to 1
|
||||
new DictionaryEntry(keys[index], values[index]);
|
||||
|
||||
public object Key => Entry.Key;
|
||||
|
||||
public object Value => Entry.Value;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
index++;
|
||||
return index < count;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
|
@ -250,9 +246,7 @@ namespace Godot.Collections
|
|||
}
|
||||
|
||||
public class Dictionary<TKey, TValue> :
|
||||
IDictionary<TKey, TValue>,
|
||||
ICollection<KeyValuePair<TKey, TValue>>,
|
||||
IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
IDictionary<TKey, TValue>
|
||||
{
|
||||
Dictionary objectDict;
|
||||
|
||||
|
@ -269,6 +263,23 @@ namespace Godot.Collections
|
|||
objectDict = new Dictionary();
|
||||
}
|
||||
|
||||
public Dictionary(IDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
objectDict = new Dictionary();
|
||||
|
||||
if (dictionary == null)
|
||||
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
|
||||
|
||||
// TODO: Can be optimized
|
||||
|
||||
IntPtr godotDictionaryPtr = GetPtr();
|
||||
|
||||
foreach (KeyValuePair<TKey, TValue> entry in dictionary)
|
||||
{
|
||||
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary(Dictionary dictionary)
|
||||
{
|
||||
objectDict = dictionary;
|
||||
|
@ -289,6 +300,13 @@ namespace Godot.Collections
|
|||
return from.objectDict;
|
||||
}
|
||||
|
||||
internal IntPtr GetPtr()
|
||||
{
|
||||
return objectDict.GetPtr();
|
||||
}
|
||||
|
||||
// IDictionary<TKey, TValue>
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
|
@ -319,6 +337,31 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
objectDict.Add(key, value);
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return objectDict.Contains(key);
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
object retValue;
|
||||
bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
|
||||
value = found ? (TValue)retValue : default(TValue);
|
||||
return found;
|
||||
}
|
||||
|
||||
// ICollection<KeyValuePair<TKey, TValue>>
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
|
@ -335,11 +378,6 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
objectDict.Add(key, value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
objectDict.Add(item.Key, item.Value);
|
||||
|
@ -355,18 +393,22 @@ namespace Godot.Collections
|
|||
return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return objectDict.ContainsKey(key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
|
||||
|
||||
if (arrayIndex < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
|
||||
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
Array<TKey> keys = (Array<TKey>)Keys;
|
||||
Array<TValue> values = (Array<TValue>)Values;
|
||||
int count = Count;
|
||||
|
||||
if (array.Length < (arrayIndex + count))
|
||||
throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// TODO 2 internal calls, can reduce to 1
|
||||
|
@ -375,6 +417,13 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ;
|
||||
}
|
||||
|
||||
// IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
|
@ -389,32 +438,9 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
return objectDict.Remove(key);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value));
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
object retValue;
|
||||
bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
|
||||
value = found ? (TValue)retValue : default(TValue);
|
||||
return found;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
internal IntPtr GetPtr()
|
||||
{
|
||||
return objectDict.GetPtr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,68 @@
|
|||
using System;
|
||||
using Godot.Collections;
|
||||
using System.Collections;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
using Array = Godot.Collections.Array;
|
||||
using Dictionary = Godot.Collections.Dictionary;
|
||||
|
||||
static class MarshalUtils
|
||||
{
|
||||
static bool IsArrayGenericType(Type type)
|
||||
static bool TypeIsGenericArray(Type type)
|
||||
{
|
||||
return type.GetGenericTypeDefinition() == typeof(Array<>);
|
||||
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
|
||||
}
|
||||
|
||||
static bool IsDictionaryGenericType(Type type)
|
||||
static bool TypeIsGenericDictionary(Type type)
|
||||
{
|
||||
return type.GetGenericTypeDefinition() == typeof(Dictionary<, >);
|
||||
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
|
||||
}
|
||||
|
||||
static void ArrayGetElementType(Type type, out Type elementType)
|
||||
{
|
||||
elementType = type.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
static void DictionaryGetKeyValueTypes(Type type, out Type keyType, out Type valueType)
|
||||
{
|
||||
var genericArgs = type.GetGenericArguments();
|
||||
|
||||
keyType = genericArgs[0];
|
||||
valueType = genericArgs[1];
|
||||
}
|
||||
|
||||
// TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
|
||||
// TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
|
||||
|
||||
internal static void EnumerableToArray(IEnumerable enumerable, IntPtr godotArrayPtr)
|
||||
{
|
||||
if (enumerable is ICollection collection)
|
||||
{
|
||||
int count = collection.Count;
|
||||
|
||||
object[] tempArray = new object[count];
|
||||
collection.CopyTo(tempArray, 0);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.godot_icall_Array_Add(godotArrayPtr, tempArray[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (object element in enumerable)
|
||||
{
|
||||
Array.godot_icall_Array_Add(godotArrayPtr, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void IDictionaryToDictionary(IDictionary dictionary, IntPtr godotDictionaryPtr)
|
||||
{
|
||||
foreach (DictionaryEntry entry in dictionary)
|
||||
{
|
||||
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
11
modules/mono/glue/Managed/IgnoredFiles/Variant.cs
Normal file
11
modules/mono/glue/Managed/IgnoredFiles/Variant.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
namespace Godot
|
||||
{
|
||||
public static class Variant
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,8 +73,9 @@ int godot_icall_Array_Count(Array *ptr) {
|
|||
return ptr->size();
|
||||
}
|
||||
|
||||
void godot_icall_Array_Add(Array *ptr, MonoObject *item) {
|
||||
int godot_icall_Array_Add(Array *ptr, MonoObject *item) {
|
||||
ptr->append(GDMonoMarshal::mono_object_to_variant(item));
|
||||
return ptr->size();
|
||||
}
|
||||
|
||||
void godot_icall_Array_Clear(Array *ptr) {
|
||||
|
|
|
@ -51,7 +51,7 @@ void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value);
|
|||
|
||||
int godot_icall_Array_Count(Array *ptr);
|
||||
|
||||
void godot_icall_Array_Add(Array *ptr, MonoObject *item);
|
||||
int godot_icall_Array_Add(Array *ptr, MonoObject *item);
|
||||
|
||||
void godot_icall_Array_Clear(Array *ptr);
|
||||
|
||||
|
|
|
@ -55,7 +55,8 @@ String GDMonoClass::get_full_name() const {
|
|||
}
|
||||
|
||||
MonoType *GDMonoClass::get_mono_type() {
|
||||
// Care, you cannot compare MonoType pointers
|
||||
// Careful, you cannot compare two MonoType*.
|
||||
// There is mono_metadata_type_equal, how is this different from comparing two MonoClass*?
|
||||
return get_mono_type(mono_class);
|
||||
}
|
||||
|
||||
|
@ -260,6 +261,11 @@ bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) {
|
|||
return get_fetched_method_unknown_params(p_name) != NULL;
|
||||
}
|
||||
|
||||
bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
|
||||
|
||||
return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
|
||||
}
|
||||
|
||||
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
|
||||
|
||||
MethodKey key = MethodKey(p_name, p_params_count);
|
||||
|
|
|
@ -135,6 +135,8 @@ public:
|
|||
void fetch_attributes();
|
||||
void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
|
||||
|
||||
bool implements_interface(GDMonoClass *p_interface);
|
||||
|
||||
GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
|
||||
GDMonoMethod *get_method(MonoMethod *p_raw_method);
|
||||
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
|
||||
|
|
|
@ -313,6 +313,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
|||
break;
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||
mono_field_set_value(p_object, mono_field, managed);
|
||||
break;
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
||||
mono_field_set_value(p_object, mono_field, managed);
|
||||
break;
|
||||
}
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
|
||||
ERR_FAIL();
|
||||
} break;
|
||||
|
@ -422,8 +434,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
|||
|
||||
MonoException *exc = NULL;
|
||||
|
||||
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_dict) {
|
||||
|
@ -434,8 +446,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
|||
|
||||
exc = NULL;
|
||||
|
||||
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_array) {
|
||||
|
@ -443,6 +455,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
|||
mono_field_set_value(p_object, mono_field, managed);
|
||||
break;
|
||||
}
|
||||
|
||||
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||
mono_field_set_value(p_object, mono_field, managed);
|
||||
break;
|
||||
}
|
||||
|
||||
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
||||
mono_field_set_value(p_object, mono_field, managed);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
|
|
|
@ -35,24 +35,12 @@
|
|||
|
||||
class GDMonoAssembly;
|
||||
class GDMonoClass;
|
||||
class IMonoClassMember;
|
||||
class GDMonoField;
|
||||
class GDMonoProperty;
|
||||
class GDMonoMethod;
|
||||
class GDMonoProperty;
|
||||
|
||||
struct ManagedType {
|
||||
int type_encoding;
|
||||
GDMonoClass *type_class;
|
||||
class IMonoClassMember;
|
||||
|
||||
ManagedType() :
|
||||
type_encoding(0),
|
||||
type_class(NULL) {
|
||||
}
|
||||
|
||||
ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
|
||||
type_encoding(p_type_encoding),
|
||||
type_class(p_type_class) {
|
||||
}
|
||||
};
|
||||
#include "managed_type.h"
|
||||
|
||||
#endif // GD_MONO_HEADER_H
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
namespace GDMonoMarshal {
|
||||
|
||||
Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||
Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info) {
|
||||
switch (p_type.type_encoding) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
return Variant::BOOL;
|
||||
|
@ -156,26 +156,66 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
|||
if (CACHED_CLASS(Array) == type_class) {
|
||||
return Variant::ARRAY;
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
return Variant::DICTIONARY;
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
return Variant::ARRAY;
|
||||
}
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
|
||||
|
||||
MonoException *exc = NULL;
|
||||
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_dict) {
|
||||
if (r_export_info) {
|
||||
MonoReflectionType *key_reftype;
|
||||
MonoReflectionType *value_reftype;
|
||||
|
||||
exc = NULL;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes),
|
||||
reftype, &key_reftype, &value_reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
r_export_info->dictionary.key_type = managed_to_variant_type(ManagedType::from_reftype(key_reftype));
|
||||
r_export_info->dictionary.value_type = managed_to_variant_type(ManagedType::from_reftype(value_reftype));
|
||||
}
|
||||
|
||||
return Variant::DICTIONARY;
|
||||
}
|
||||
|
||||
exc = NULL;
|
||||
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_array) {
|
||||
if (r_export_info) {
|
||||
MonoReflectionType *elem_reftype;
|
||||
|
||||
exc = NULL;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType),
|
||||
reftype, &elem_reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
r_export_info->array.element_type = managed_to_variant_type(ManagedType::from_reftype(elem_reftype));
|
||||
}
|
||||
|
||||
return Variant::ARRAY;
|
||||
}
|
||||
|
||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
return Variant::DICTIONARY;
|
||||
}
|
||||
|
||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
return Variant::ARRAY;
|
||||
}
|
||||
} break;
|
||||
|
@ -453,6 +493,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
|||
if (CACHED_CLASS(Array) == type_class) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
||||
}
|
||||
} break;
|
||||
case MONO_TYPE_OBJECT: {
|
||||
// Variant
|
||||
|
@ -548,8 +596,8 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
|||
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
|
||||
|
||||
MonoException *exc = NULL;
|
||||
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_dict) {
|
||||
|
@ -557,13 +605,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
|||
}
|
||||
|
||||
exc = NULL;
|
||||
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_array) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
|
||||
}
|
||||
|
||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||
}
|
||||
|
||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
||||
}
|
||||
} break;
|
||||
} break;
|
||||
}
|
||||
|
@ -577,15 +633,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
|||
if (!p_obj)
|
||||
return Variant();
|
||||
|
||||
GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
|
||||
ERR_FAIL_COND_V(!tclass, Variant());
|
||||
ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
|
||||
|
||||
MonoType *raw_type = tclass->get_mono_type();
|
||||
|
||||
ManagedType type;
|
||||
|
||||
type.type_encoding = mono_type_get_type(raw_type);
|
||||
type.type_class = tclass;
|
||||
ERR_FAIL_COND_V(!type.type_class, Variant());
|
||||
|
||||
switch (type.type_encoding) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
|
@ -717,17 +767,33 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
|||
|
||||
if (CACHED_CLASS(Array) == type_class) {
|
||||
MonoException *exc = NULL;
|
||||
Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, (MonoObject **)&exc);
|
||||
Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
return ptr ? Variant(*ptr) : Variant();
|
||||
}
|
||||
|
||||
if (CACHED_CLASS(Dictionary) == type_class) {
|
||||
MonoException *exc = NULL;
|
||||
Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, (MonoObject **)&exc);
|
||||
Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
return ptr ? Variant(*ptr) : Variant();
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
Dictionary dict;
|
||||
MonoException *exc = NULL;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
return dict;
|
||||
}
|
||||
|
||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
Array array;
|
||||
MonoException *exc = NULL;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
return array;
|
||||
}
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
|
@ -735,8 +801,8 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
|||
|
||||
MonoException *exc = NULL;
|
||||
|
||||
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
|
||||
MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_dict) {
|
||||
|
@ -748,8 +814,8 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
|||
|
||||
exc = NULL;
|
||||
|
||||
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
|
||||
GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
|
||||
MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
|
||||
if (is_array) {
|
||||
|
@ -758,6 +824,22 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
|
|||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
return *unbox<Array *>(ret);
|
||||
}
|
||||
|
||||
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
||||
Dictionary dict;
|
||||
exc = NULL;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
return dict;
|
||||
}
|
||||
|
||||
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
||||
Array array;
|
||||
exc = NULL;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
|
||||
UNLIKELY_UNHANDLED_EXCEPTION(exc);
|
||||
return array;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define GDMONOMARSHAL_H
|
||||
|
||||
#include "core/variant.h"
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_utils.h"
|
||||
|
||||
|
@ -56,7 +57,25 @@ T unbox(MonoObject *p_obj) {
|
|||
#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
|
||||
#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
|
||||
|
||||
Variant::Type managed_to_variant_type(const ManagedType &p_type);
|
||||
// FIXME: Made this struct in a hurry. It could be done differently.
|
||||
struct ExportInfo {
|
||||
struct ArrayInfo {
|
||||
Variant::Type element_type;
|
||||
|
||||
ArrayInfo() :
|
||||
element_type(Variant::NIL) {}
|
||||
} array;
|
||||
struct DictionaryInfo {
|
||||
Variant::Type key_type;
|
||||
Variant::Type value_type;
|
||||
|
||||
DictionaryInfo() :
|
||||
key_type(Variant::NIL),
|
||||
value_type(Variant::NIL) {}
|
||||
} dictionary;
|
||||
};
|
||||
|
||||
Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info = NULL);
|
||||
|
||||
// String
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ MonoCache mono_cache;
|
|||
#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val)
|
||||
#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val)
|
||||
#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
|
||||
#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val)
|
||||
|
||||
void MonoCache::clear_members() {
|
||||
|
||||
|
@ -81,6 +82,9 @@ void MonoCache::clear_members() {
|
|||
class_String = NULL;
|
||||
class_IntPtr = NULL;
|
||||
|
||||
class_System_Collections_IEnumerable = NULL;
|
||||
class_System_Collections_IDictionary = NULL;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
class_System_Diagnostics_StackTrace = NULL;
|
||||
methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL;
|
||||
|
@ -143,12 +147,17 @@ void MonoCache::clear_members() {
|
|||
methodthunk_GodotObject_Dispose = NULL;
|
||||
methodthunk_Array_GetPtr = NULL;
|
||||
methodthunk_Dictionary_GetPtr = NULL;
|
||||
methodthunk_MarshalUtils_IsArrayGenericType = NULL;
|
||||
methodthunk_MarshalUtils_IsDictionaryGenericType = NULL;
|
||||
methodthunk_SignalAwaiter_SignalCallback = NULL;
|
||||
methodthunk_SignalAwaiter_FailureCallback = NULL;
|
||||
methodthunk_GodotTaskScheduler_Activate = NULL;
|
||||
|
||||
methodthunk_MarshalUtils_TypeIsGenericArray = NULL;
|
||||
methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL;
|
||||
methodthunk_MarshalUtils_ArrayGetElementType = NULL;
|
||||
methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL;
|
||||
methodthunk_MarshalUtils_EnumerableToArray = NULL;
|
||||
methodthunk_MarshalUtils_IDictionaryToDictionary = NULL;
|
||||
|
||||
task_scheduler_handle = Ref<MonoGCHandle>();
|
||||
}
|
||||
|
||||
|
@ -178,6 +187,9 @@ void update_corlib_cache() {
|
|||
CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
|
||||
CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
|
||||
|
||||
CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
|
||||
CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames"));
|
||||
|
@ -242,12 +254,17 @@ void update_godot_api_cache() {
|
|||
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsDictionaryGenericType", 1));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0));
|
||||
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2));
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4));
|
||||
#endif
|
||||
|
@ -712,7 +729,7 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &
|
|||
}
|
||||
|
||||
void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, (MonoObject **)r_exc);
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc);
|
||||
}
|
||||
|
||||
} // namespace GDMonoUtils
|
||||
|
|
|
@ -49,18 +49,21 @@
|
|||
|
||||
namespace GDMonoUtils {
|
||||
|
||||
typedef void (*GodotObject_Dispose)(MonoObject *, MonoObject **);
|
||||
typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
|
||||
typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
|
||||
typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
|
||||
typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
|
||||
typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
|
||||
typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
|
||||
typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
|
||||
typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
|
||||
typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
|
||||
typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
|
||||
typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
|
||||
typedef void (*GodotObject_Dispose)(MonoObject *, MonoException **);
|
||||
typedef Array *(*Array_GetPtr)(MonoObject *, MonoException **);
|
||||
typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoException **);
|
||||
typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoException **);
|
||||
typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoException **);
|
||||
typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoException **);
|
||||
typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoException **);
|
||||
typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoException **);
|
||||
|
||||
typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **);
|
||||
typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **);
|
||||
typedef MonoBoolean (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
|
||||
typedef MonoBoolean (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
|
||||
typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **);
|
||||
typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
|
||||
|
||||
struct MonoCache {
|
||||
|
||||
|
@ -83,6 +86,9 @@ struct MonoCache {
|
|||
GDMonoClass *class_String;
|
||||
GDMonoClass *class_IntPtr;
|
||||
|
||||
GDMonoClass *class_System_Collections_IEnumerable;
|
||||
GDMonoClass *class_System_Collections_IDictionary;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
GDMonoClass *class_System_Diagnostics_StackTrace;
|
||||
StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames;
|
||||
|
@ -146,12 +152,17 @@ struct MonoCache {
|
|||
GodotObject_Dispose methodthunk_GodotObject_Dispose;
|
||||
Array_GetPtr methodthunk_Array_GetPtr;
|
||||
Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
|
||||
IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
|
||||
IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType;
|
||||
SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
|
||||
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
|
||||
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
|
||||
|
||||
TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray;
|
||||
TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary;
|
||||
ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType;
|
||||
DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
|
||||
EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray;
|
||||
IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary;
|
||||
|
||||
Ref<MonoGCHandle> task_scheduler_handle;
|
||||
|
||||
bool corlib_cache_updated;
|
||||
|
@ -255,6 +266,7 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc);
|
|||
#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
|
||||
#define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method)
|
||||
#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method)
|
||||
#define CACHED_PROPERTY(m_class, m_property) (GDMonoUtils::mono_cache.property_##m_class##_##m_property)
|
||||
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
|
||||
|
|
58
modules/mono/mono_gd/managed_type.cpp
Normal file
58
modules/mono/mono_gd/managed_type.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*************************************************************************/
|
||||
/* managed_type.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "managed_type.h"
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_class.h"
|
||||
|
||||
ManagedType ManagedType::from_class(GDMonoClass *p_class) {
|
||||
return ManagedType(mono_type_get_type(p_class->get_mono_type()), p_class);
|
||||
}
|
||||
|
||||
ManagedType ManagedType::from_class(MonoClass *p_mono_class) {
|
||||
GDMonoClass *tclass = GDMono::get_singleton()->get_class(p_mono_class);
|
||||
ERR_FAIL_COND_V(!tclass, ManagedType());
|
||||
|
||||
return ManagedType(mono_type_get_type(tclass->get_mono_type()), tclass);
|
||||
}
|
||||
|
||||
ManagedType ManagedType::from_type(MonoType *p_mono_type) {
|
||||
MonoClass *mono_class = mono_class_from_mono_type(p_mono_type);
|
||||
GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_class);
|
||||
ERR_FAIL_COND_V(!tclass, ManagedType());
|
||||
|
||||
return ManagedType(mono_type_get_type(p_mono_type), tclass);
|
||||
}
|
||||
|
||||
ManagedType ManagedType::from_reftype(MonoReflectionType *p_mono_reftype) {
|
||||
MonoType *mono_type = mono_reflection_type_get_type(p_mono_reftype);
|
||||
return from_type(mono_type);
|
||||
}
|
58
modules/mono/mono_gd/managed_type.h
Normal file
58
modules/mono/mono_gd/managed_type.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*************************************************************************/
|
||||
/* managed_type.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MANAGED_TYPE_H
|
||||
#define MANAGED_TYPE_H
|
||||
|
||||
#include <mono/metadata/object.h>
|
||||
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
struct ManagedType {
|
||||
int type_encoding;
|
||||
GDMonoClass *type_class;
|
||||
|
||||
static ManagedType from_class(GDMonoClass *p_class);
|
||||
static ManagedType from_class(MonoClass *p_mono_class);
|
||||
static ManagedType from_type(MonoType *p_mono_type);
|
||||
static ManagedType from_reftype(MonoReflectionType *p_mono_reftype);
|
||||
|
||||
ManagedType() :
|
||||
type_encoding(0),
|
||||
type_class(NULL) {
|
||||
}
|
||||
|
||||
ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
|
||||
type_encoding(p_type_encoding),
|
||||
type_class(p_type_class) {
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MANAGED_TYPE_H
|
|
@ -100,7 +100,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
|
|||
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, (MonoObject **)&exc);
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, &exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
|
@ -132,7 +132,7 @@ SignalAwaiterHandle::~SignalAwaiterHandle() {
|
|||
if (awaiter) {
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, (MonoObject **)&exc);
|
||||
invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, &exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
|
|
Loading…
Reference in a new issue