/// <summary>Static helpers for registering trait implementations</summary>
public static class {{ trait_pascal }}Registry {
private static readonly ConcurrentDictionary<string, {{ trait_pascal }}Bridge> _bridges =
new ConcurrentDictionary<string, {{ trait_pascal }}Bridge>();
/// <summary>Register a {{ trait_pascal }} implementation and return its native handle</summary>
public static IntPtr Register{{ trait_pascal }}(I{{ trait_pascal }} impl) {
if (impl == null)
throw new ArgumentNullException(nameof(impl));
var bridge = new {{ trait_pascal }}Bridge(impl);
var userData = bridge._bridgeId;
var name = {% if has_super_trait %}impl.Name{% else %}"bridge_" + Guid.NewGuid().ToString(){% endif %};
lock ({{ trait_pascal }}Bridge._registryLock) {
{{ trait_pascal }}Bridge._bridgeRegistry[userData] = bridge;
}
return userData;
}
/// <summary>Register a {{ trait_pascal }} implementation and return its native handle</summary>
{% if has_super_trait %}
public static IntPtr Register(I{{ trait_pascal }} impl) {
if (impl == null)
throw new ArgumentNullException(nameof(impl));
var name = impl.Name;
{% else %}
public static IntPtr Register(I{{ trait_pascal }} impl, string name) {
if (impl == null)
throw new ArgumentNullException(nameof(impl));
{% endif %}
var bridge = new {{ trait_pascal }}Bridge(impl);
try {
var userData = bridge._bridgeId;
var vtablePtr = bridge._vtable;
// Register bridge in the static registry using its unique ID.
// This keeps the bridge alive while Rust holds the ID (userData).
lock ({{ trait_pascal }}Bridge._registryLock) {
{{ trait_pascal }}Bridge._bridgeRegistry[userData] = bridge;
}
var result = NativeMethods.Register{{ trait_pascal }}(name, vtablePtr, userData, out var outError);
if (result != 0) {
lock ({{ trait_pascal }}Bridge._registryLock) {
{{ trait_pascal }}Bridge._bridgeRegistry.Remove(userData);
}
bridge.Dispose();
var errorMsg = global::System.Runtime.InteropServices.Marshal.PtrToStringUTF8(outError) ?? "Unknown error";
global::System.Runtime.InteropServices.Marshal.FreeCoTaskMem(outError);
throw new InvalidOperationException($"Failed to register {name}: {errorMsg}");
}
return userData;
} catch {
lock ({{ trait_pascal }}Bridge._registryLock) {
{{ trait_pascal }}Bridge._bridgeRegistry.Remove(bridge._bridgeId);
}
bridge.Dispose();
throw;
}
}
{% if has_unregister %}
/// <summary>Unregister a {{ trait_pascal }} implementation</summary>
public static void Unregister(string name) {
if (string.IsNullOrEmpty(name))
throw new ArgumentException("Name cannot be empty", nameof(name));
var result = NativeMethods.Unregister{{ trait_pascal }}(name, out var outError);
if (result != 0) {
var errorMsg = global::System.Runtime.InteropServices.Marshal.PtrToStringUTF8(outError) ?? "Unknown error";
global::System.Runtime.InteropServices.Marshal.FreeCoTaskMem(outError);
throw new InvalidOperationException($"Failed to unregister {name}: {errorMsg}");
}
if (_bridges.TryRemove(name, out var bridge)) {
bridge.Dispose();
}
}
{% endif %}
{% if has_clear %}
/// <summary>Clear all registered {{ trait_pascal }} implementations</summary>
public static void Clear() {
var result = NativeMethods.Clear{{ trait_pascal }}(out var outError);
if (result != 0) {
var errorMsg = global::System.Runtime.InteropServices.Marshal.PtrToStringUTF8(outError) ?? "Unknown error";
global::System.Runtime.InteropServices.Marshal.FreeCoTaskMem(outError);
throw new InvalidOperationException($"Failed to clear {{ trait_pascal }} registry: {errorMsg}");
}
_bridges.Clear();
}
{% endif %}
}