using System; using System.Runtime.InteropServices; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; namespace UnityEngine.XR.ARKit { /// /// Represents the Objective-C type ARCollaborationData. /// /// /// /// This struct mirrors the Objective-C type ARCollaborationData. Because it /// represents a native resource, it must be explicitly disposed when no /// longer needed. /// /// ARCollaborationData can be constructed from a byte array, or from /// . /// /// This struct is not thread-safe, but it may be constructed and disposed on any thread. /// /// public struct ARCollaborationData : IDisposable, IEquatable { /// /// Constructs an ARCollaborationData from a byte array. /// Check after construction to ensure was successfully deserialized. /// /// An array of bytes to convert to . /// Thrown if is null. /// public unsafe ARCollaborationData(byte[] bytes) { if (bytes == null) throw new ArgumentNullException(nameof(bytes)); m_NativePtr = ConstructUnchecked(bytes, 0, bytes.Length); } /// /// Constructs an ARCollaborationData from a byte array. /// Check after construction to ensure was successfully deserialized. /// /// An array of bytes to convert to . /// The offset into the array from which to start constructing . /// The number of bytes in to convert to . /// Thrown if is null. /// Thrown if is outside the range [0..bytes.Length). /// Thrown if is outside the range [0..(bytes.Length - offset)]. /// public unsafe ARCollaborationData(byte[] bytes, int offset, int length) { if (bytes == null) throw new ArgumentNullException(nameof(bytes)); if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), offset, $"'{nameof(offset)}' must be greater than or equal to zero."); if (offset >= bytes.Length) throw new ArgumentOutOfRangeException(nameof(offset), offset, $"'{nameof(offset)}' must be less than the length of the byte array ({bytes.Length})."); if (length <= 0) throw new ArgumentOutOfRangeException(nameof(length), length, $"'{nameof(length)}' must be greater than zero."); if (length > (bytes.Length - offset)) throw new ArgumentOutOfRangeException(nameof(length), length, $"'{nameof(length)}' is greater than the number of available bytes in the buffer ({bytes.Length - offset})"); m_NativePtr = ConstructUnchecked(bytes, offset, length); } /// /// Constructs an ARCollaborationData from a NativeSlice of bytes. /// Check after construction to ensure was successfully deserialized. /// /// An array of bytes to convert to . /// Thrown if does not refer to valid data. /// public unsafe ARCollaborationData(NativeSlice bytes) { void* ptr = bytes.GetUnsafePtr(); if ((ptr == null) || (bytes.Length == 0)) throw new ArgumentException("Invalid NativeSlice", nameof(bytes)); m_NativePtr = ConstructUnchecked(ptr, bytes.Length); } /// /// True if the data is valid. The data may be invalid if this object was constructed /// with an invalid byte array, or if it has been disposed. /// public bool valid => m_NativePtr != IntPtr.Zero; /// /// Gets the priority of the collaboration data. Use this to determine how /// you should send the information to peers in a collaborative session, /// e.g., reliably vs unreliably. /// /// Thrown if is false. public ARCollaborationDataPriority priority { get { ValidateAndThrow(); return UnityARKit_session_getCollaborationDataPriority(m_NativePtr); } } /// /// Dispose the native ARCollaborationData. will be false after disposal. /// It is safe to dispose an invalid or already disposed ARCollaborationData. /// public void Dispose() { UnityARKit_CFRelease(m_NativePtr); m_NativePtr = IntPtr.Zero; } /// /// Copies the bytes representing the serialized to a /// . /// A common use case would be to send these bytes to another device over a network. /// /// A container representing the serialized bytes of this . /// Thrown if is false. public unsafe SerializedARCollaborationData ToSerialized() { ValidateAndThrow(); var nsData = new NSData(UnityARKit_session_serializeCollaborationDataToNSData(m_NativePtr)); return new SerializedARCollaborationData(nsData); } /// /// Generates a hash code suitable for use in HashSet and Dictionary. /// /// A hash of the . public override int GetHashCode() => m_NativePtr.GetHashCode(); /// /// Compares for equality. /// /// An object to compare against. /// true if is an and /// is also true. Otherwise, false. public override bool Equals(object obj) => (obj is ARCollaborationData) && Equals((ARCollaborationData)obj); /// /// Compares for equality. /// /// The other to compare against. /// true if the represents the same object. public bool Equals(ARCollaborationData other) => m_NativePtr == other.m_NativePtr; /// /// Compares and for equality using . /// /// The left-hand-side of the comparison. /// The right-hand-side of the comparison. /// true if compares equal to , false otherwise. public static bool operator ==(ARCollaborationData lhs, ARCollaborationData rhs) => lhs.Equals(rhs); /// /// Compares and for inequality using . /// /// The left-hand-side of the comparison. /// The right-hand-side of the comparison. /// false if compares equal to , true otherwise. public static bool operator !=(ARCollaborationData lhs, ARCollaborationData rhs) => !lhs.Equals(rhs); internal ARCollaborationData(IntPtr data) => m_NativePtr = data; internal ARCollaborationData(NSData data) => m_NativePtr = UnityARKit_session_deserializeCollaborationDataFromNSData(data); void ValidateAndThrow() { if (!valid) throw new InvalidOperationException("ARCollaborationData has already been disposed."); } unsafe static IntPtr ConstructUnchecked(void* bytes, int length) { using (var nsData = NSData.CreateWithBytesNoCopy(bytes, length)) { return UnityARKit_session_deserializeCollaborationDataFromNSData(nsData); } } unsafe static IntPtr ConstructUnchecked(byte[] bytes, int offset, int length) { fixed(void* ptr = &bytes[offset]) { return ConstructUnchecked(ptr, length); } } [DllImport("__Internal")] static extern void UnityARKit_CFRelease(IntPtr ptr); [DllImport("__Internal")] static extern IntPtr UnityARKit_session_deserializeCollaborationDataFromNSData(IntPtr nsData); [DllImport("__Internal")] static extern IntPtr UnityARKit_session_serializeCollaborationDataToNSData(IntPtr collaborationData); [DllImport("__Internal")] static extern ARCollaborationDataPriority UnityARKit_session_getCollaborationDataPriority(IntPtr collaborationData); internal IntPtr m_NativePtr; } }