using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; namespace Capnp { /// /// SerializerState specialization for unmanaged primitive types (including enum). /// /// List element type, must be primitive. Static constructor will throw if the type does not work. public class ListOfPrimitivesSerializer : SerializerState, IReadOnlyList where T : unmanaged { static readonly int ElementSize; static ListOfPrimitivesSerializer() { if (typeof(T).IsEnum) { ElementSize = Marshal.SizeOf(Enum.GetUnderlyingType(typeof(T))); } else { ElementSize = Marshal.SizeOf(); } } /// /// The list's data /// public Span Data => MemoryMarshal.Cast(RawData).Slice(0, Count); /// /// Gets or sets the value at given index. /// /// Element index /// Element value public T this[int index] { get { ListSerializerHelper.EnsureAllocated(this); return Data[index]; } set { ListSerializerHelper.EnsureAllocated(this); Data[index] = value; } } /// /// This list's element count. /// public int Count => ListElementCount; /// /// Initializes this list with a specific size. The list can be initialized only once. /// /// List element count /// The list was already initialized /// is negative or greater than 2^29-1 public void Init(int count) { if (IsAllocated) throw new InvalidOperationException("Already initialized"); if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); SetListOfValues((byte)(8 * ElementSize), count); } /// /// Initializes the list with given content. /// /// List content. Can be null in which case the list is simply not initialized. /// The list was already initialized /// More than 2^29-1 items. public void Init(IReadOnlyList? items) { if (items == null) { return; } Init(items.Count); switch (items) { case T[] array: array.CopyTo(Data); break; case ArraySegment segment: segment.AsSpan().CopyTo(Data); break; case ListOfPrimitivesDeserializer deser: deser.Span.CopyTo(Data); break; case ListOfPrimitivesSerializer ser: ser.Data.CopyTo(Data); break; default: for (int i = 0; i < items.Count; i++) { this[i] = items[i]; } break; } } IEnumerable Enumerate() { for (int i = 0; i < Count; i++) yield return Data[i]; } /// /// Implements . /// /// public IEnumerator GetEnumerator() => Enumerate().GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } }