diff --git a/Directory.Build.props b/Directory.Build.props index 883eb2d..3da0ef4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@  - 2025.11.25.0 + 2025.12.9.0 enable enable preview diff --git a/TedToolkit.slnx b/TedToolkit.slnx index 59c3970..fceeb9a 100644 --- a/TedToolkit.slnx +++ b/TedToolkit.slnx @@ -74,6 +74,7 @@ + diff --git a/Tests/TedToolkit.Scopes.Tests/ScopesTests.cs b/Tests/TedToolkit.Scopes.Tests/ScopesTests.cs new file mode 100644 index 0000000..4139828 --- /dev/null +++ b/Tests/TedToolkit.Scopes.Tests/ScopesTests.cs @@ -0,0 +1,13 @@ +namespace TedToolkit.Scopes.Tests; + +public class ScopesTests +{ + [Test] + [MatrixDataSource] + public async Task ScopeCreateTest([MatrixRange(-1000, 1000)]int value) + { + using var scope = new TestScope(value); + await Task.Delay(1000); + await Assert.That(TestScope.Current?.Value).IsEqualTo(value); + } +} \ No newline at end of file diff --git a/Tests/TedToolkit.Scopes.Tests/TedToolkit.Scopes.Tests.csproj b/Tests/TedToolkit.Scopes.Tests/TedToolkit.Scopes.Tests.csproj new file mode 100644 index 0000000..e2700a8 --- /dev/null +++ b/Tests/TedToolkit.Scopes.Tests/TedToolkit.Scopes.Tests.csproj @@ -0,0 +1,5 @@ + + + + + diff --git a/Tests/TedToolkit.Scopes.Tests/TestScope.cs b/Tests/TedToolkit.Scopes.Tests/TestScope.cs new file mode 100644 index 0000000..5053328 --- /dev/null +++ b/Tests/TedToolkit.Scopes.Tests/TestScope.cs @@ -0,0 +1,6 @@ +namespace TedToolkit.Scopes.Tests; + +public class TestScope(int value) : ScopeBase +{ + public int Value => value; +} \ No newline at end of file diff --git a/src/libraries/TedToolkit.CppInteropGen/NativeFunctionLoader.cs b/src/libraries/TedToolkit.CppInteropGen/NativeFunctionLoader.cs index f8212fc..61b3bbd 100644 --- a/src/libraries/TedToolkit.CppInteropGen/NativeFunctionLoader.cs +++ b/src/libraries/TedToolkit.CppInteropGen/NativeFunctionLoader.cs @@ -8,42 +8,41 @@ namespace TedToolkit.CppInteropGen; public sealed class NativeFunctionLoader : IDisposable { - private static readonly ConcurrentDictionary Loaders = []; - private readonly ConcurrentDictionary _exportCache = new(StringComparer.Ordinal); - private readonly Lazy _libHandle; - private bool _disposed; + private static readonly ConcurrentDictionary Loaders = []; + private readonly ConcurrentDictionary _exportCache = new(StringComparer.Ordinal); + private readonly IntPtr _libHandle; + private bool _disposed; - private NativeFunctionLoader(string libraryPath) - { - _libHandle = new Lazy(() => - { - var handle = NativeLibrary.Load(libraryPath); - if (handle != IntPtr.Zero) return handle; - throw new InvalidOperationException($"Failed to load native library: {libraryPath}"); - }); - } + private NativeFunctionLoader(string libraryPath) + { + _libHandle = NativeLibrary.Load(libraryPath); + if (_libHandle != IntPtr.Zero) return; + throw new InvalidOperationException($"Failed to load native library: {libraryPath}"); + } - public void Dispose() - { - if (_disposed) return; - _disposed = true; - if (_libHandle.IsValueCreated) NativeLibrary.Free(_libHandle.Value); - } + public void Dispose() + { + if (_disposed) return; + _disposed = true; + NativeLibrary.Free(_libHandle); + } - internal static NativeFunctionLoader GetLoader(string libName) - { - if (string.IsNullOrEmpty(libName)) - throw new ArgumentException("The libName is null or empty.", nameof(libName)); - var loader = Loaders.GetOrAdd(libName, n => new NativeFunctionLoader(n)); - if (!loader._disposed) return loader; - return Loaders[libName] = new NativeFunctionLoader(libName); - } + internal static NativeFunctionLoader GetLoader(string libName) + { + if (string.IsNullOrEmpty(libName)) + throw new ArgumentException("The libName is null or empty.", nameof(libName)); - public IntPtr GetFunctionPointer(string name) - { - if (_disposed) throw new ObjectDisposedException(nameof(NativeFunctionLoader)); - return _exportCache.GetOrAdd(name, n => NativeLibrary.GetExport(_libHandle.Value, n)); - } + return Loaders.AddOrUpdate( + key: libName, + addValueFactory: n => new(n), + updateValueFactory: (n, existingLoader) => existingLoader._disposed ? new(n) : existingLoader); + } + + public IntPtr GetFunctionPointer(string name) + { + if (_disposed) throw new ObjectDisposedException(nameof(NativeFunctionLoader)); + return _exportCache.GetOrAdd(name, n => NativeLibrary.GetExport(_libHandle, n)); + } } #if NETSTANDARD || NETFRAMEWORK