diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation.meta b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation.meta new file mode 100644 index 0000000..ec11650 --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0d01d4c153ea844208e5cb33fd821c18 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NSNumber.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NSNumber.cs new file mode 100644 index 0000000..4bdd251 --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NSNumber.cs @@ -0,0 +1,47 @@ +using System; + +namespace CoreBluetooth.Foundation +{ + public class NSNumber : IDisposable + { + internal SafeNSNumberHandle Handle { get; private set; } + + internal NSNumber(bool value) + { + Handle = NativeMethods.ns_number_new_bool(value); + } + + internal NSNumber(int value) + { + Handle = NativeMethods.ns_number_new_int(value); + } + + internal NSNumber(SafeNSNumberHandle handle) + { + Handle = handle; + } + + internal NSNumber(IntPtr handle) + { + Handle = new SafeNSNumberHandle(handle); + } + + public bool BoolValue() + { + ExceptionUtils.ThrowObjectDisposedExceptionIf(Handle.IsInvalid, this); + return NativeMethods.ns_number_bool_value(Handle); + } + + public int IntValue() + { + ExceptionUtils.ThrowObjectDisposedExceptionIf(Handle.IsInvalid, this); + return NativeMethods.ns_number_int_value(Handle); + } + + public void Dispose() + { + if (Handle != null && !Handle.IsInvalid) + Handle.Dispose(); + } + } +} diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NSNumber.cs.meta b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NSNumber.cs.meta new file mode 100644 index 0000000..90e327a --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NSNumber.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6434df3869a1e4a748239147c582f655 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NativeMethods.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NativeMethods.cs new file mode 100644 index 0000000..56338ac --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NativeMethods.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.InteropServices; + +namespace CoreBluetooth.Foundation +{ + internal static class NativeMethods + { +#if UNITY_IOS && !UNITY_EDITOR + const string DLL_NAME = "__Internal"; +#else + const string DLL_NAME = "libCoreBluetoothForUnity"; +#endif + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + internal static extern void ns_object_release(IntPtr handle); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + internal static extern SafeNSNumberHandle ns_number_new_bool([MarshalAs(UnmanagedType.I1)] bool value); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + internal static extern SafeNSNumberHandle ns_number_new_int(int value); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool ns_number_bool_value(SafeNSNumberHandle handle); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + internal static extern int ns_number_int_value(SafeNSNumberHandle handle); + } +} diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NativeMethods.cs.meta b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NativeMethods.cs.meta new file mode 100644 index 0000000..8d54101 --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NativeMethods.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e30aa1a959f834368a7d5082602bd951 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSNumberHandle.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSNumberHandle.cs new file mode 100644 index 0000000..bfc1588 --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSNumberHandle.cs @@ -0,0 +1,10 @@ +using System; + +namespace CoreBluetooth.Foundation +{ + internal class SafeNSNumberHandle : SafeNSObjectHandle + { + public SafeNSNumberHandle() : base() { } + public SafeNSNumberHandle(IntPtr handle) : base(handle) { } + } +} diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSNumberHandle.cs.meta b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSNumberHandle.cs.meta new file mode 100644 index 0000000..4121d56 --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSNumberHandle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d25d9164f6ce5490cb55386db2e22d9b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSObjectHandle.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSObjectHandle.cs new file mode 100644 index 0000000..4a0473c --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSObjectHandle.cs @@ -0,0 +1,20 @@ +using System; +using Microsoft.Win32.SafeHandles; + +namespace CoreBluetooth.Foundation +{ + public abstract class SafeNSObjectHandle : SafeHandleZeroOrMinusOneIsInvalid + { + protected SafeNSObjectHandle() : base(true) { } + protected SafeNSObjectHandle(IntPtr handle) : base(true) + { + SetHandle(handle); + } + + protected override bool ReleaseHandle() + { + NativeMethods.ns_object_release(handle); + return true; + } + } +} diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSObjectHandle.cs.meta b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSObjectHandle.cs.meta new file mode 100644 index 0000000..49e32d9 --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/SafeNSObjectHandle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f1b5da64673e47abbbace0db0a880c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation.meta b/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation.meta new file mode 100644 index 0000000..d90eaa3 --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea24704c13038490da0c067e709299bd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation/NSNumberTests.cs b/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation/NSNumberTests.cs new file mode 100644 index 0000000..ce044dd --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation/NSNumberTests.cs @@ -0,0 +1,31 @@ +using CoreBluetooth.Foundation; +using NUnit.Framework; + +namespace CoreBluetoothTests.Foundation +{ + public class NSNumberTests + { + [Test] + public void IntValue() + { + using var nsNumber = new NSNumber(2); + Assert.That(nsNumber.Handle, Is.Not.Null); + Assert.That(nsNumber.Handle.IsInvalid, Is.False); + Assert.That(nsNumber.IntValue, Is.EqualTo(2)); + } + + [Test] + public void BoolValue() + { + using var trueNumber = new NSNumber(true); + Assert.That(trueNumber.Handle, Is.Not.Null); + Assert.That(trueNumber.Handle.IsInvalid, Is.False); + Assert.That(trueNumber.BoolValue, Is.True); + + using var falseNumber = new NSNumber(false); + Assert.That(falseNumber.Handle, Is.Not.Null); + Assert.That(falseNumber.Handle.IsInvalid, Is.False); + Assert.That(falseNumber.BoolValue, Is.False); + } + } +} diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation/NSNumberTests.cs.meta b/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation/NSNumberTests.cs.meta new file mode 100644 index 0000000..f668cdb --- /dev/null +++ b/Packages/com.teach310.core-bluetooth-for-unity/Tests/Runtime/Foundation/NSNumberTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 92d8a88cda7bf4b118dfd49aee13c8b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/CoreBluetoothForUnity/Sources/CoreBluetoothForUnity/FoundationForUnity/FoundationForUnity.swift b/Plugins/CoreBluetoothForUnity/Sources/CoreBluetoothForUnity/FoundationForUnity/FoundationForUnity.swift new file mode 100644 index 0000000..d249030 --- /dev/null +++ b/Plugins/CoreBluetoothForUnity/Sources/CoreBluetoothForUnity/FoundationForUnity/FoundationForUnity.swift @@ -0,0 +1,30 @@ +import Foundation + +@_cdecl("ns_object_release") +public func ns_object_release(_ handle: UnsafeRawPointer) { + Unmanaged.fromOpaque(handle).release() +} + +@_cdecl("ns_number_new_bool") +public func ns_number_new_bool(_ value: Bool) -> UnsafeMutableRawPointer { + let instance = NSNumber(value: value) + return Unmanaged.passRetained(instance).toOpaque() +} + +@_cdecl("ns_number_new_int") +public func ns_number_new_int(_ value: Int32) -> UnsafeMutableRawPointer { + let instance = NSNumber(value: value) + return Unmanaged.passRetained(instance).toOpaque() +} + +@_cdecl("ns_number_bool_value") +public func ns_number_bool_value(_ handle: UnsafeRawPointer) -> Bool { + let instance = Unmanaged.fromOpaque(handle).takeUnretainedValue() + return instance.boolValue +} + +@_cdecl("ns_number_int_value") +public func ns_number_int_value(_ handle: UnsafeRawPointer) -> Int32 { + let instance = Unmanaged.fromOpaque(handle).takeUnretainedValue() + return instance.int32Value +}