Skip to content

Commit 3dbd066

Browse files
committed
Update project to use C# 13 and version 1.1.19-b1; refactor library loading with new event handlers and remove deprecated NativeLibraryLoader.
1 parent 3f7afa5 commit 3dbd066

File tree

4 files changed

+134
-14
lines changed

4 files changed

+134
-14
lines changed

HexaGen.Runtime/EventHandlerList.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
namespace HexaGen.Runtime
2+
{
3+
using System;
4+
using System.Collections;
5+
6+
internal class EventHandlerList<T> : IEnumerable<T> where T : Delegate
7+
{
8+
private readonly List<T> delegates = [];
9+
#if NET9_0_OR_GREATER
10+
private readonly Lock _lock = new();
11+
#else
12+
private readonly object _lock = new();
13+
#endif
14+
15+
public void Add(T value)
16+
{
17+
lock (_lock)
18+
{
19+
delegates.Add(value);
20+
}
21+
}
22+
23+
public void Remove(T value)
24+
{
25+
lock (_lock)
26+
{
27+
delegates.Remove(value);
28+
}
29+
}
30+
31+
public void Invoke<TUserdata>(TUserdata userdata, Func<T, TUserdata, bool> action)
32+
{
33+
foreach (var item in delegates)
34+
{
35+
if (action.Invoke(item, userdata))
36+
{
37+
break;
38+
}
39+
}
40+
}
41+
42+
public IEnumerator<T> GetEnumerator()
43+
{
44+
return delegates.GetEnumerator();
45+
}
46+
47+
IEnumerator IEnumerable.GetEnumerator()
48+
{
49+
return GetEnumerator();
50+
}
51+
}
52+
}

HexaGen.Runtime/HexaGen.Runtime.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
<Nullable>enable</Nullable>
77
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
88

9-
<LangVersion>12</LangVersion>
9+
<LangVersion>13</LangVersion>
1010

1111
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
1212
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
1313
<EnableAotAnalyzer>true</EnableAotAnalyzer>
1414
<IsAotCompatible>true</IsAotCompatible>
1515

1616
<AssemblyVersion>1.1.0</AssemblyVersion>
17-
<PackageVersion>1.1.18</PackageVersion>
17+
<PackageVersion>1.1.19-b1</PackageVersion>
1818
<Description>The C Runtime for all C Wrappers generated with the HexaGen Code Generator.</Description>
1919
<Authors>Juna Meinhold</Authors>
2020
<Copyright>Copyright (c) 2024 Juna Meinhold</Copyright>

HexaGen.Runtime/LibraryLoader.cs

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
namespace HexaGen.Runtime
22
{
33
using System;
4+
using System.Collections;
5+
using System.Diagnostics;
6+
using System.Diagnostics.CodeAnalysis;
47
using System.Reflection;
8+
using System.Runtime.CompilerServices;
59
using System.Runtime.InteropServices;
610

711
#if !NET5_0_OR_GREATER
@@ -30,12 +34,21 @@ public enum TargetPlatform
3034
Any = FreeBSD | Linux | OSX | Windows | Android | IOS | Tizen | ChromeOS | WebAssembly | Solaris | WatchOS | TVO
3135
}
3236

33-
public delegate void ResolvePathHandler(string libraryName, out string? pathToLibrary);
37+
public delegate bool ResolvePathHandler(string libraryName, out string? pathToLibrary);
3438

35-
public delegate void LibraryNameInterceptor(ref string libraryName);
39+
public delegate bool LibraryNameInterceptor(ref string libraryName);
40+
41+
public delegate bool LibraryLoadInterceptor(string libraryName, out nint pointer);
42+
43+
public delegate bool NativeContextInterceptor(string libraryName, out INativeContext? context);
3644

