using System; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; namespace UnityEngine.XR.ARKit { /// /// Use this to construct an incrementally from serialized bytes. /// /// /// This struct can be useful if you receive data through a stream. If you already have all /// the bytes, use a constructor instead. /// This struct represents a native resource and must be explicitly disposed when no longer needed. /// While this struct is not thread safe, you can construct, Dispose, and Append from any thread. /// public struct ARCollaborationDataBuilder : IDisposable, IEquatable { internal NSMutableData m_NSMutableData; /// /// Whether the has allocated any data. If true, /// this struct must be disposed to avoid leaking native resources. If false, this struct /// either never allocated memory /// (with or ) /// or it has already been d. /// public bool hasData => m_NSMutableData.created; /// /// The number of bytes owned by this struct. /// /// /// /// public int length => m_NSMutableData.created ? m_NSMutableData.length : 0; /// /// Converts the bytes accumulated through calls to to an . /// The caller is responsible for disposing the returned . /// /// A new constructed from the bytes added to this . /// Thrown if is not supported. /// Check for support with . /// Thrown if is false. public ARCollaborationData ToCollaborationData() { if (!ARKitSessionSubsystem.supportsCollaboration) throw new NotSupportedException("ARCollaborationData is not supported by this version of iOS."); if (!hasData) throw new InvalidOperationException("No data to convert to ARCollaborationData."); return new ARCollaborationData(m_NSMutableData); } /// /// Appends bytes of the array to an existing array of bytes. /// /// A buffer containing bytes to append. /// The offset within to start appending bytes to the internal array. /// The number of bytes from to append. Must be less than `.Length` + . /// Thrown if is . /// Thrown if is less than zero. /// Thrown if is less than zero. /// Thrown if is less than zero or greater than the length of . public unsafe void Append(byte[] buffer, int offset, int size) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); if (size < 0) throw new ArgumentOutOfRangeException(nameof(size), size, $"'{nameof(size)}' must be greater than or equal to zero."); if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), offset, $"'{nameof(offset)}' must be greater than or equal to zero."); if (buffer.Length < size + offset) throw new InvalidOperationException($"Reading {size} bytes starting at offset {offset} would write past the end of '{nameof(buffer)}' (buffer length = {buffer.Length})."); fixed (byte* ptr = &buffer[offset]) { AppendUnchecked(ptr, size); } } /// /// Appends all bytes of the array to an existing array of bytes. /// /// A buffer containing bytes to append. /// Thrown if is . public unsafe void Append(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); fixed (byte* ptr = buffer) { AppendUnchecked(ptr, buffer.Length); } } /// /// Appends to an existing array of bytes. /// /// An array of bytes to append to the existing data. /// Thrown if does not reference valid data. public unsafe void Append(NativeSlice bytes) { void* ptr = bytes.GetUnsafePtr(); if (ptr == null) throw new ArgumentException("Invalid NativeSlice", nameof(bytes)); AppendUnchecked(ptr, bytes.Length); } /// /// Releases the native resource. /// public void Dispose() => m_NSMutableData.Dispose(); /// /// Appends data to the underlying `NSMutableData` array. /// /// A pointer to an array of bytes to append to the existing data. /// The number of bytes pointed to by . unsafe void AppendUnchecked(void* bytes, int size) { if (m_NSMutableData.created) { m_NSMutableData.AppendBytes(bytes, size); } else { m_NSMutableData = new NSMutableData(bytes, size); } } /// /// Computes a hash code suitable for use in a Dictionary or HashSet. /// /// The hash code for this instance. public override int GetHashCode() => m_NSMutableData.GetHashCode(); /// /// Compares for equality. /// /// The object to compare for equality. /// if is of type `ARCollaborationDataBuilder` and /// compares equal to this instance with . /// Otherwise, returns . public override bool Equals(object obj) => (obj is ARCollaborationDataBuilder) && Equals((ARCollaborationDataBuilder)obj); /// /// Compares for equality. /// /// The to compare against. /// if all fields of this instance compare equal to . /// Otherwise, returns . public bool Equals(ARCollaborationDataBuilder other) => m_NSMutableData.Equals(other.m_NSMutableData); /// /// Compares for equality. Equivalent to . /// /// The left-hand side of the comparison. /// The right-hand side of the comparison. /// if all fields of the instances are equal. Otherwise, returns . public static bool operator ==(ARCollaborationDataBuilder lhs, ARCollaborationDataBuilder rhs) => lhs.Equals(rhs); /// /// Compares for inequality. Equivalent to !. /// /// The left-hand side of the comparison. /// The right-hand side of the comparison. /// if any of the fields of the instances are not equal. Otherwise, returns . public static bool operator !=(ARCollaborationDataBuilder lhs, ARCollaborationDataBuilder rhs) => !lhs.Equals(rhs); } }