2019-06-12 21:56:55 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace Capnp
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// ListDeserializer specialization for List(Int*), List(UInt*), List(Float*), and List(Enum).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T">List element type</typeparam>
|
|
|
|
|
public class ListOfPrimitivesDeserializer<T>: ListDeserializer, IReadOnlyList<T>
|
|
|
|
|
where T: struct
|
|
|
|
|
{
|
|
|
|
|
class ListOfULongAsStructView<U> : IReadOnlyList<U>
|
|
|
|
|
{
|
|
|
|
|
readonly ListOfPrimitivesDeserializer<ulong> _lpd;
|
|
|
|
|
readonly Func<DeserializerState, U> _sel;
|
|
|
|
|
|
|
|
|
|
public ListOfULongAsStructView(ListOfPrimitivesDeserializer<ulong> lpd, Func<DeserializerState, U> sel)
|
|
|
|
|
{
|
|
|
|
|
_lpd = lpd;
|
|
|
|
|
_sel = sel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public U this[int index]
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
var state = _lpd.State;
|
|
|
|
|
|
|
|
|
|
if (index < 0 || index >= _lpd.Count)
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(index));
|
|
|
|
|
|
|
|
|
|
state.Offset += index;
|
|
|
|
|
state.Kind = ObjectKind.Struct;
|
|
|
|
|
state.StructDataCount = 1;
|
|
|
|
|
state.StructPtrCount = 0;
|
|
|
|
|
|
|
|
|
|
return _sel(state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Count => _lpd.Count;
|
|
|
|
|
|
|
|
|
|
IEnumerable<U> 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<U> GetEnumerator()
|
|
|
|
|
{
|
|
|
|
|
return Enumerate().GetEnumerator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
|
|
|
{
|
|
|
|
|
return GetEnumerator();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly ListKind _kind;
|
|
|
|
|
|
|
|
|
|
internal ListOfPrimitivesDeserializer(ref DeserializerState state, ListKind kind) :
|
|
|
|
|
base(ref state)
|
|
|
|
|
{
|
|
|
|
|
_kind = kind;
|
|
|
|
|
|
|
|
|
|
var binCoder = PrimitiveCoder.Get<T>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// One of ListOfBytes, ListOfShorts, ListOfInts, ListOfLongs.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override ListKind Kind => _kind;
|
|
|
|
|
|
|
|
|
|
ReadOnlySpan<T> Data => MemoryMarshal.Cast<ulong, T>(State.CurrentSegment.Slice(State.Offset)).Slice(0, Count);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the element at given index.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="index">Element index</param>
|
|
|
|
|
/// <returns>Element value</returns>
|
|
|
|
|
/// <exception cref="IndexOutOfRangeException"><paramref name="index"/> is out of range.</exception>
|
|
|
|
|
public T this[int index] => Data[index];
|
|
|
|
|
|
|
|
|
|
ListOfPrimitivesDeserializer<U> PrimitiveCast<U>() where U: struct
|
|
|
|
|
{
|
|
|
|
|
if (Marshal.SizeOf<U>() != Marshal.SizeOf<T>())
|
|
|
|
|
throw new NotSupportedException("Source and target types have different sizes, cannot cast");
|
|
|
|
|
|
|
|
|
|
var stateCopy = State;
|
|
|
|
|
return new ListOfPrimitivesDeserializer<U>(ref stateCopy, Kind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Always throws <see cref="NotSupportedException"/> because this specialization can never represent a List(bool).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override IReadOnlyList<bool> CastBool() => throw new NotSupportedException("Cannot cast to list of bits");
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(UInt8).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 1 byte.</exception>
|
|
|
|
|
public override IReadOnlyList<byte> CastByte() => PrimitiveCast<byte>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(Int8).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 1 byte.</exception>
|
|
|
|
|
public override IReadOnlyList<sbyte> CastSByte() => PrimitiveCast<sbyte>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(UInt16).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 2 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<ushort> CastUShort() => PrimitiveCast<ushort>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(Int16).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 2 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<short> CastShort() => PrimitiveCast<short>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(UInt32).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 4 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<uint> CastUInt() => PrimitiveCast<uint>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(Int32).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 4 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<int> CastInt() => PrimitiveCast<int>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(UInt64).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 8 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<ulong> CastULong() => PrimitiveCast<ulong>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(Int64).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 8 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<long> CastLong() => PrimitiveCast<long>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(Float32).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 4 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<float> CastFloat() => PrimitiveCast<float>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(Float64).
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 8 bytes.</exception>
|
|
|
|
|
public override IReadOnlyList<double> CastDouble() => PrimitiveCast<double>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as List(U) whereby U is a struct, applying a selector function to each element.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="cons">Selector function</param>
|
|
|
|
|
/// <returns>The desired representation</returns>
|
|
|
|
|
public override IReadOnlyList<U> Cast<U>(Func<DeserializerState, U> cons)
|
|
|
|
|
{
|
|
|
|
|
switch (Marshal.SizeOf<T>())
|
|
|
|
|
{
|
|
|
|
|
case 1: return PrimitiveCast<byte>().LazyListSelect(x => cons(DeserializerState.MakeValueState(x)));
|
|
|
|
|
case 2: return PrimitiveCast<ushort>().LazyListSelect(x => cons(DeserializerState.MakeValueState(x)));
|
|
|
|
|
case 4: return PrimitiveCast<uint>().LazyListSelect(x => cons(DeserializerState.MakeValueState(x)));
|
|
|
|
|
case 8: return new ListOfULongAsStructView<U>(PrimitiveCast<ulong>(), cons);
|
|
|
|
|
default:
|
|
|
|
|
throw new InvalidProgramException("This program path should not be reachable");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Attempts to interpret this instance as Text and returns the string representation.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The decoded string</returns>
|
|
|
|
|
/// <exception cref="NotSupportedException">Element size is different from 1 byte.</exception>
|
|
|
|
|
public override string CastText()
|
|
|
|
|
{
|
|
|
|
|
var utf8Bytes = PrimitiveCast<byte>().Data;
|
|
|
|
|
if (utf8Bytes.Length == 0) return string.Empty;
|
|
|
|
|
var utf8GytesNoZterm = utf8Bytes.Slice(0, utf8Bytes.Length - 1);
|
2019-06-22 18:43:30 -04:00
|
|
|
|
return Encoding.UTF8.GetString(utf8GytesNoZterm.ToArray());
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerable<T> Enumerate()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
yield return this[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Implements <see cref="IEnumerable{T}"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
|
|
|
{
|
|
|
|
|
return Enumerate().GetEnumerator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
|
|
|
{
|
|
|
|
|
return GetEnumerator();
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-11 17:56:12 +01:00
|
|
|
|
}
|