3745
public static class LibraryLoader
3846
{
47+
private static readonly EventHandlerList<ResolvePathHandler> resolvePathHandlers = [];
48+
private static readonly EventHandlerList<LibraryNameInterceptor> libraryNameInterceptors = [];
49+
private static readonly EventHandlerList<LibraryLoadInterceptor> libraryLoadInterceptors = [];
50+
private static readonly EventHandlerList<NativeContextInterceptor> nativeContextInterceptors = [];
51+
3952
public static OSPlatform FreeBSD { get; } = OSPlatform.Create("FREEBSD");
4053

4154
public static OSPlatform Linux { get; } = OSPlatform.Create("LINUX");
@@ -62,9 +75,13 @@ public static class LibraryLoader
6275

6376
public static List<string> CustomLoadFolders { get; } = [];
6477

65-
public static ResolvePathHandler? ResolvePath;
78+
public static event ResolvePathHandler ResolvePath { add => resolvePathHandlers.Add(value); remove => resolvePathHandlers.Remove(value); }
79+
80+
public static event LibraryNameInterceptor InterceptLibraryName { add => libraryNameInterceptors.Add(value); remove => libraryNameInterceptors.Remove(value); }
81+
82+
public static event LibraryLoadInterceptor InterceptLibraryLoad { add => libraryLoadInterceptors.Add(value); remove => libraryLoadInterceptors.Remove(value); }
6683

67-
public static LibraryNameInterceptor? InterceptLibraryName;
84+
public static event NativeContextInterceptor InterceptNativeContext { add => nativeContextInterceptors.Add(value); remove => nativeContextInterceptors.Remove(value); }
6885

6986
public static string GetExtension()
7087
{
@@ -126,11 +143,62 @@ public static string GetExtension()
126143

127144
public delegate string LibraryExtensionCallback();
128145

129-
public static nint LoadLibrary(LibraryNameCallback libraryNameCallback, LibraryExtensionCallback? libraryExtensionCallback)
146+
public static void LoadFromMainModule(string targetLibraryName)
147+
{
148+
LoadFrom(targetLibraryName, Process.GetCurrentProcess().MainModule!.BaseAddress);
149+
}
150+
151+
public static void LoadFrom(string targetLibraryName, nint address)
152+
{
153+
bool Callback(string libraryName, out nint pointer)
154+
{
155+
if (libraryName == targetLibraryName)
156+
{
157+
pointer = address;
158+
return true;
159+
}
160+
161+
pointer = 0;
162+
return false;
163+
}
164+
165+
libraryLoadInterceptors.Add(Callback);
166+
}
167+
168+
public static INativeContext LoadLibraryEx(LibraryNameCallback libraryNameCallback, LibraryExtensionCallback? libraryExtensionCallback)
169+
{
170+
var libraryName = libraryNameCallback();
171+
172+
foreach (var callback in nativeContextInterceptors)
173+
{
174+
if (callback(libraryName, out var context))
175+
{
176+
return context ?? throw new InvalidOperationException("'context' cannot be null when returning true.");
177+
}
178+
}
179+
180+
return new NativeLibraryContext(LoadLibrary(libraryNameCallback, libraryExtensionCallback));
181+
}
182+
183+
public static nint LoadLibrary(LibraryNameCallback libraryNameCallback, LibraryExtensionCallback? libraryExtensionCallback, [CallerMemberName] string? name = "")
130184
{
131185
var libraryName = libraryNameCallback();
132186

133-
InterceptLibraryName?.Invoke(ref libraryName);
187+
foreach (var callback in libraryNameInterceptors)
188+
{
189+
if (callback(ref libraryName))
190+
{
191+
break;
192+
}
193+
}
194+
195+
foreach (var callback in libraryLoadInterceptors)
196+
{
197+
if (callback(libraryName, out nint pointer))
198+
{
199+
return pointer;
200+
}
201+
}
134202

135203
var extension = libraryExtensionCallback != null ? libraryExtensionCallback() : GetExtension();
136204

@@ -143,9 +211,7 @@ public static nint LoadLibrary(LibraryNameCallback libraryNameCallback, LibraryE
143211
var architecture = GetArchitecture();
144212
var libraryPath = GetNativeAssemblyPath(osPlatform, architecture, libraryName);
145213

146-
nint handle;
147-
148-
handle = NativeLibrary.Load(libraryPath);
214+
nint handle = NativeLibrary.Load(libraryPath);
149215

150216
if (handle == IntPtr.Zero)
151217
{
@@ -157,10 +223,12 @@ public static nint LoadLibrary(LibraryNameCallback libraryNameCallback, LibraryE
157223

158224
private static string GetNativeAssemblyPath(string osPlatform, string architecture, string libraryName)
159225
{
160-
if (ResolvePath != null)
226+
foreach (var callback in resolvePathHandlers)
161227
{
162-
ResolvePath.Invoke(libraryName, out var pathToLibrary);
163-
if (pathToLibrary != null) return pathToLibrary;
228+
if (callback(libraryName, out var pathToLibrary))
229+
{
230+
return pathToLibrary ?? throw new InvalidOperationException("'pathToLibrary' cannot be null when returning true.");
231+
}
164232
}
165233

166234
#if ANDROID

0 commit comments

Comments
 (0)