using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Capnp
{
///
/// ListDeserializer specialization for unmanaged primitive types (including enum).
///
/// List element type
public class ListOfPrimitivesDeserializer: ListDeserializer, IReadOnlyList
where T: unmanaged
{
class ListOfULongAsStructView : IReadOnlyList
{
readonly ListOfPrimitivesDeserializer _lpd;
readonly Func _sel;
public ListOfULongAsStructView(ListOfPrimitivesDeserializer lpd, Func sel)
{
_lpd = lpd;
_sel = sel;
}
public U this[int index]
{
get
{
var state = _lpd.State;
if (index < 0 || index >= _lpd.Count)
throw new IndexOutOfRangeException();
state.Offset += index;
state.Kind = ObjectKind.Struct;
state.StructDataCount = 1;
state.StructPtrCount = 0;
return _sel(state);
}
}
public int Count => _lpd.Count;
IEnumerable Enumerate()
{
var state = _lpd.State;
state.Kind = ObjectKind.Struct;
state.StructDataCount = 1;
state.StructPtrCount = 0;
for (int i = 0; i < Count; i++)
{
yield return _sel(state);
++state.Offset;
}
}
public IEnumerator GetEnumerator()
{
return Enumerate().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
readonly ListKind _kind;
internal ListOfPrimitivesDeserializer(in DeserializerState state, ListKind kind) :
base(state)
{
_kind = kind;
}
///
/// One of ListOfBytes, ListOfShorts, ListOfInts, ListOfLongs.
///
public override ListKind Kind => _kind;
///
/// Retrieves the underlying memory span of this object
///
public ReadOnlySpan Span => MemoryMarshal.Cast(State.CurrentSegment.Slice(State.Offset)).Slice(0, Count);
///
/// Returns the element at given index.
///
/// Element index
/// Element value
/// is out of range.
public T this[int index] => Span[index];
ListOfPrimitivesDeserializer PrimitiveCast() where U: unmanaged
{
if (Marshal.SizeOf() != Marshal.SizeOf())
throw new NotSupportedException("Source and target types have different sizes, cannot cast");
return new ListOfPrimitivesDeserializer(State, Kind);
}
///
/// Always throws because this specialization can never represent a List(bool).
///
public override IReadOnlyList CastBool() => throw new NotSupportedException("Cannot cast to list of bits");
///
/// Attempts to interpret this instance as List(UInt8).
///
/// The desired representation
/// Element size is different from 1 byte.
public override IReadOnlyList CastByte() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(Int8).
///
/// The desired representation
/// Element size is different from 1 byte.
public override IReadOnlyList CastSByte() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(UInt16).
///
/// The desired representation
/// Element size is different from 2 bytes.
public override IReadOnlyList CastUShort() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(Int16).
///
/// The desired representation
/// Element size is different from 2 bytes.
public override IReadOnlyList CastShort() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(UInt32).
///
/// The desired representation
/// Element size is different from 4 bytes.
public override IReadOnlyList CastUInt() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(Int32).
///
/// The desired representation
/// Element size is different from 4 bytes.
public override IReadOnlyList CastInt() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(UInt64).
///
/// The desired representation
/// Element size is different from 8 bytes.
public override IReadOnlyList CastULong() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(Int64).
///
/// The desired representation
/// Element size is different from 8 bytes.
public override IReadOnlyList CastLong() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(Float32).
///
/// The desired representation
/// Element size is different from 4 bytes.
public override IReadOnlyList CastFloat() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(Float64).
///
/// The desired representation
/// Element size is different from 8 bytes.
public override IReadOnlyList CastDouble() => PrimitiveCast();
///
/// Attempts to interpret this instance as List(U) whereby U is a struct, applying a selector function to each element.
///
/// Selector function
/// The desired representation
public override IReadOnlyList Cast(Func cons)
{
switch (Marshal.SizeOf())
{
case 1: return PrimitiveCast().LazyListSelect(x => cons(DeserializerState.MakeValueState(x)));
case 2: return PrimitiveCast().LazyListSelect(x => cons(DeserializerState.MakeValueState(x)));
case 4: return PrimitiveCast().LazyListSelect(x => cons(DeserializerState.MakeValueState(x)));
case 8: return new ListOfULongAsStructView(PrimitiveCast(), cons);
default:
throw new InvalidProgramException("This program path should not be reachable");
}
}
///
/// Attempts to interpret this instance as Text and returns the string representation.
///
/// The decoded string
/// Element size is different from 1 byte.
public override string CastText()
{
var utf8Bytes = PrimitiveCast().Span;
if (utf8Bytes.Length == 0) return string.Empty;
var utf8GytesNoZterm = utf8Bytes.Slice(0, utf8Bytes.Length - 1);
return Encoding.UTF8.GetString(utf8GytesNoZterm.ToArray());
}
IEnumerable Enumerate()
{
for (int i = 0; i < Count; i++)
yield return this[i];
}
///
/// Implements .
///
///
public IEnumerator GetEnumerator()
{
return Enumerate().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}