-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Reflection.Metadata; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace GObject.Internal; | ||
|
||
internal class DemoTypeRegistration | ||
{ | ||
internal static void RegisterTypes() | ||
{ | ||
Register<GObject.Binding>(Binding.GetGType, OSPlatform.Linux, OSPlatform.OSX, OSPlatform.Windows); | ||
Check failure on line 13 in src/Libs/GObject-2.0/Internal/DemoTypeRegistration.cs
|
||
} | ||
|
||
private static void Register<T>(Func<nuint> getType, params OSPlatform[] supportedPlatforms) where T : Constructable | ||
{ | ||
try | ||
{ | ||
if (supportedPlatforms.Any(RuntimeInformation.IsOSPlatform)) | ||
InstanceFactory.AddFactoryForType(getType(), T.Create); | ||
} | ||
catch (System.Exception e) | ||
{ | ||
Debug.WriteLine($"Could not register type '{nameof(T)}': {e.Message}"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace GObject.Internal; | ||
|
||
public interface Constructable | ||
{ | ||
public static abstract object Create(IntPtr handle, bool ownedRef); | ||
Check failure on line 10 in src/Libs/GObject-2.0/Internal/InstanceFactory.cs
|
||
} | ||
|
||
/// <summary> | ||
/// Creates new instances of classes and records | ||
/// </summary> | ||
internal class InstanceFactory | ||
{ | ||
private static readonly Dictionary<Type, Func<IntPtr, bool, object>> Factories = new(); | ||
|
||
public static object Create(IntPtr handle, bool ownedRef) | ||
{ | ||
var gtype = GetTypeFromInstance(handle); | ||
|
||
Debug.Assert( | ||
condition: Functions.TypeName(gtype.Value).ConvertToString() == Functions.TypeNameFromInstance(new TypeInstanceUnownedHandle(handle)).ConvertToString(), | ||
message: "GType name of instance and class do not match" | ||
); | ||
|
||
var factory = GetFactory(gtype); | ||
|
||
return factory(handle, ownedRef); | ||
} | ||
|
||
public static void AddFactoryForType(Type type, Func<IntPtr, bool, object> factory) | ||
{ | ||
Factories[type] = factory; | ||
} | ||
|
||
private static Func<IntPtr, bool, object> GetFactory(Type gtype) | ||
{ | ||
if (Factories.TryGetValue(gtype, out var factory)) | ||
return factory; | ||
|
||
do | ||
{ | ||
var parentType = new Type(Functions.TypeParent(gtype)); | ||
if (parentType.Value is (nuint) BasicType.Invalid or (nuint) BasicType.None) | ||
throw new Exception("Could not retrieve parent type - is the typeid valid?"); | ||
|
||
if (!Factories.TryGetValue(gtype, out var parentFactory)) | ||
continue; | ||
|
||
//Store parent factory for later use | ||
AddFactoryForType(gtype, parentFactory); | ||
|
||
} while(true); | ||
} | ||
|
||
private static unsafe Type GetTypeFromInstance(IntPtr handle) | ||
{ | ||
var gclass = Unsafe.AsRef<TypeInstanceData>((void*) handle).GClass; | ||
var gtype = Unsafe.AsRef<TypeClassData>((void*) gclass).GType; | ||
|
||
if (gtype == 0) | ||
throw new Exception("Could not retrieve type from class struct - is the struct valid?"); | ||
|
||
return new Type(gtype); | ||
} | ||
} |