mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-10-30 15:41:35 +00:00
Pull Stream
This commit is contained in:
@@ -381,7 +381,7 @@ public static class Codec
|
||||
ComposeInternal(object valueOrSource, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
if (valueOrSource == null)
|
||||
return new TDU(TDUIdentifier.Null);
|
||||
return new TDU(TDUIdentifier.Null, null, 0);
|
||||
|
||||
var type = valueOrSource.GetType();
|
||||
|
||||
@@ -408,7 +408,7 @@ public static class Codec
|
||||
valueOrSource = ((IUserType)valueOrSource).Get();
|
||||
|
||||
if (valueOrSource == null)
|
||||
return new TDU(TDUIdentifier.Null);
|
||||
return new TDU(TDUIdentifier.Null, null, 0);
|
||||
|
||||
|
||||
type = valueOrSource.GetType();
|
||||
@@ -484,7 +484,7 @@ public static class Codec
|
||||
|
||||
}
|
||||
|
||||
return new TDU(TDUIdentifier.Null);
|
||||
return new TDU(TDUIdentifier.Null, null, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,15 @@ using System.Reflection;
|
||||
using Esiur.Data;
|
||||
using Esiur.Core;
|
||||
using Esiur.Resource;
|
||||
using System.Collections;
|
||||
using Esiur.Data.GVWIE;
|
||||
|
||||
namespace Esiur.Data;
|
||||
|
||||
public static class DC // Data Converter
|
||||
{
|
||||
|
||||
|
||||
public static object CastConvert(object value, Type destinationType)
|
||||
{
|
||||
if (value == null)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Esiur.Core;
|
||||
using Esiur.Data;
|
||||
using Esiur.Data.GVWIE;
|
||||
using Esiur.Misc;
|
||||
using Esiur.Net.IIP;
|
||||
using Esiur.Resource;
|
||||
@@ -742,8 +743,8 @@ public static class DataDeserializer
|
||||
{
|
||||
// get key type
|
||||
|
||||
var (keyCs, keyRepType) = RepresentationType.Parse(tdu.Metadata, 0);
|
||||
var (valueCs, valueRepType) = RepresentationType.Parse(tdu.Metadata, keyCs);
|
||||
var (keyCs, keyRepType) = TRU.Parse(tdu.Metadata, 0);
|
||||
var (valueCs, valueRepType) = TRU.Parse(tdu.Metadata, keyCs);
|
||||
|
||||
var wh = connection.Instance.Warehouse;
|
||||
|
||||
@@ -792,8 +793,8 @@ public static class DataDeserializer
|
||||
{
|
||||
// get key type
|
||||
|
||||
var (keyCs, keyRepType) = RepresentationType.Parse(tdu.Metadata, 0);
|
||||
var (valueCs, valueRepType) = RepresentationType.Parse(tdu.Metadata, keyCs);
|
||||
var (keyCs, keyRepType) = TRU.Parse(tdu.Metadata, 0);
|
||||
var (valueCs, valueRepType) = TRU.Parse(tdu.Metadata, keyCs);
|
||||
|
||||
var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType(keyRepType.GetRuntimeType(warehouse), valueRepType.GetRuntimeType(warehouse)));
|
||||
|
||||
@@ -838,7 +839,7 @@ public static class DataDeserializer
|
||||
uint mtOffset = 1;
|
||||
for (var i = 0; i < tupleSize; i++)
|
||||
{
|
||||
var (cs, rep) = RepresentationType.Parse(tdu.Metadata, mtOffset);
|
||||
var (cs, rep) = TRU.Parse(tdu.Metadata, mtOffset);
|
||||
types.Add(rep.GetRuntimeType(connection.Instance.Warehouse));
|
||||
mtOffset += cs;
|
||||
}
|
||||
@@ -913,7 +914,7 @@ public static class DataDeserializer
|
||||
uint mtOffset = 1;
|
||||
for (var i = 0; i < tupleSize; i++)
|
||||
{
|
||||
var (cs, rep) = RepresentationType.Parse(tdu.Metadata, mtOffset);
|
||||
var (cs, rep) = TRU.Parse(tdu.Metadata, mtOffset);
|
||||
types.Add(rep.GetRuntimeType(warehouse));
|
||||
mtOffset += cs;
|
||||
}
|
||||
@@ -975,111 +976,152 @@ public static class DataDeserializer
|
||||
|
||||
public static AsyncReply TypedListParserAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence)
|
||||
{
|
||||
var rt = new AsyncBag<object>();
|
||||
|
||||
// get the type
|
||||
var (hdrCs, rep) = RepresentationType.Parse(tdu.Metadata, 0);
|
||||
var (hdrCs, rep) = TRU.Parse(tdu.Metadata, 0);
|
||||
|
||||
|
||||
var runtimeType = rep.GetRuntimeType(connection.Instance.Warehouse);
|
||||
|
||||
rt.ArrayType = runtimeType;
|
||||
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
var offset = tdu.Offset;
|
||||
var length = tdu.ContentLength;
|
||||
var ends = offset + (uint)length;
|
||||
|
||||
while (length > 0)
|
||||
switch (rep.Identifier)
|
||||
{
|
||||
case TRUIdentifier.Int32:
|
||||
return new AsyncReply(GroupInt32Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength)));
|
||||
case TRUIdentifier.Int64:
|
||||
return new AsyncReply(GroupInt64Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength)));
|
||||
case TRUIdentifier.Int16:
|
||||
return new AsyncReply(GroupInt16Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength)));
|
||||
case TRUIdentifier.UInt32:
|
||||
return new AsyncReply(GroupUInt32Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength)));
|
||||
case TRUIdentifier.UInt64:
|
||||
return new AsyncReply(GroupUInt64Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength)));
|
||||
case TRUIdentifier.UInt16:
|
||||
return new AsyncReply(GroupUInt16Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength)));
|
||||
default:
|
||||
|
||||
current = ParsedTDU.Parse(tdu.Data, offset, ends);
|
||||
var rt = new AsyncBag<object>();
|
||||
|
||||
if (current.Class == TDUClass.Invalid)
|
||||
throw new Exception("Unknown type.");
|
||||
var runtimeType = rep.GetRuntimeType(connection.Instance.Warehouse);
|
||||
|
||||
rt.ArrayType = runtimeType;
|
||||
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
var offset = tdu.Offset;
|
||||
var length = tdu.ContentLength;
|
||||
var ends = offset + (uint)length;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
|
||||
current = ParsedTDU.Parse(tdu.Data, offset, ends);
|
||||
|
||||
if (current.Class == TDUClass.Invalid)
|
||||
throw new Exception("Unknown type.");
|
||||
|
||||
|
||||
if (current.Identifier == TDUIdentifier.TypeContinuation)
|
||||
{
|
||||
current.Class = previous.Value.Class;
|
||||
current.Identifier = previous.Value.Identifier;
|
||||
current.Metadata = previous.Value.Metadata;
|
||||
}
|
||||
if (current.Identifier == TDUIdentifier.TypeContinuation)
|
||||
{
|
||||
current.Class = previous.Value.Class;
|
||||
current.Identifier = previous.Value.Identifier;
|
||||
current.Metadata = previous.Value.Metadata;
|
||||
}
|
||||
|
||||
var (cs, reply) = Codec.ParseAsync(tdu.Data, offset, connection, requestSequence);
|
||||
var (cs, reply) = Codec.ParseAsync(tdu.Data, offset, connection, requestSequence);
|
||||
|
||||
rt.Add(reply);
|
||||
rt.Add(reply);
|
||||
|
||||
if (cs > 0)
|
||||
{
|
||||
offset += (uint)cs;
|
||||
length -= (uint)cs;
|
||||
}
|
||||
else
|
||||
throw new Exception("Error while parsing structured data");
|
||||
if (cs > 0)
|
||||
{
|
||||
offset += (uint)cs;
|
||||
length -= (uint)cs;
|
||||
}
|
||||
else
|
||||
throw new Exception("Error while parsing structured data");
|
||||
|
||||
}
|
||||
|
||||
rt.Seal();
|
||||
return rt;
|
||||
}
|
||||
|
||||
rt.Seal();
|
||||
return rt;
|
||||
}
|
||||
|
||||
public static object TypedListParser(ParsedTDU tdu, Warehouse warehouse)
|
||||
{
|
||||
|
||||
// get the type
|
||||
var (hdrCs, rep) = RepresentationType.Parse(tdu.Metadata, 0);
|
||||
var (hdrCs, rep) = TRU.Parse(tdu.Metadata, 0);
|
||||
|
||||
//offset += hdrCs;
|
||||
//length -= hdrCs;
|
||||
|
||||
var runtimeType = rep.GetRuntimeType(warehouse);
|
||||
|
||||
var list = new List<object>();
|
||||
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
var offset = tdu.Offset;
|
||||
var length = tdu.ContentLength;
|
||||
var ends = offset + (uint)length;
|
||||
|
||||
while (length > 0)
|
||||
switch (rep.Identifier)
|
||||
{
|
||||
current = ParsedTDU.Parse(tdu.Data, offset, ends);
|
||||
|
||||
if (current.Class == TDUClass.Invalid)
|
||||
throw new Exception("Unknown type.");
|
||||
case TRUIdentifier.Int32:
|
||||
return GroupInt32Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength));
|
||||
case TRUIdentifier.Int64:
|
||||
return GroupInt64Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength));
|
||||
case TRUIdentifier.Int16:
|
||||
return GroupInt16Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength));
|
||||
case TRUIdentifier.UInt32:
|
||||
return GroupUInt32Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength));
|
||||
case TRUIdentifier.UInt64:
|
||||
return GroupUInt64Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength));
|
||||
case TRUIdentifier.UInt16:
|
||||
return GroupUInt16Codec.Decode(tdu.Data.AsSpan(
|
||||
(int)tdu.Offset, (int)tdu.ContentLength));
|
||||
default:
|
||||
|
||||
|
||||
if (current.Identifier == TDUIdentifier.TypeContinuation)
|
||||
{
|
||||
current.Class = previous.Value.Class;
|
||||
current.Identifier = previous.Value.Identifier;
|
||||
current.Metadata = previous.Value.Metadata;
|
||||
}
|
||||
var list = new List<object>();
|
||||
|
||||
var (cs, reply) = Codec.ParseSync(current, warehouse);
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
list.Add(reply);
|
||||
var offset = tdu.Offset;
|
||||
var length = tdu.ContentLength;
|
||||
var ends = offset + (uint)length;
|
||||
|
||||
if (cs > 0)
|
||||
{
|
||||
offset += (uint)cs;
|
||||
length -= (uint)cs;
|
||||
previous = current;
|
||||
}
|
||||
else
|
||||
throw new Exception("Error while parsing structured data");
|
||||
while (length > 0)
|
||||
{
|
||||
current = ParsedTDU.Parse(tdu.Data, offset, ends);
|
||||
|
||||
if (current.Class == TDUClass.Invalid)
|
||||
throw new Exception("Unknown type.");
|
||||
|
||||
|
||||
if (current.Identifier == TDUIdentifier.TypeContinuation)
|
||||
{
|
||||
current.Class = previous.Value.Class;
|
||||
current.Identifier = previous.Value.Identifier;
|
||||
current.Metadata = previous.Value.Metadata;
|
||||
}
|
||||
|
||||
var (cs, reply) = Codec.ParseSync(current, warehouse);
|
||||
|
||||
list.Add(reply);
|
||||
|
||||
if (cs > 0)
|
||||
{
|
||||
offset += (uint)cs;
|
||||
length -= (uint)cs;
|
||||
previous = current;
|
||||
}
|
||||
else
|
||||
throw new Exception("Error while parsing structured data");
|
||||
|
||||
}
|
||||
|
||||
var runtimeType = rep.GetRuntimeType(warehouse);
|
||||
var rt = Array.CreateInstance(runtimeType, list.Count);
|
||||
Array.Copy(list.ToArray(), rt, rt.Length);
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
var rt = Array.CreateInstance(runtimeType, list.Count);
|
||||
Array.Copy(list.ToArray(), rt, rt.Length);
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
public static AsyncBag<PropertyValue> PropertyValueArrayParserAsync(byte[] data, uint offset, uint length, DistributedConnection connection, uint[] requestSequence)//, bool ageIncluded = true)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Esiur.Core;
|
||||
using Esiur.Data.GVWIE;
|
||||
using Esiur.Net.IIP;
|
||||
using Esiur.Resource;
|
||||
using Esiur.Resource.Template;
|
||||
@@ -112,7 +113,7 @@ public static class DataSerializer
|
||||
}
|
||||
|
||||
|
||||
public static unsafe TDU Float32Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
public static unsafe TDU Float32Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
float v = (float)value;
|
||||
|
||||
@@ -404,6 +405,7 @@ public static class DataSerializer
|
||||
if (ct == null)
|
||||
return new TDU(TDUIdentifier.Null, null, 0);
|
||||
|
||||
return Codec.ComposeInternal(intVal, warehouse, connection);
|
||||
|
||||
return new TDU(TDUIdentifier.TypedEnum,
|
||||
new byte[] { ct.Index }, 1, template.ClassId.Data);
|
||||
@@ -442,18 +444,18 @@ public static class DataSerializer
|
||||
{
|
||||
if ((bool)value)
|
||||
{
|
||||
return new TDU(TDUIdentifier.True);
|
||||
return new TDU(TDUIdentifier.True, null, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TDU(TDUIdentifier.True);
|
||||
return new TDU(TDUIdentifier.True, null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static TDU NotModifiedComposer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
return new TDU(TDUIdentifier.NotModified);
|
||||
return new TDU(TDUIdentifier.NotModified, null, 0);
|
||||
}
|
||||
|
||||
public static TDU RawDataComposerFromArray(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
@@ -492,16 +494,85 @@ public static class DataSerializer
|
||||
|
||||
public static TDU TypedListComposer(IEnumerable value, Type type, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var composed = ArrayComposer((IEnumerable)value, warehouse, connection);
|
||||
byte[] composed;
|
||||
|
||||
if (value == null)
|
||||
return new TDU(TDUIdentifier.Null, new byte[0], 0);
|
||||
|
||||
var tru = TRU.FromType(type);
|
||||
|
||||
if (type == typeof(int))
|
||||
{
|
||||
composed = GroupInt32Codec.Encode((IList<int>)value);
|
||||
}
|
||||
else if (type == typeof(long))
|
||||
{
|
||||
composed = GroupInt64Codec.Encode((IList<long>)value);
|
||||
}
|
||||
else if (type == typeof(short))
|
||||
{
|
||||
composed = GroupInt16Codec.Encode((IList<short>)value);
|
||||
}
|
||||
else if (type == typeof(uint))
|
||||
{
|
||||
composed = GroupUInt32Codec.Encode((IList<uint>)value);
|
||||
}
|
||||
else if (type == typeof(ulong))
|
||||
{
|
||||
composed = GroupUInt64Codec.Encode((IList<ulong>)value);
|
||||
}
|
||||
else if (type == typeof(ushort))
|
||||
{
|
||||
composed = GroupUInt16Codec.Encode((IList<ushort>)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var rt = new List<byte>();
|
||||
|
||||
TDU? previous = null;
|
||||
|
||||
foreach (var i in value)
|
||||
{
|
||||
var tdu = Codec.ComposeInternal(i, warehouse, connection);
|
||||
|
||||
var currentTru = TRU.FromType(i.GetType());
|
||||
|
||||
if (tru.Match(currentTru))
|
||||
{
|
||||
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
||||
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
||||
|
||||
var ntd = new TDU(TDUIdentifier.TypeOfTarget, d, (ulong)d.Length);
|
||||
rt.AddRange(ntd.Composed);
|
||||
}
|
||||
else
|
||||
|
||||
if (previous != null && tdu.MatchType(previous.Value))
|
||||
{
|
||||
var d = tdu.Composed.Clip(tdu.ContentOffset,
|
||||
(uint)tdu.Composed.Length - tdu.ContentOffset);
|
||||
|
||||
var ntd = new TDU(TDUIdentifier.TypeContinuation, d, (ulong)d.Length);
|
||||
rt.AddRange(ntd.Composed);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt.AddRange(tdu.Composed);
|
||||
}
|
||||
|
||||
previous = tdu;
|
||||
}
|
||||
|
||||
composed = rt.ToArray();
|
||||
|
||||
}
|
||||
|
||||
if (composed == null)
|
||||
return new TDU(TDUIdentifier.Null, new byte[0], 0);
|
||||
|
||||
var metadata = RepresentationType.FromType(type).Compose();
|
||||
var metadata = tru.Compose();
|
||||
|
||||
|
||||
return new TDU(TDUIdentifier.TypedList, composed,
|
||||
(uint)composed.Length, metadata);
|
||||
return new TDU(TDUIdentifier.TypedList, composed, (uint)composed.Length, metadata);
|
||||
}
|
||||
|
||||
//public static byte[] PropertyValueComposer(PropertyValue propertyValue, DistributedConnection connection)//, bool includeAge = true)
|
||||
@@ -539,8 +610,8 @@ public static class DataSerializer
|
||||
if (value == null)
|
||||
return new TDU(TDUIdentifier.Null, new byte[0], 0);
|
||||
|
||||
var kt = RepresentationType.FromType(keyType).Compose();
|
||||
var vt = RepresentationType.FromType(valueType).Compose();
|
||||
var kt = TRU.FromType(keyType).Compose();
|
||||
var vt = TRU.FromType(valueType).Compose();
|
||||
|
||||
var rt = new List<byte>();
|
||||
|
||||
@@ -558,8 +629,8 @@ public static class DataSerializer
|
||||
if (value == null)
|
||||
return new TDU(TDUIdentifier.Null, null, 0);
|
||||
|
||||
var kt = RepresentationType.FromType(keyType).Compose();
|
||||
var vt = RepresentationType.FromType(valueType).Compose();
|
||||
var kt = TRU.FromType(keyType).Compose();
|
||||
var vt = TRU.FromType(valueType).Compose();
|
||||
|
||||
var rt = new List<byte>();
|
||||
|
||||
@@ -583,7 +654,7 @@ public static class DataSerializer
|
||||
DC.Combine(kt, 0, (uint)kt.Length, vt, 0, (uint)vt.Length));
|
||||
}
|
||||
|
||||
public static byte[] ArrayComposer(IEnumerable value, Warehouse warehouse, DistributedConnection connection)
|
||||
public static byte[] DynamicArrayComposer(IEnumerable value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
@@ -727,14 +798,29 @@ public static class DataSerializer
|
||||
foreach (var pt in template.Properties)
|
||||
{
|
||||
var propValue = pt.PropertyInfo.GetValue(record, null);
|
||||
var rr = Codec.Compose(propValue, warehouse, connection);
|
||||
rt.AddRange(rr);
|
||||
|
||||
if (propValue == null)
|
||||
return new TDU(TDUIdentifier.Null, null, 0);
|
||||
var tru = TRU.FromType(propValue.GetType());
|
||||
var tdu = Codec.ComposeInternal(propValue, warehouse, connection);
|
||||
|
||||
|
||||
if (pt.ValueType.Identifier == TRUIdentifier.TypedRecord && pt.ValueType.Match(tru))
|
||||
{
|
||||
// strip metadata
|
||||
var len = (uint)tdu.Composed.Length - tdu.ContentOffset;
|
||||
tdu = new TDU(TDUIdentifier.TypeOfTarget,
|
||||
tdu.Composed.Clip(tdu.ContentOffset, len), len);
|
||||
}
|
||||
|
||||
rt.AddRange(tdu.Composed);
|
||||
}
|
||||
|
||||
return new TDU(TDUIdentifier.Record, rt.ToArray(),
|
||||
(uint)rt.Count,
|
||||
template.ClassId.Data);
|
||||
}
|
||||
|
||||
public static byte[] HistoryComposer(KeyList<PropertyTemplate, PropertyValue[]> history, Warehouse warehouse,
|
||||
DistributedConnection connection, bool prependLength = false)
|
||||
{
|
||||
@@ -758,7 +844,7 @@ public static class DataSerializer
|
||||
|
||||
var fields = value.GetType().GetFields();
|
||||
var list = fields.Select(x => x.GetValue(value)).ToArray();
|
||||
var types = fields.Select(x => RepresentationType.FromType(x.FieldType).Compose()).ToArray();
|
||||
var types = fields.Select(x => TRU.FromType(x.FieldType).Compose()).ToArray();
|
||||
|
||||
|
||||
var metadata = new List<byte>();
|
||||
|
||||
137
Esiur/Data/GVWIE/GroupInt16Codec.cs
Normal file
137
Esiur/Data/GVWIE/GroupInt16Codec.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Esiur.Data.GVWIE;
|
||||
|
||||
public static class GroupInt16Codec
|
||||
{
|
||||
// ----------------- Encoder -----------------
|
||||
public static byte[] Encode(IList<short> values)
|
||||
{
|
||||
var dst = new List<byte>(values.Count); // close lower bound
|
||||
int i = 0;
|
||||
|
||||
while (i < values.Count)
|
||||
{
|
||||
ushort zz = ZigZag16(values[i]);
|
||||
|
||||
// Fast path: single byte with 7-bit ZigZag
|
||||
if (zz <= 0x7Fu)
|
||||
{
|
||||
dst.Add((byte)zz); // MSB=0 implicitly
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group path: up to 64 items sharing width (1 or 2 bytes)
|
||||
int start = i;
|
||||
int count = 1;
|
||||
int width = (zz <= 0xFFu) ? 1 : 2;
|
||||
|
||||
while (count < 64 && (i + count) < values.Count)
|
||||
{
|
||||
ushort z2 = ZigZag16(values[i + count]);
|
||||
int w2 = (z2 <= 0xFFu) ? 1 : 2;
|
||||
if (w2 > width) width = w2; // widen as needed
|
||||
count++;
|
||||
}
|
||||
|
||||
// Header: 1 | (count-1)[6 bits] | (width-1)[1 bit]
|
||||
byte header = 0x80;
|
||||
header |= (byte)(((count - 1) & 0x3F) << 1);
|
||||
header |= (byte)((width - 1) & 0x01);
|
||||
dst.Add(header);
|
||||
|
||||
// Payload: count ZigZag magnitudes, LE, 'width' bytes each
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
ushort z = ZigZag16(values[start + k]);
|
||||
WriteLE(dst, z, width);
|
||||
}
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
||||
return dst.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Decoder -----------------
|
||||
public static short[] Decode(ReadOnlySpan<byte> src)
|
||||
{
|
||||
var result = new List<short>();
|
||||
int pos = 0;
|
||||
|
||||
while (pos < src.Length)
|
||||
{
|
||||
byte h = src[pos++];
|
||||
|
||||
if ((h & 0x80) == 0)
|
||||
{
|
||||
// Fast path: 7-bit ZigZag
|
||||
ushort zz7 = (ushort)(h & 0x7F);
|
||||
result.Add(UnZigZag16(zz7));
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = ((h >> 1) & 0x3F) + 1; // 1..64
|
||||
int width = (h & 0x01) + 1; // 1..2
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
uint raw = ReadLE(src, ref pos, width);
|
||||
if (width > 2 && (raw >> 16) != 0)
|
||||
throw new OverflowException("Decoded ZigZag value exceeds 16-bit range.");
|
||||
|
||||
ushort u = (ushort)raw;
|
||||
short val = UnZigZag16(u);
|
||||
result.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Helpers -----------------
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ushort ZigZag16(short v)
|
||||
{
|
||||
// (v << 1) ^ (v >> 15), result as unsigned 16-bit
|
||||
return (ushort)(((uint)(ushort)v << 1) ^ (uint)((int)v >> 15));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static short UnZigZag16(ushort u)
|
||||
{
|
||||
// (u >> 1) ^ -(u & 1), narrowed to 16-bit signed
|
||||
return (short)((u >> 1) ^ (ushort)-(short)(u & 1));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void WriteLE(List<byte> dst, ushort value, int width)
|
||||
{
|
||||
// width is 1 or 2
|
||||
dst.Add((byte)(value & 0xFF));
|
||||
if (width == 2) dst.Add((byte)(value >> 8));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
|
||||
{
|
||||
if ((uint)(pos + width) > (uint)src.Length)
|
||||
throw new ArgumentException("Buffer underflow while reading group payload.");
|
||||
|
||||
uint v = src[pos++];
|
||||
if (width == 2)
|
||||
{
|
||||
v |= (uint)src[pos++] << 8;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
129
Esiur/Data/GVWIE/GroupInt32Codec.cs
Normal file
129
Esiur/Data/GVWIE/GroupInt32Codec.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Collections;
|
||||
|
||||
namespace Esiur.Data.GVWIE;
|
||||
|
||||
public static class GroupInt32Codec
|
||||
{
|
||||
// ----------------- Encoder -----------------
|
||||
public static byte[] Encode(IList<int> values)
|
||||
{
|
||||
//var values = value as int[];
|
||||
|
||||
var dst = new List<byte>(values.Count * 2);
|
||||
int i = 0;
|
||||
|
||||
while (i < values.Count)
|
||||
{
|
||||
uint zz = ZigZag32(values[i]);
|
||||
|
||||
// Fast path: single byte (MSB=0) when zigzag fits in 7 bits
|
||||
if (zz <= 0x7Fu)
|
||||
{
|
||||
dst.Add((byte)zz);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group: up to 32 items sharing a common width (1..4 bytes)
|
||||
int start = i;
|
||||
int count = 1;
|
||||
int width = WidthFromZigZag(zz);
|
||||
|
||||
while (count < 32 && (i + count) < values.Count)
|
||||
{
|
||||
uint z2 = ZigZag32(values[i + count]);
|
||||
int w2 = WidthFromZigZag(z2);
|
||||
width = Math.Max(width, w2); // widen as needed
|
||||
count++;
|
||||
}
|
||||
|
||||
// Header: 1 | (count-1)[5 bits] | (width-1)[2 bits]
|
||||
byte header = 0x80;
|
||||
header |= (byte)(((count - 1) & 0x1F) << 2);
|
||||
header |= (byte)((width - 1) & 0x03);
|
||||
dst.Add(header);
|
||||
|
||||
// Payload: 'count' zigzag values, LE, 'width' bytes each
|
||||
for (int k = 0; k < count; k++)
|
||||
WriteLE(dst, ZigZag32(values[start + k]), width);
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
||||
return dst.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Decoder -----------------
|
||||
public static int[] Decode(ReadOnlySpan<byte> src)
|
||||
{
|
||||
var result = new List<int>();
|
||||
int pos = 0;
|
||||
|
||||
while (pos < src.Length)
|
||||
{
|
||||
byte h = src[pos++];
|
||||
|
||||
if ((h & 0x80) == 0)
|
||||
{
|
||||
// Fast path: 7-bit ZigZag in low bits
|
||||
uint zz7 = (uint)(h & 0x7F);
|
||||
result.Add(UnZigZag32(zz7));
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = ((h >> 2) & 0x1F) + 1; // 1..32
|
||||
int width = (h & 0x03) + 1; // 1..4
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
uint raw = (uint)ReadLE(src, ref pos, width);
|
||||
int val = UnZigZag32(raw);
|
||||
result.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Helpers -----------------
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint ZigZag32(int v) => (uint)((v << 1) ^ (v >> 31));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int UnZigZag32(uint u) => (int)((u >> 1) ^ (uint)-(int)(u & 1));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int WidthFromZigZag(uint z)
|
||||
{
|
||||
if (z <= 0xFFu) return 1;
|
||||
if (z <= 0xFFFFu) return 2;
|
||||
if (z <= 0xFFFFFFu) return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void WriteLE(List<byte> dst, uint value, int width)
|
||||
{
|
||||
for (int i = 0; i < width; i++)
|
||||
dst.Add((byte)((value >> (8 * i)) & 0xFF));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
|
||||
{
|
||||
if ((uint)(pos + width) > (uint)src.Length)
|
||||
throw new ArgumentException("Buffer underflow while reading group payload.");
|
||||
|
||||
ulong v = 0;
|
||||
for (int i = 0; i < width; i++)
|
||||
v |= (ulong)src[pos++] << (8 * i);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
135
Esiur/Data/GVWIE/GroupInt64Codec.cs
Normal file
135
Esiur/Data/GVWIE/GroupInt64Codec.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Esiur.Data.GVWIE;
|
||||
|
||||
public static class GroupInt64Codec
|
||||
{
|
||||
// ----------------- Encoder -----------------
|
||||
public static byte[] Encode(IList<long> values)
|
||||
{
|
||||
var dst = new List<byte>(values.Count * 2);
|
||||
int i = 0;
|
||||
|
||||
while (i < values.Count)
|
||||
{
|
||||
ulong zz = ZigZag64(values[i]);
|
||||
|
||||
// Fast path: 1 byte when ZigZag fits in 7 bits
|
||||
if (zz <= 0x7Ful)
|
||||
{
|
||||
dst.Add((byte)zz); // MSB = 0 implicitly
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group path: up to 16 items sharing a common width (1..8 bytes)
|
||||
int start = i;
|
||||
int count = 1;
|
||||
int width = WidthFromZigZag(zz);
|
||||
|
||||
while (count < 16 && (i + count) < values.Count)
|
||||
{
|
||||
ulong z2 = ZigZag64(values[i + count]);
|
||||
int w2 = WidthFromZigZag(z2);
|
||||
width = Math.Max(width, w2); // widen as needed
|
||||
count++;
|
||||
}
|
||||
|
||||
// Header: 1 | (count-1)[4 bits] | (width-1)[3 bits]
|
||||
byte header = 0x80;
|
||||
header |= (byte)(((count - 1) & 0x0F) << 3);
|
||||
header |= (byte)((width - 1) & 0x07);
|
||||
dst.Add(header);
|
||||
|
||||
// Payload: 'count' ZigZag values, LE, 'width' bytes each
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
ulong z = ZigZag64(values[start + k]);
|
||||
WriteLE(dst, z, width);
|
||||
}
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
||||
return dst.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Decoder -----------------
|
||||
public static long[] Decode(ReadOnlySpan<byte> src)
|
||||
{
|
||||
var result = new List<long>();
|
||||
int pos = 0;
|
||||
|
||||
while (pos < src.Length)
|
||||
{
|
||||
byte h = src[pos++];
|
||||
|
||||
if ((h & 0x80) == 0)
|
||||
{
|
||||
// Fast path: 7-bit ZigZag
|
||||
ulong zz7 = (ulong)(h & 0x7F);
|
||||
result.Add(UnZigZag64(zz7));
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = ((h >> 3) & 0x0F) + 1; // 1..16
|
||||
int width = (h & 0x07) + 1; // 1..8
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
ulong raw = ReadLE(src, ref pos, width);
|
||||
long val = UnZigZag64(raw);
|
||||
result.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Helpers -----------------
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ZigZag64(long v) => (ulong)((v << 1) ^ (v >> 63));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static long UnZigZag64(ulong u) => (long)((u >> 1) ^ (ulong)-(long)(u & 1));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int WidthFromZigZag(ulong z)
|
||||
{
|
||||
if (z <= 0xFFUL) return 1;
|
||||
if (z <= 0xFFFFUL) return 2;
|
||||
if (z <= 0xFFFFFFUL) return 3;
|
||||
if (z <= 0xFFFFFFFFUL) return 4;
|
||||
if (z <= 0xFFFFFFFFFFUL) return 5;
|
||||
if (z <= 0xFFFFFFFFFFFFUL) return 6;
|
||||
if (z <= 0xFFFFFFFFFFFFFFUL) return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void WriteLE(List<byte> dst, ulong value, int width)
|
||||
{
|
||||
for (int i = 0; i < width; i++)
|
||||
dst.Add((byte)((value >> (8 * i)) & 0xFF));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
|
||||
{
|
||||
if ((uint)(pos + width) > (uint)src.Length)
|
||||
throw new ArgumentException("Buffer underflow while reading group payload.");
|
||||
|
||||
ulong v = 0;
|
||||
for (int i = 0; i < width; i++)
|
||||
v |= (ulong)src[pos++] << (8 * i);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
121
Esiur/Data/GVWIE/GroupUInt16Codec.cs
Normal file
121
Esiur/Data/GVWIE/GroupUInt16Codec.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Esiur.Data.GVWIE;
|
||||
|
||||
|
||||
public static class GroupUInt16Codec
|
||||
{
|
||||
// ----------------- Encoder -----------------
|
||||
public static byte[] Encode(IList<ushort> values)
|
||||
{
|
||||
if (values is null) throw new ArgumentNullException(nameof(values));
|
||||
|
||||
var dst = new List<byte>(values.Count * 2);
|
||||
int i = 0;
|
||||
|
||||
while (i < values.Count)
|
||||
{
|
||||
ushort v = values[i];
|
||||
|
||||
// Fast path: single byte for 0..127
|
||||
if (v <= 0x7F)
|
||||
{
|
||||
dst.Add((byte)v); // MSB=0 implicitly
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group path: up to 16 items sharing a common width (1..2 bytes for uint16)
|
||||
int start = i;
|
||||
int count = 1;
|
||||
int width = WidthFromUnsigned(v);
|
||||
|
||||
while (count < 16 && (i + count) < values.Count)
|
||||
{
|
||||
ushort v2 = values[i + count];
|
||||
int w2 = WidthFromUnsigned(v2);
|
||||
if (w2 > width) width = w2; // widen group if needed
|
||||
count++;
|
||||
}
|
||||
|
||||
// Header: 1 | (count-1)[4b] | (width-1)[3b]
|
||||
byte header = 0x80;
|
||||
header |= (byte)(((count - 1) & 0xF) << 3);
|
||||
header |= (byte)((width - 1) & 0x7);
|
||||
dst.Add(header);
|
||||
|
||||
// Payload
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
WriteLE(dst, values[start + k], width);
|
||||
}
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
||||
return dst.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Decoder -----------------
|
||||
public static ushort[] Decode(ReadOnlySpan<byte> src)
|
||||
{
|
||||
var result = new List<ushort>();
|
||||
int pos = 0;
|
||||
|
||||
while (pos < src.Length)
|
||||
{
|
||||
byte h = src[pos++];
|
||||
|
||||
if ((h & 0x80) == 0)
|
||||
{
|
||||
// Fast path byte (0..127)
|
||||
result.Add(h);
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = ((h >> 3) & 0xF) + 1; // 1..16
|
||||
int width = (h & 0x7) + 1; // 1..8 (expect 1..2)
|
||||
|
||||
if (width > 2)
|
||||
throw new NotSupportedException($"Width {width} bytes exceeds uint16 capacity.");
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
uint val = (uint)ReadLE(src, ref pos, width);
|
||||
if (val > 0xFFFFu)
|
||||
throw new OverflowException("Decoded value exceeds UInt16 range.");
|
||||
result.Add((ushort)val);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Helpers -----------------
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int WidthFromUnsigned(ushort v) => (v <= 0xFF) ? 1 : 2;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void WriteLE(List<byte> dst, ushort value, int width)
|
||||
{
|
||||
// width is 1 or 2
|
||||
dst.Add((byte)(value & 0xFF));
|
||||
if (width == 2) dst.Add((byte)(value >> 8));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
|
||||
{
|
||||
if (pos + width > src.Length)
|
||||
throw new ArgumentException("Buffer underflow while reading payload.");
|
||||
|
||||
ulong v = src[pos++]; // first byte (LSB)
|
||||
if (width == 2) v |= (ulong)src[pos++] << 8;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
125
Esiur/Data/GVWIE/GroupUInt32Codec.cs
Normal file
125
Esiur/Data/GVWIE/GroupUInt32Codec.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Esiur.Data.GVWIE;
|
||||
|
||||
public static class GroupUInt32Codec
|
||||
{
|
||||
// ----------------- Encoder -----------------
|
||||
public static byte[] Encode(IList<uint> values)
|
||||
{
|
||||
if (values is null) throw new ArgumentNullException(nameof(values));
|
||||
|
||||
var dst = new List<byte>(values.Count * 2);
|
||||
int i = 0;
|
||||
|
||||
while (i < values.Count)
|
||||
{
|
||||
uint v = values[i];
|
||||
|
||||
// Fast path: single byte for 0..127
|
||||
if (v <= 0x7Fu)
|
||||
{
|
||||
dst.Add((byte)v); // MSB=0 implicitly
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group path: up to 16 items sharing a common width (1..4 bytes for uint32)
|
||||
int start = i;
|
||||
int count = 1;
|
||||
int width = WidthFromUnsigned(v);
|
||||
|
||||
while (count < 16 && (i + count) < values.Count)
|
||||
{
|
||||
uint v2 = values[i + count];
|
||||
int w2 = WidthFromUnsigned(v2);
|
||||
if (w2 > width) width = w2;
|
||||
count++;
|
||||
}
|
||||
|
||||
// Header: 1 | (count-1)[4b] | (width-1)[3b]
|
||||
byte header = 0x80;
|
||||
header |= (byte)(((count - 1) & 0xF) << 3);
|
||||
header |= (byte)((width - 1) & 0x7);
|
||||
dst.Add(header);
|
||||
|
||||
// Payload
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
WriteLE(dst, values[start + k], width);
|
||||
}
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
||||
return dst.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Decoder -----------------
|
||||
public static uint[] Decode(ReadOnlySpan<byte> src)
|
||||
{
|
||||
var result = new List<uint>();
|
||||
int pos = 0;
|
||||
|
||||
while (pos < src.Length)
|
||||
{
|
||||
byte h = src[pos++];
|
||||
|
||||
if ((h & 0x80) == 0)
|
||||
{
|
||||
// Fast path byte (0..127)
|
||||
result.Add(h);
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = ((h >> 3) & 0xF) + 1; // 1..16
|
||||
int width = (h & 0x7) + 1; // 1..8 (we expect 1..4)
|
||||
|
||||
if (width > 4)
|
||||
throw new NotSupportedException($"Width {width} bytes exceeds uint32 capacity.");
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
uint val = (uint)ReadLE(src, ref pos, width);
|
||||
result.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Helpers -----------------
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int WidthFromUnsigned(uint v)
|
||||
{
|
||||
if (v <= 0xFFu) return 1;
|
||||
if (v <= 0xFFFFu) return 2;
|
||||
if (v <= 0xFFFFFFu) return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void WriteLE(List<byte> dst, uint value, int width)
|
||||
{
|
||||
for (int i = 0; i < width; i++)
|
||||
dst.Add((byte)((value >> (8 * i)) & 0xFF));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
|
||||
{
|
||||
if (pos + width > src.Length)
|
||||
throw new ArgumentException("Buffer underflow while reading payload.");
|
||||
|
||||
ulong v = 0;
|
||||
for (int i = 0; i < width; i++)
|
||||
v |= (ulong)src[pos++] << (8 * i);
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
132
Esiur/Data/GVWIE/GroupUInt64Codec.cs
Normal file
132
Esiur/Data/GVWIE/GroupUInt64Codec.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Esiur.Data.GVWIE;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
public static class GroupUInt64Codec
|
||||
{
|
||||
// ----------------- Encoder -----------------
|
||||
public static byte[] Encode(IList<ulong> values)
|
||||
{
|
||||
if (values is null) throw new ArgumentNullException(nameof(values));
|
||||
|
||||
var dst = new List<byte>(values.Count * 2);
|
||||
int i = 0;
|
||||
|
||||
while (i < values.Count)
|
||||
{
|
||||
ulong v = values[i];
|
||||
|
||||
// Fast path: single byte for 0..127
|
||||
if (v <= 0x7FUL)
|
||||
{
|
||||
dst.Add((byte)v); // MSB = 0 implicitly
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group path: up to 16 items sharing max width (1..8 bytes)
|
||||
int start = i;
|
||||
int count = 1;
|
||||
int width = WidthFromUnsigned(v);
|
||||
|
||||
while (count < 16 && (i + count) < values.Count)
|
||||
{
|
||||
ulong v2 = values[i + count];
|
||||
int w2 = WidthFromUnsigned(v2);
|
||||
if (w2 > width) width = w2;
|
||||
count++;
|
||||
}
|
||||
|
||||
// Header: 1 | (count-1)[4b] | (width-1)[3b]
|
||||
byte header = 0x80;
|
||||
header |= (byte)(((count - 1) & 0xF) << 3);
|
||||
header |= (byte)((width - 1) & 0x7);
|
||||
dst.Add(header);
|
||||
|
||||
// Payload
|
||||
for (int k = 0; k < count; k++)
|
||||
WriteLE(dst, values[start + k], width);
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
||||
return dst.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Decoder -----------------
|
||||
public static ulong[] Decode(ReadOnlySpan<byte> src)
|
||||
{
|
||||
var result = new List<ulong>();
|
||||
int pos = 0;
|
||||
|
||||
while (pos < src.Length)
|
||||
{
|
||||
byte h = src[pos++];
|
||||
|
||||
if ((h & 0x80) == 0)
|
||||
{
|
||||
// Fast path byte (0..127)
|
||||
result.Add(h);
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = ((h >> 3) & 0xF) + 1; // 1..16
|
||||
int width = (h & 0x7) + 1; // 1..8
|
||||
|
||||
if (width < 1 || width > 8)
|
||||
throw new NotSupportedException($"Invalid width {width} in header.");
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
ulong val = ReadLE(src, ref pos, width);
|
||||
result.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
// ----------------- Helpers -----------------
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int WidthFromUnsigned(ulong v)
|
||||
{
|
||||
if (v <= 0xFFUL) return 1;
|
||||
if (v <= 0xFFFFUL) return 2;
|
||||
if (v <= 0xFFFFFFUL) return 3;
|
||||
if (v <= 0xFFFFFFFFUL) return 4;
|
||||
if (v <= 0xFFFFFFFFFFUL) return 5;
|
||||
if (v <= 0xFFFFFFFFFFFFUL) return 6;
|
||||
if (v <= 0xFFFFFFFFFFFFFFUL) return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void WriteLE(List<byte> dst, ulong value, int width)
|
||||
{
|
||||
for (int i = 0; i < width; i++)
|
||||
dst.Add((byte)((value >> (8 * i)) & 0xFF));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ReadLE(ReadOnlySpan<byte> src, ref int pos, int width)
|
||||
{
|
||||
if (pos + width > src.Length)
|
||||
throw new ArgumentException("Buffer underflow while reading payload.");
|
||||
|
||||
ulong v = 0;
|
||||
for (int i = 0; i < width; i++)
|
||||
v |= (ulong)src[pos++] << (8 * i);
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
@@ -1,536 +0,0 @@
|
||||
using Esiur.Core;
|
||||
using Esiur.Net.IIP;
|
||||
using Esiur.Resource;
|
||||
using Esiur.Resource.Template;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Esiur.Data
|
||||
{
|
||||
public enum RepresentationTypeIdentifier
|
||||
{
|
||||
Void = 0x0,
|
||||
Dynamic = 0x1,
|
||||
Bool = 0x2,
|
||||
UInt8,
|
||||
Int8,
|
||||
Char,
|
||||
UInt16,
|
||||
Int16,
|
||||
UInt32,
|
||||
Int32,
|
||||
Float32,
|
||||
UInt64,
|
||||
Int64,
|
||||
Float64,
|
||||
DateTime,
|
||||
UInt128,
|
||||
Int128,
|
||||
Decimal,
|
||||
String,
|
||||
RawData,
|
||||
Resource,
|
||||
Record,
|
||||
List,
|
||||
Map,
|
||||
Enum = 0x44,
|
||||
TypedResource = 0x45, // Followed by UUID
|
||||
TypedRecord = 0x46, // Followed by UUID
|
||||
TypedList = 0x48, // Followed by element type
|
||||
Tuple2 = 0x50, // Followed by element type
|
||||
TypedMap = 0x51, // Followed by key type and value type
|
||||
Tuple3 = 0x58,
|
||||
Tuple4 = 0x60,
|
||||
Tuple5 = 0x68,
|
||||
Tuple6 = 0x70,
|
||||
Tuple7 = 0x78
|
||||
}
|
||||
|
||||
public class RepresentationType
|
||||
{
|
||||
|
||||
static RepresentationTypeIdentifier[] refTypes = new RepresentationTypeIdentifier[]
|
||||
{
|
||||
RepresentationTypeIdentifier.Dynamic,
|
||||
RepresentationTypeIdentifier.RawData,
|
||||
RepresentationTypeIdentifier.String,
|
||||
RepresentationTypeIdentifier.Resource,
|
||||
RepresentationTypeIdentifier.Record,
|
||||
RepresentationTypeIdentifier.Map,
|
||||
RepresentationTypeIdentifier.List,
|
||||
RepresentationTypeIdentifier.TypedList,
|
||||
RepresentationTypeIdentifier.TypedMap,
|
||||
RepresentationTypeIdentifier.Tuple2,
|
||||
RepresentationTypeIdentifier.Tuple3,
|
||||
RepresentationTypeIdentifier.Tuple4,
|
||||
RepresentationTypeIdentifier.Tuple5,
|
||||
RepresentationTypeIdentifier.Tuple6,
|
||||
RepresentationTypeIdentifier.Tuple7,
|
||||
RepresentationTypeIdentifier.TypedRecord,
|
||||
RepresentationTypeIdentifier.TypedResource
|
||||
};
|
||||
|
||||
static Map<TDUIdentifier, RepresentationTypeIdentifier> typesMap = new Map<TDUIdentifier, RepresentationTypeIdentifier>()
|
||||
{
|
||||
[TDUIdentifier.UInt8] = RepresentationTypeIdentifier.UInt8,
|
||||
[TDUIdentifier.Int8] = RepresentationTypeIdentifier.Int8,
|
||||
[TDUIdentifier.UInt16] = RepresentationTypeIdentifier.UInt16,
|
||||
[TDUIdentifier.Int16] = RepresentationTypeIdentifier.Int16,
|
||||
[TDUIdentifier.UInt32] = RepresentationTypeIdentifier.UInt32,
|
||||
[TDUIdentifier.Int32] = RepresentationTypeIdentifier.Int32,
|
||||
[TDUIdentifier.UInt64] = RepresentationTypeIdentifier.UInt64,
|
||||
[TDUIdentifier.Int64] = RepresentationTypeIdentifier.Int64,
|
||||
[TDUIdentifier.UInt128] = RepresentationTypeIdentifier.UInt128,
|
||||
[TDUIdentifier.Int128] = RepresentationTypeIdentifier.Int128,
|
||||
[TDUIdentifier.Char8] = RepresentationTypeIdentifier.Char,
|
||||
[TDUIdentifier.DateTime] = RepresentationTypeIdentifier.DateTime,
|
||||
[TDUIdentifier.Float32] = RepresentationTypeIdentifier.Float32,
|
||||
[TDUIdentifier.Float64] = RepresentationTypeIdentifier.Float64,
|
||||
[TDUIdentifier.Decimal128] = RepresentationTypeIdentifier.Decimal,
|
||||
[TDUIdentifier.False] = RepresentationTypeIdentifier.Bool,
|
||||
[TDUIdentifier.True] = RepresentationTypeIdentifier.Bool,
|
||||
[TDUIdentifier.Map] = RepresentationTypeIdentifier.Map,
|
||||
[TDUIdentifier.List] = RepresentationTypeIdentifier.List,
|
||||
[TDUIdentifier.RawData] = RepresentationTypeIdentifier.RawData,
|
||||
[TDUIdentifier.Record] = RepresentationTypeIdentifier.Record,
|
||||
[TDUIdentifier.String] = RepresentationTypeIdentifier.String,
|
||||
};
|
||||
|
||||
|
||||
|
||||
public void SetNull(List<byte> flags)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flags.FirstOrDefault() == 2);
|
||||
if (flags.Count > 0)
|
||||
flags.RemoveAt(0);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNull(flags);
|
||||
}
|
||||
|
||||
public void SetNull(byte flag)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flag == 2);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNull(flag);
|
||||
}
|
||||
|
||||
|
||||
public void SetNotNull(List<byte> flags)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flags.FirstOrDefault() != 1);
|
||||
if (flags.Count > 0)
|
||||
flags.RemoveAt(0);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNotNull(flags);
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (SubTypes != null && SubTypes.Length > 0)
|
||||
return Identifier.ToString() + "<" + String.Join(",", SubTypes.Select(x => x.ToString())) + ">" + (Nullable ? "?" : "");
|
||||
return Identifier.ToString() + (Nullable ? "?" : "");
|
||||
}
|
||||
public void SetNotNull(byte flag)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flag != 1);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNotNull(flag);
|
||||
}
|
||||
|
||||
public Type? GetRuntimeType(Warehouse warehouse)
|
||||
{
|
||||
|
||||
if (Identifier == RepresentationTypeIdentifier.TypedList)
|
||||
{
|
||||
var sub = SubTypes?[0].GetRuntimeType(warehouse);
|
||||
if (sub == null)
|
||||
return null;
|
||||
|
||||
var rt = sub.MakeArrayType();
|
||||
|
||||
return rt;
|
||||
}
|
||||
else if (Identifier == RepresentationTypeIdentifier.TypedMap)
|
||||
{
|
||||
var subs = SubTypes.Select(x => x.GetRuntimeType(warehouse)).ToArray();
|
||||
var rt = typeof(Map<,>).MakeGenericType(subs);
|
||||
return rt;
|
||||
}
|
||||
|
||||
return Identifier switch
|
||||
{
|
||||
(RepresentationTypeIdentifier.Void) => typeof(void),
|
||||
(RepresentationTypeIdentifier.Dynamic) => typeof(object),
|
||||
(RepresentationTypeIdentifier.Bool) => Nullable ? typeof(bool?) : typeof(bool),
|
||||
(RepresentationTypeIdentifier.Char) => Nullable ? typeof(char?) : typeof(char),
|
||||
(RepresentationTypeIdentifier.UInt8) => Nullable ? typeof(byte?) : typeof(byte),
|
||||
(RepresentationTypeIdentifier.Int8) => Nullable ? typeof(sbyte?) : typeof(sbyte),
|
||||
(RepresentationTypeIdentifier.Int16) => Nullable ? typeof(short?) : typeof(short),
|
||||
(RepresentationTypeIdentifier.UInt16) => Nullable ? typeof(ushort?) : typeof(ushort),
|
||||
(RepresentationTypeIdentifier.Int32) => Nullable ? typeof(int?) : typeof(int),
|
||||
(RepresentationTypeIdentifier.UInt32) => Nullable ? typeof(uint?) : typeof(uint),
|
||||
(RepresentationTypeIdentifier.Int64) => Nullable ? typeof(ulong?) : typeof(long),
|
||||
(RepresentationTypeIdentifier.UInt64) => Nullable ? typeof(ulong?) : typeof(ulong),
|
||||
(RepresentationTypeIdentifier.Float32) => Nullable ? typeof(float?) : typeof(float),
|
||||
(RepresentationTypeIdentifier.Float64) => Nullable ? typeof(double?) : typeof(double),
|
||||
(RepresentationTypeIdentifier.Decimal) => Nullable ? typeof(decimal?) : typeof(decimal),
|
||||
(RepresentationTypeIdentifier.String) => typeof(string),
|
||||
(RepresentationTypeIdentifier.DateTime) => Nullable ? typeof(DateTime?) : typeof(DateTime),
|
||||
(RepresentationTypeIdentifier.Resource) => typeof(IResource),
|
||||
(RepresentationTypeIdentifier.Record) => typeof(IRecord),
|
||||
(RepresentationTypeIdentifier.TypedRecord) => warehouse.GetTemplateByClassId((UUID)UUID!, TemplateType.Record)?.DefinedType,
|
||||
(RepresentationTypeIdentifier.TypedResource) => warehouse.GetTemplateByClassId((UUID)UUID!, TemplateType.Resource)?.DefinedType,
|
||||
(RepresentationTypeIdentifier.Enum) =>warehouse.GetTemplateByClassId((UUID)UUID!, TemplateType.Enum)?.DefinedType,
|
||||
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public RepresentationTypeIdentifier Identifier;
|
||||
public bool Nullable;
|
||||
public UUID? UUID;
|
||||
//public RepresentationType? SubType1; // List + Map
|
||||
//public RepresentationType? SubType2; // Map
|
||||
//public RepresentationType? SubType3; // No types yet
|
||||
|
||||
public RepresentationType[]? SubTypes = null;
|
||||
|
||||
public RepresentationType ToNullable()
|
||||
{
|
||||
return new RepresentationType(Identifier, true, UUID, SubTypes);
|
||||
}
|
||||
|
||||
public static RepresentationType? FromType(Type type)
|
||||
{
|
||||
|
||||
var nullable = false;
|
||||
|
||||
var nullType = System.Nullable.GetUnderlyingType(type);
|
||||
|
||||
if (nullType != null)
|
||||
{
|
||||
type = nullType;
|
||||
nullable = true;
|
||||
}
|
||||
|
||||
if (type == typeof(IResource))
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Resource, nullable);
|
||||
else if (type == typeof(IRecord) || type == typeof(Record))
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Record, nullable);
|
||||
else if (type == typeof(Map<object, object>)
|
||||
|| type == typeof(Dictionary<object, object>))
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Map, nullable);
|
||||
else if (Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
{
|
||||
return new RepresentationType(
|
||||
RepresentationTypeIdentifier.TypedResource,
|
||||
nullable,
|
||||
TypeTemplate.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
|
||||
{
|
||||
return new RepresentationType(
|
||||
RepresentationTypeIdentifier.TypedRecord,
|
||||
nullable,
|
||||
TypeTemplate.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (type.IsGenericType)
|
||||
{
|
||||
var genericType = type.GetGenericTypeDefinition();
|
||||
if (genericType == typeof(List<>)
|
||||
|| genericType == typeof(VarList<>)
|
||||
|| genericType == typeof(IList<>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object))
|
||||
{
|
||||
return new RepresentationType(RepresentationTypeIdentifier.List, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subType = FromType(args[0]);
|
||||
if (subType == null) // unrecongnized type
|
||||
return null;
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.TypedList, nullable, null,
|
||||
new RepresentationType[] { subType });
|
||||
|
||||
}
|
||||
}
|
||||
else if (genericType == typeof(Map<,>)
|
||||
|| genericType == typeof(Dictionary<,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object) && args[1] == typeof(object))
|
||||
{
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Map, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subType1 = FromType(args[0]);
|
||||
if (subType1 == null)
|
||||
return null;
|
||||
|
||||
var subType2 = FromType(args[1]);
|
||||
if (subType2 == null)
|
||||
return null;
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.TypedMap, nullable, null,
|
||||
new RepresentationType[] { subType1, subType2 });
|
||||
}
|
||||
}
|
||||
//else if (genericType == typeof(AsyncReply<>))
|
||||
//{
|
||||
// var args = type.GetGenericArguments();
|
||||
// return FromType(args[0]);
|
||||
//}
|
||||
//else if (genericType == typeof(DistributedPropertyContext<>))
|
||||
//{
|
||||
// var args = type.GetGenericArguments();
|
||||
// return FromType(args[0]);
|
||||
//}
|
||||
else if (genericType == typeof(ValueTuple<,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new RepresentationType[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Tuple2, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new RepresentationType[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Tuple3, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,>))
|
||||
{
|
||||
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new RepresentationType[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Tuple4, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new RepresentationType[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Tuple5, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new RepresentationType[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Tuple6, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new RepresentationType[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Tuple7, nullable, null, subTypes);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
var elementType = type.GetElementType();
|
||||
if (elementType == typeof(object))
|
||||
return new RepresentationType(RepresentationTypeIdentifier.List, nullable);
|
||||
else
|
||||
{
|
||||
var subType = FromType(elementType);
|
||||
|
||||
if (subType == null)
|
||||
return null;
|
||||
|
||||
return new RepresentationType(RepresentationTypeIdentifier.TypedList, nullable, null,
|
||||
new RepresentationType[] { subType });
|
||||
|
||||
}
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
return new RepresentationType(RepresentationTypeIdentifier.Enum, nullable, TypeTemplate.GetTypeUUID(type));
|
||||
}
|
||||
else if (type.IsInterface)
|
||||
{
|
||||
return null; // other interfaces are not supported
|
||||
}
|
||||
|
||||
//else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => RepresentationTypeIdentifier.Structure)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
return type switch
|
||||
{
|
||||
_ when type == typeof(void) => new RepresentationType(RepresentationTypeIdentifier.Void, nullable),
|
||||
_ when type == typeof(object) => new RepresentationType(RepresentationTypeIdentifier.Dynamic, nullable),
|
||||
_ when type == typeof(bool) => new RepresentationType(RepresentationTypeIdentifier.Bool, nullable),
|
||||
_ when type == typeof(char) => new RepresentationType(RepresentationTypeIdentifier.Char, nullable),
|
||||
_ when type == typeof(byte) => new RepresentationType(RepresentationTypeIdentifier.UInt8, nullable),
|
||||
_ when type == typeof(sbyte) => new RepresentationType(RepresentationTypeIdentifier.Int8, nullable),
|
||||
_ when type == typeof(short) => new RepresentationType(RepresentationTypeIdentifier.Int16, nullable),
|
||||
_ when type == typeof(ushort) => new RepresentationType(RepresentationTypeIdentifier.UInt16, nullable),
|
||||
_ when type == typeof(int) => new RepresentationType(RepresentationTypeIdentifier.Int32, nullable),
|
||||
_ when type == typeof(uint) => new RepresentationType(RepresentationTypeIdentifier.UInt32, nullable),
|
||||
_ when type == typeof(long) => new RepresentationType(RepresentationTypeIdentifier.Int64, nullable),
|
||||
_ when type == typeof(ulong) => new RepresentationType(RepresentationTypeIdentifier.UInt64, nullable),
|
||||
_ when type == typeof(float) => new RepresentationType(RepresentationTypeIdentifier.Float32, nullable),
|
||||
_ when type == typeof(double) => new RepresentationType(RepresentationTypeIdentifier.Float64, nullable),
|
||||
_ when type == typeof(decimal) => new RepresentationType(RepresentationTypeIdentifier.Decimal, nullable),
|
||||
_ when type == typeof(string) => new RepresentationType(RepresentationTypeIdentifier.String, nullable),
|
||||
_ when type == typeof(DateTime) => new RepresentationType(RepresentationTypeIdentifier.DateTime, nullable),
|
||||
_ => null
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public RepresentationType(RepresentationTypeIdentifier identifier, bool nullable, UUID? uuid = null, RepresentationType[]? subTypes = null)
|
||||
{
|
||||
Nullable = nullable;
|
||||
Identifier = identifier;
|
||||
UUID = uuid;
|
||||
SubTypes = subTypes;
|
||||
}
|
||||
|
||||
public byte[] Compose()
|
||||
{
|
||||
var rt = new BinaryList();
|
||||
|
||||
if (Nullable)
|
||||
rt.AddUInt8((byte)(0x80 | (byte)Identifier));
|
||||
else
|
||||
rt.AddUInt8((byte)Identifier);
|
||||
|
||||
if (UUID != null)
|
||||
rt.AddUInt8Array(UUID.Value.Data);
|
||||
|
||||
if (SubTypes != null)
|
||||
for (var i = 0; i < SubTypes.Length; i++)
|
||||
rt.AddUInt8Array(SubTypes[i].Compose());
|
||||
|
||||
return rt.ToArray();
|
||||
}
|
||||
|
||||
|
||||
//public override string ToString() => Identifier.ToString() + (Nullable ? "?" : "")
|
||||
// + TypeTemplate != null ? "<" + TypeTemplate.ClassName + ">" : "";
|
||||
|
||||
|
||||
public static (uint, RepresentationType) Parse(byte[] data, uint offset)
|
||||
{
|
||||
var oOffset = offset;
|
||||
|
||||
var header = data[offset++];
|
||||
bool nullable = (header & 0x80) > 0;
|
||||
var identifier = (RepresentationTypeIdentifier)(header & 0x7F);
|
||||
|
||||
|
||||
if ((header & 0x40) > 0)
|
||||
{
|
||||
|
||||
var hasUUID = (header & 0x4) > 0;
|
||||
var subsCount = (header >> 3) & 0x7;
|
||||
|
||||
UUID? uuid = null;
|
||||
|
||||
if (hasUUID)
|
||||
{
|
||||
uuid = data.GetUUID(offset);
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
var subs = new RepresentationType[subsCount];
|
||||
|
||||
for (var i = 0; i < subsCount; i++)
|
||||
{
|
||||
(var len, subs[i]) = RepresentationType.Parse(data, offset);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return (offset - oOffset, new RepresentationType(identifier, nullable, uuid, subs));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (1, new RepresentationType(identifier, nullable));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ public struct TDU
|
||||
public TDU(TDUIdentifier identifier)
|
||||
{
|
||||
Identifier = identifier;
|
||||
Composed = new byte[0];
|
||||
}
|
||||
|
||||
public TDU(TDUIdentifier identifier,
|
||||
@@ -74,7 +75,10 @@ public struct TDU
|
||||
|
||||
if (Class == TDUClass.Fixed)
|
||||
{
|
||||
Composed = DC.Combine(new byte[] { (byte)Identifier }, 0, 1, data, 0, (uint)length);
|
||||
if (length == 0)
|
||||
Composed = new byte[1] { (byte)identifier };
|
||||
else
|
||||
Composed = DC.Combine(new byte[] { (byte)Identifier }, 0, 1, data, 0, (uint)length);
|
||||
}
|
||||
else if (Class == TDUClass.Dynamic
|
||||
|| Class == TDUClass.Extension)
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Esiur.Data
|
||||
TypedConstant = 0x85,
|
||||
|
||||
TypeContinuation = 0xC0,
|
||||
|
||||
TypeOfTarget = 0xC1,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
502
Esiur/Data/TRU.cs
Normal file
502
Esiur/Data/TRU.cs
Normal file
@@ -0,0 +1,502 @@
|
||||
using Esiur.Core;
|
||||
using Esiur.Net.IIP;
|
||||
using Esiur.Resource;
|
||||
using Esiur.Resource.Template;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Esiur.Data
|
||||
{
|
||||
public class TRU
|
||||
{
|
||||
|
||||
static TRUIdentifier[] refTypes = new TRUIdentifier[]
|
||||
{
|
||||
TRUIdentifier.Dynamic,
|
||||
TRUIdentifier.RawData,
|
||||
TRUIdentifier.String,
|
||||
TRUIdentifier.Resource,
|
||||
TRUIdentifier.Record,
|
||||
TRUIdentifier.Map,
|
||||
TRUIdentifier.List,
|
||||
TRUIdentifier.TypedList,
|
||||
TRUIdentifier.TypedMap,
|
||||
TRUIdentifier.Tuple2,
|
||||
TRUIdentifier.Tuple3,
|
||||
TRUIdentifier.Tuple4,
|
||||
TRUIdentifier.Tuple5,
|
||||
TRUIdentifier.Tuple6,
|
||||
TRUIdentifier.Tuple7,
|
||||
TRUIdentifier.TypedRecord,
|
||||
TRUIdentifier.TypedResource
|
||||
};
|
||||
|
||||
static Map<TDUIdentifier, TRUIdentifier> typesMap = new Map<TDUIdentifier, TRUIdentifier>()
|
||||
{
|
||||
[TDUIdentifier.UInt8] = TRUIdentifier.UInt8,
|
||||
[TDUIdentifier.Int8] = TRUIdentifier.Int8,
|
||||
[TDUIdentifier.UInt16] = TRUIdentifier.UInt16,
|
||||
[TDUIdentifier.Int16] = TRUIdentifier.Int16,
|
||||
[TDUIdentifier.UInt32] = TRUIdentifier.UInt32,
|
||||
[TDUIdentifier.Int32] = TRUIdentifier.Int32,
|
||||
[TDUIdentifier.UInt64] = TRUIdentifier.UInt64,
|
||||
[TDUIdentifier.Int64] = TRUIdentifier.Int64,
|
||||
[TDUIdentifier.UInt128] = TRUIdentifier.UInt128,
|
||||
[TDUIdentifier.Int128] = TRUIdentifier.Int128,
|
||||
[TDUIdentifier.Char8] = TRUIdentifier.Char,
|
||||
[TDUIdentifier.DateTime] = TRUIdentifier.DateTime,
|
||||
[TDUIdentifier.Float32] = TRUIdentifier.Float32,
|
||||
[TDUIdentifier.Float64] = TRUIdentifier.Float64,
|
||||
[TDUIdentifier.Decimal128] = TRUIdentifier.Decimal,
|
||||
[TDUIdentifier.False] = TRUIdentifier.Bool,
|
||||
[TDUIdentifier.True] = TRUIdentifier.Bool,
|
||||
[TDUIdentifier.Map] = TRUIdentifier.Map,
|
||||
[TDUIdentifier.List] = TRUIdentifier.List,
|
||||
[TDUIdentifier.RawData] = TRUIdentifier.RawData,
|
||||
[TDUIdentifier.Record] = TRUIdentifier.Record,
|
||||
[TDUIdentifier.String] = TRUIdentifier.String,
|
||||
};
|
||||
|
||||
|
||||
|
||||
public void SetNull(List<byte> flags)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flags.FirstOrDefault() == 2);
|
||||
if (flags.Count > 0)
|
||||
flags.RemoveAt(0);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNull(flags);
|
||||
}
|
||||
|
||||
public void SetNull(byte flag)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flag == 2);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNull(flag);
|
||||
}
|
||||
|
||||
|
||||
public void SetNotNull(List<byte> flags)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flags.FirstOrDefault() != 1);
|
||||
if (flags.Count > 0)
|
||||
flags.RemoveAt(0);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNotNull(flags);
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (SubTypes != null && SubTypes.Length > 0)
|
||||
return Identifier.ToString() + "<" + String.Join(",", SubTypes.Select(x => x.ToString())) + ">" + (Nullable ? "?" : "");
|
||||
return Identifier.ToString() + (Nullable ? "?" : "");
|
||||
}
|
||||
public void SetNotNull(byte flag)
|
||||
{
|
||||
if (refTypes.Contains(Identifier))
|
||||
{
|
||||
Nullable = (flag != 1);
|
||||
}
|
||||
|
||||
if (SubTypes != null)
|
||||
foreach (var st in SubTypes)
|
||||
st.SetNotNull(flag);
|
||||
}
|
||||
|
||||
public Type? GetRuntimeType(Warehouse warehouse)
|
||||
{
|
||||
|
||||
if (Identifier == TRUIdentifier.TypedList)
|
||||
{
|
||||
var sub = SubTypes?[0].GetRuntimeType(warehouse);
|
||||
if (sub == null)
|
||||
return null;
|
||||
|
||||
var rt = sub.MakeArrayType();
|
||||
|
||||
return rt;
|
||||
}
|
||||
else if (Identifier == TRUIdentifier.TypedMap)
|
||||
{
|
||||
var subs = SubTypes.Select(x => x.GetRuntimeType(warehouse)).ToArray();
|
||||
var rt = typeof(Map<,>).MakeGenericType(subs);
|
||||
return rt;
|
||||
}
|
||||
|
||||
return Identifier switch
|
||||
{
|
||||
(TRUIdentifier.Void) => typeof(void),
|
||||
(TRUIdentifier.Dynamic) => typeof(object),
|
||||
(TRUIdentifier.Bool) => Nullable ? typeof(bool?) : typeof(bool),
|
||||
(TRUIdentifier.Char) => Nullable ? typeof(char?) : typeof(char),
|
||||
(TRUIdentifier.UInt8) => Nullable ? typeof(byte?) : typeof(byte),
|
||||
(TRUIdentifier.Int8) => Nullable ? typeof(sbyte?) : typeof(sbyte),
|
||||
(TRUIdentifier.Int16) => Nullable ? typeof(short?) : typeof(short),
|
||||
(TRUIdentifier.UInt16) => Nullable ? typeof(ushort?) : typeof(ushort),
|
||||
(TRUIdentifier.Int32) => Nullable ? typeof(int?) : typeof(int),
|
||||
(TRUIdentifier.UInt32) => Nullable ? typeof(uint?) : typeof(uint),
|
||||
(TRUIdentifier.Int64) => Nullable ? typeof(ulong?) : typeof(long),
|
||||
(TRUIdentifier.UInt64) => Nullable ? typeof(ulong?) : typeof(ulong),
|
||||
(TRUIdentifier.Float32) => Nullable ? typeof(float?) : typeof(float),
|
||||
(TRUIdentifier.Float64) => Nullable ? typeof(double?) : typeof(double),
|
||||
(TRUIdentifier.Decimal) => Nullable ? typeof(decimal?) : typeof(decimal),
|
||||
(TRUIdentifier.String) => typeof(string),
|
||||
(TRUIdentifier.DateTime) => Nullable ? typeof(DateTime?) : typeof(DateTime),
|
||||
(TRUIdentifier.Resource) => typeof(IResource),
|
||||
(TRUIdentifier.Record) => typeof(IRecord),
|
||||
(TRUIdentifier.TypedRecord) => warehouse.GetTemplateByClassId((UUID)UUID!, TemplateType.Record)?.DefinedType,
|
||||
(TRUIdentifier.TypedResource) => warehouse.GetTemplateByClassId((UUID)UUID!, TemplateType.Resource)?.DefinedType,
|
||||
(TRUIdentifier.Enum) =>warehouse.GetTemplateByClassId((UUID)UUID!, TemplateType.Enum)?.DefinedType,
|
||||
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public TRUIdentifier Identifier;
|
||||
public bool Nullable;
|
||||
public UUID? UUID;
|
||||
//public RepresentationType? SubType1; // List + Map
|
||||
//public RepresentationType? SubType2; // Map
|
||||
//public RepresentationType? SubType3; // No types yet
|
||||
|
||||
public TRU[]? SubTypes = null;
|
||||
|
||||
public TRU ToNullable()
|
||||
{
|
||||
return new TRU(Identifier, true, UUID, SubTypes);
|
||||
}
|
||||
|
||||
public bool Match(TRU other)
|
||||
{
|
||||
if (other.Identifier != Identifier)
|
||||
return false;
|
||||
if (other.UUID != UUID)
|
||||
return false;
|
||||
|
||||
if (other.SubTypes != null)
|
||||
{
|
||||
if (other.SubTypes.Length != (SubTypes?.Length ?? -1))
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < SubTypes?.Length; i++)
|
||||
if (!SubTypes[i].Match(other.SubTypes[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static TRU? FromType(Type type)
|
||||
{
|
||||
|
||||
var nullable = false;
|
||||
|
||||
var nullType = System.Nullable.GetUnderlyingType(type);
|
||||
|
||||
if (nullType != null)
|
||||
{
|
||||
type = nullType;
|
||||
nullable = true;
|
||||
}
|
||||
|
||||
if (type == typeof(IResource))
|
||||
return new TRU(TRUIdentifier.Resource, nullable);
|
||||
else if (type == typeof(IRecord) || type == typeof(Record))
|
||||
return new TRU(TRUIdentifier.Record, nullable);
|
||||
else if (type == typeof(Map<object, object>)
|
||||
|| type == typeof(Dictionary<object, object>))
|
||||
return new TRU(TRUIdentifier.Map, nullable);
|
||||
else if (Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
{
|
||||
return new TRU(
|
||||
TRUIdentifier.TypedResource,
|
||||
nullable,
|
||||
TypeTemplate.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
|
||||
{
|
||||
return new TRU(
|
||||
TRUIdentifier.TypedRecord,
|
||||
nullable,
|
||||
TypeTemplate.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (type.IsGenericType)
|
||||
{
|
||||
var genericType = type.GetGenericTypeDefinition();
|
||||
if (genericType == typeof(List<>)
|
||||
|| genericType == typeof(VarList<>)
|
||||
|| genericType == typeof(IList<>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object))
|
||||
{
|
||||
return new TRU(TRUIdentifier.List, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subType = FromType(args[0]);
|
||||
if (subType == null) // unrecongnized type
|
||||
return null;
|
||||
|
||||
return new TRU(TRUIdentifier.TypedList, nullable, null,
|
||||
new TRU[] { subType });
|
||||
|
||||
}
|
||||
}
|
||||
else if (genericType == typeof(Map<,>)
|
||||
|| genericType == typeof(Dictionary<,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object) && args[1] == typeof(object))
|
||||
{
|
||||
return new TRU(TRUIdentifier.Map, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subType1 = FromType(args[0]);
|
||||
if (subType1 == null)
|
||||
return null;
|
||||
|
||||
var subType2 = FromType(args[1]);
|
||||
if (subType2 == null)
|
||||
return null;
|
||||
|
||||
return new TRU(TRUIdentifier.TypedMap, nullable, null,
|
||||
new TRU[] { subType1, subType2 });
|
||||
}
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new TRU[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new TRU(TRUIdentifier.Tuple2, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new TRU[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new TRU(TRUIdentifier.Tuple3, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,>))
|
||||
{
|
||||
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new TRU[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new TRU(TRUIdentifier.Tuple4, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new TRU[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new TRU(TRUIdentifier.Tuple5, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new TRU[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new TRU(TRUIdentifier.Tuple6, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new TRU[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
return new TRU(TRUIdentifier.Tuple7, nullable, null, subTypes);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
var elementType = type.GetElementType();
|
||||
if (elementType == typeof(object))
|
||||
return new TRU(TRUIdentifier.List, nullable);
|
||||
else
|
||||
{
|
||||
var subType = FromType(elementType);
|
||||
|
||||
if (subType == null)
|
||||
return null;
|
||||
|
||||
return new TRU(TRUIdentifier.TypedList, nullable, null,
|
||||
new TRU[] { subType });
|
||||
|
||||
}
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
return new TRU(TRUIdentifier.Enum, nullable, TypeTemplate.GetTypeUUID(type));
|
||||
}
|
||||
else if (type.IsInterface)
|
||||
{
|
||||
return null; // other interfaces are not supported
|
||||
}
|
||||
|
||||
//else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => TRUIdentifier.Structure)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
return type switch
|
||||
{
|
||||
_ when type == typeof(void) => new TRU(TRUIdentifier.Void, nullable),
|
||||
_ when type == typeof(object) => new TRU(TRUIdentifier.Dynamic, nullable),
|
||||
_ when type == typeof(bool) => new TRU(TRUIdentifier.Bool, nullable),
|
||||
_ when type == typeof(char) => new TRU(TRUIdentifier.Char, nullable),
|
||||
_ when type == typeof(byte) => new TRU(TRUIdentifier.UInt8, nullable),
|
||||
_ when type == typeof(sbyte) => new TRU(TRUIdentifier.Int8, nullable),
|
||||
_ when type == typeof(short) => new TRU(TRUIdentifier.Int16, nullable),
|
||||
_ when type == typeof(ushort) => new TRU(TRUIdentifier.UInt16, nullable),
|
||||
_ when type == typeof(int) => new TRU(TRUIdentifier.Int32, nullable),
|
||||
_ when type == typeof(uint) => new TRU(TRUIdentifier.UInt32, nullable),
|
||||
_ when type == typeof(long) => new TRU(TRUIdentifier.Int64, nullable),
|
||||
_ when type == typeof(ulong) => new TRU(TRUIdentifier.UInt64, nullable),
|
||||
_ when type == typeof(float) => new TRU(TRUIdentifier.Float32, nullable),
|
||||
_ when type == typeof(double) => new TRU(TRUIdentifier.Float64, nullable),
|
||||
_ when type == typeof(decimal) => new TRU(TRUIdentifier.Decimal, nullable),
|
||||
_ when type == typeof(string) => new TRU(TRUIdentifier.String, nullable),
|
||||
_ when type == typeof(DateTime) => new TRU(TRUIdentifier.DateTime, nullable),
|
||||
_ => null
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public TRU(TRUIdentifier identifier, bool nullable, UUID? uuid = null, TRU[]? subTypes = null)
|
||||
{
|
||||
Nullable = nullable;
|
||||
Identifier = identifier;
|
||||
UUID = uuid;
|
||||
SubTypes = subTypes;
|
||||
}
|
||||
|
||||
public byte[] Compose()
|
||||
{
|
||||
var rt = new BinaryList();
|
||||
|
||||
if (Nullable)
|
||||
rt.AddUInt8((byte)(0x80 | (byte)Identifier));
|
||||
else
|
||||
rt.AddUInt8((byte)Identifier);
|
||||
|
||||
if (UUID != null)
|
||||
rt.AddUInt8Array(UUID.Value.Data);
|
||||
|
||||
if (SubTypes != null)
|
||||
for (var i = 0; i < SubTypes.Length; i++)
|
||||
rt.AddUInt8Array(SubTypes[i].Compose());
|
||||
|
||||
return rt.ToArray();
|
||||
}
|
||||
|
||||
public static (uint, TRU) Parse(byte[] data, uint offset)
|
||||
{
|
||||
var oOffset = offset;
|
||||
|
||||
var header = data[offset++];
|
||||
bool nullable = (header & 0x80) > 0;
|
||||
var identifier = (TRUIdentifier)(header & 0x7F);
|
||||
|
||||
|
||||
if ((header & 0x40) > 0)
|
||||
{
|
||||
|
||||
var hasUUID = (header & 0x4) > 0;
|
||||
var subsCount = (header >> 3) & 0x7;
|
||||
|
||||
UUID? uuid = null;
|
||||
|
||||
if (hasUUID)
|
||||
{
|
||||
uuid = data.GetUUID(offset);
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
var subs = new TRU[subsCount];
|
||||
|
||||
for (var i = 0; i < subsCount; i++)
|
||||
{
|
||||
(var len, subs[i]) = TRU.Parse(data, offset);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return (offset - oOffset, new TRU(identifier, nullable, uuid, subs));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (1, new TRU(identifier, nullable));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
46
Esiur/Data/TRUIdentifier.cs
Normal file
46
Esiur/Data/TRUIdentifier.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Data
|
||||
{
|
||||
public enum TRUIdentifier
|
||||
{
|
||||
Void = 0x0,
|
||||
Dynamic = 0x1,
|
||||
Bool = 0x2,
|
||||
UInt8,
|
||||
Int8,
|
||||
Char,
|
||||
UInt16,
|
||||
Int16,
|
||||
UInt32,
|
||||
Int32,
|
||||
Float32,
|
||||
UInt64,
|
||||
Int64,
|
||||
Float64,
|
||||
DateTime,
|
||||
UInt128,
|
||||
Int128,
|
||||
Decimal,
|
||||
String,
|
||||
RawData,
|
||||
Resource,
|
||||
Record,
|
||||
List,
|
||||
Map,
|
||||
Enum = 0x44,
|
||||
TypedResource = 0x45, // Followed by UUID
|
||||
TypedRecord = 0x46, // Followed by UUID
|
||||
TypedList = 0x48, // Followed by element type
|
||||
Tuple2 = 0x50, // Followed by element type
|
||||
TypedMap = 0x51, // Followed by key type and value type
|
||||
Tuple3 = 0x58,
|
||||
Tuple4 = 0x60,
|
||||
Tuple5 = 0x68,
|
||||
Tuple6 = 0x70,
|
||||
Tuple7 = 0x78
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ namespace Esiur.Net.Packets
|
||||
// Success
|
||||
Completed = 0x0,
|
||||
Propagated = 0x1,
|
||||
Stream = 0x2,
|
||||
|
||||
// Error
|
||||
PermissionError = 0x81,
|
||||
|
||||
@@ -32,6 +32,11 @@ namespace Esiur.Net.Packets
|
||||
// Request Static
|
||||
KeepAlive = 0x18,
|
||||
ProcedureCall = 0x19,
|
||||
StaticCall = 0x1A
|
||||
StaticCall = 0x1A,
|
||||
IndirectCall = 0x1B,
|
||||
PullStream = 0x1C,
|
||||
TerminateExecution = 0x1D,
|
||||
HaltExecution = 0x1E,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,28 +121,28 @@ public static class TemplateGenerator
|
||||
}
|
||||
|
||||
|
||||
static string GetTypeName(RepresentationType representationType, TypeTemplate[] templates)
|
||||
static string GetTypeName(TRU representationType, TypeTemplate[] templates)
|
||||
{
|
||||
string name;
|
||||
|
||||
if (representationType.Identifier == RepresentationTypeIdentifier.TypedResource)// == DataType.Resource)
|
||||
if (representationType.Identifier == TRUIdentifier.TypedResource)// == DataType.Resource)
|
||||
name = templates.First(x => x.ClassId == representationType.UUID && (x.Type == TemplateType.Resource)).ClassName;
|
||||
else if (representationType.Identifier == RepresentationTypeIdentifier.TypedRecord)
|
||||
else if (representationType.Identifier == TRUIdentifier.TypedRecord)
|
||||
name = templates.First(x => x.ClassId == representationType.UUID && x.Type == TemplateType.Record).ClassName;
|
||||
else if (representationType.Identifier == RepresentationTypeIdentifier.Enum)
|
||||
else if (representationType.Identifier == TRUIdentifier.Enum)
|
||||
name = templates.First(x => x.ClassId == representationType.UUID && x.Type == TemplateType.Enum).ClassName;
|
||||
else if (representationType.Identifier == RepresentationTypeIdentifier.TypedList)
|
||||
else if (representationType.Identifier == TRUIdentifier.TypedList)
|
||||
name = GetTypeName(representationType.SubTypes[0], templates) + "[]";
|
||||
else if (representationType.Identifier == RepresentationTypeIdentifier.TypedMap)
|
||||
else if (representationType.Identifier == TRUIdentifier.TypedMap)
|
||||
name = "Map<" + GetTypeName(representationType.SubTypes[0], templates)
|
||||
+ "," + GetTypeName(representationType.SubTypes[1], templates)
|
||||
+ ">";
|
||||
else if (representationType.Identifier == RepresentationTypeIdentifier.Tuple2 ||
|
||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple3 ||
|
||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple4 ||
|
||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple5 ||
|
||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple6 ||
|
||||
representationType.Identifier == RepresentationTypeIdentifier.Tuple7)
|
||||
else if (representationType.Identifier == TRUIdentifier.Tuple2 ||
|
||||
representationType.Identifier == TRUIdentifier.Tuple3 ||
|
||||
representationType.Identifier == TRUIdentifier.Tuple4 ||
|
||||
representationType.Identifier == TRUIdentifier.Tuple5 ||
|
||||
representationType.Identifier == TRUIdentifier.Tuple6 ||
|
||||
representationType.Identifier == TRUIdentifier.Tuple7)
|
||||
name = "(" + String.Join(",", representationType.SubTypes.Select(x => GetTypeName(x, templates)))
|
||||
+ ")";
|
||||
else
|
||||
@@ -150,26 +150,26 @@ public static class TemplateGenerator
|
||||
|
||||
name = representationType.Identifier switch
|
||||
{
|
||||
RepresentationTypeIdentifier.Dynamic => "object",
|
||||
RepresentationTypeIdentifier.Bool => "bool",
|
||||
RepresentationTypeIdentifier.Char => "char",
|
||||
RepresentationTypeIdentifier.DateTime => "DateTime",
|
||||
RepresentationTypeIdentifier.Decimal => "decimal",
|
||||
RepresentationTypeIdentifier.Float32 => "float",
|
||||
RepresentationTypeIdentifier.Float64 => "double",
|
||||
RepresentationTypeIdentifier.Int16 => "short",
|
||||
RepresentationTypeIdentifier.Int32 => "int",
|
||||
RepresentationTypeIdentifier.Int64 => "long",
|
||||
RepresentationTypeIdentifier.Int8 => "sbyte",
|
||||
RepresentationTypeIdentifier.String => "string",
|
||||
RepresentationTypeIdentifier.Map => "Map<object, object>",
|
||||
RepresentationTypeIdentifier.UInt16 => "ushort",
|
||||
RepresentationTypeIdentifier.UInt32 => "uint",
|
||||
RepresentationTypeIdentifier.UInt64 => "ulong",
|
||||
RepresentationTypeIdentifier.UInt8 => "byte",
|
||||
RepresentationTypeIdentifier.List => "object[]",
|
||||
RepresentationTypeIdentifier.Resource => "IResource",
|
||||
RepresentationTypeIdentifier.Record => "IRecord",
|
||||
TRUIdentifier.Dynamic => "object",
|
||||
TRUIdentifier.Bool => "bool",
|
||||
TRUIdentifier.Char => "char",
|
||||
TRUIdentifier.DateTime => "DateTime",
|
||||
TRUIdentifier.Decimal => "decimal",
|
||||
TRUIdentifier.Float32 => "float",
|
||||
TRUIdentifier.Float64 => "double",
|
||||
TRUIdentifier.Int16 => "short",
|
||||
TRUIdentifier.Int32 => "int",
|
||||
TRUIdentifier.Int64 => "long",
|
||||
TRUIdentifier.Int8 => "sbyte",
|
||||
TRUIdentifier.String => "string",
|
||||
TRUIdentifier.Map => "Map<object, object>",
|
||||
TRUIdentifier.UInt16 => "ushort",
|
||||
TRUIdentifier.UInt32 => "uint",
|
||||
TRUIdentifier.UInt64 => "ulong",
|
||||
TRUIdentifier.UInt8 => "byte",
|
||||
TRUIdentifier.List => "object[]",
|
||||
TRUIdentifier.Resource => "IResource",
|
||||
TRUIdentifier.Record => "IRecord",
|
||||
_ => "object"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class Storable : global::System.Attribute
|
||||
|
||||
SerializerFunction serializer;
|
||||
DeserializerFunction deserializer;
|
||||
RepresentationType dataType;
|
||||
TRU dataType;
|
||||
|
||||
public Storable()
|
||||
{
|
||||
@@ -57,12 +57,12 @@ public class Storable : global::System.Attribute
|
||||
get { return serializer; }
|
||||
}
|
||||
|
||||
public Storable(RepresentationType type)
|
||||
public Storable(TRU type)
|
||||
{
|
||||
this.dataType = type;
|
||||
}
|
||||
|
||||
public Storable(RepresentationType type, SerializerFunction serializer, DeserializerFunction deserializer)
|
||||
public Storable(TRU type, SerializerFunction serializer, DeserializerFunction deserializer)
|
||||
{
|
||||
this.dataType = type;
|
||||
this.serializer = serializer;
|
||||
|
||||
@@ -11,7 +11,7 @@ public class ArgumentTemplate
|
||||
|
||||
public bool Optional { get; set; }
|
||||
|
||||
public RepresentationType Type { get; set; }
|
||||
public TRU Type { get; set; }
|
||||
|
||||
public ParameterInfo ParameterInfo { get; set; }
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ArgumentTemplate
|
||||
var cs = (uint)data[offset++];
|
||||
var name = data.GetString(offset, cs);
|
||||
offset += cs;
|
||||
var (size, type) = RepresentationType.Parse(data, offset);
|
||||
var (size, type) = TRU.Parse(data, offset);
|
||||
|
||||
return (cs + 2 + size, new ArgumentTemplate(name, index, type, optional));
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public class ArgumentTemplate
|
||||
|
||||
}
|
||||
|
||||
public ArgumentTemplate(string name, int index, RepresentationType type, bool optional)
|
||||
public ArgumentTemplate(string name, int index, TRU type, bool optional)
|
||||
{
|
||||
Name = name;
|
||||
Index = index;
|
||||
|
||||
@@ -12,11 +12,11 @@ public class ConstantTemplate : MemberTemplate
|
||||
public readonly object Value;
|
||||
//public readonly byte[] ValueData;
|
||||
public readonly string Annotation;
|
||||
public readonly RepresentationType ValueType;
|
||||
public readonly TRU ValueType;
|
||||
|
||||
public FieldInfo FieldInfo { get; set; }
|
||||
|
||||
public ConstantTemplate(TypeTemplate template, byte index, string name, bool inherited, RepresentationType valueType, object value, string annotation)
|
||||
public ConstantTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU valueType, object value, string annotation)
|
||||
: base(template, index, name, inherited)
|
||||
{
|
||||
Annotation = annotation;
|
||||
@@ -73,7 +73,7 @@ public class ConstantTemplate : MemberTemplate
|
||||
{
|
||||
var annotationAttr = ci.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
|
||||
var valueType = RepresentationType.FromType(ci.FieldType);
|
||||
var valueType = TRU.FromType(ci.FieldType);
|
||||
|
||||
if (valueType == null)
|
||||
throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`");
|
||||
|
||||
@@ -21,7 +21,7 @@ public class EventTemplate : MemberTemplate
|
||||
|
||||
public EventInfo EventInfo { get; set; }
|
||||
|
||||
public RepresentationType ArgumentType { get; set; }
|
||||
public TRU ArgumentType { get; set; }
|
||||
|
||||
public override byte[] Compose()
|
||||
{
|
||||
@@ -55,7 +55,7 @@ public class EventTemplate : MemberTemplate
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public EventTemplate(TypeTemplate template, byte index, string name, bool inherited, RepresentationType argumentType, string annotation = null, bool subscribable = false)
|
||||
public EventTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU argumentType, string annotation = null, bool subscribable = false)
|
||||
: base(template, index, name, inherited)
|
||||
{
|
||||
this.Annotation = annotation;
|
||||
@@ -75,7 +75,7 @@ public class EventTemplate : MemberTemplate
|
||||
|
||||
|
||||
var argType = ei.EventHandlerType.GenericTypeArguments[0];
|
||||
var evtType = RepresentationType.FromType(argType);
|
||||
var evtType = TRU.FromType(argType);
|
||||
|
||||
if (evtType == null)
|
||||
throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`");
|
||||
|
||||
@@ -25,7 +25,7 @@ public class FunctionTemplate : MemberTemplate
|
||||
// set;
|
||||
//}
|
||||
|
||||
public RepresentationType ReturnType { get; set; }
|
||||
public TRU ReturnType { get; set; }
|
||||
|
||||
public bool IsStatic { get; set; }
|
||||
|
||||
@@ -66,7 +66,7 @@ public class FunctionTemplate : MemberTemplate
|
||||
return bl.ToArray();
|
||||
}
|
||||
|
||||
public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, bool isStatic, ArgumentTemplate[] arguments, RepresentationType returnType, string annotation = null)
|
||||
public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, bool isStatic, ArgumentTemplate[] arguments, TRU returnType, string annotation = null)
|
||||
: base(template, index, name, inherited)
|
||||
{
|
||||
this.Arguments = arguments;
|
||||
@@ -82,20 +82,20 @@ public class FunctionTemplate : MemberTemplate
|
||||
|
||||
var genericRtType = mi.ReturnType.IsGenericType ? mi.ReturnType.GetGenericTypeDefinition() : null;
|
||||
|
||||
RepresentationType rtType;
|
||||
TRU rtType;
|
||||
|
||||
if (genericRtType == typeof(AsyncReply<>))
|
||||
{
|
||||
rtType = RepresentationType.FromType(mi.ReturnType.GetGenericArguments()[0]);
|
||||
rtType = TRU.FromType(mi.ReturnType.GetGenericArguments()[0]);
|
||||
}
|
||||
else if (genericRtType == typeof(IEnumerable<>))// || genericRtType == typeof(IAsyncEnumerable<>))
|
||||
{
|
||||
// get export
|
||||
rtType = RepresentationType.FromType(mi.ReturnType.GetGenericArguments()[0]);
|
||||
rtType = TRU.FromType(mi.ReturnType.GetGenericArguments()[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtType = RepresentationType.FromType(mi.ReturnType);
|
||||
rtType = TRU.FromType(mi.ReturnType);
|
||||
}
|
||||
|
||||
if (rtType == null)
|
||||
@@ -165,7 +165,7 @@ public class FunctionTemplate : MemberTemplate
|
||||
|
||||
var arguments = args.Select(x =>
|
||||
{
|
||||
var argType = RepresentationType.FromType(x.ParameterType);
|
||||
var argType = TRU.FromType(x.ParameterType);
|
||||
|
||||
if (argType == null)
|
||||
throw new Exception($"Unsupported type `{x.ParameterType}` in method `{type.Name}.{mi.Name}` parameter `{x.Name}`");
|
||||
|
||||
@@ -25,7 +25,7 @@ public class PropertyTemplate : MemberTemplate
|
||||
set;
|
||||
}
|
||||
|
||||
public RepresentationType ValueType { get; set; }
|
||||
public TRU ValueType { get; set; }
|
||||
|
||||
|
||||
/*
|
||||
@@ -136,7 +136,7 @@ public class PropertyTemplate : MemberTemplate
|
||||
}
|
||||
|
||||
public PropertyTemplate(TypeTemplate template, byte index, string name, bool inherited,
|
||||
RepresentationType valueType, string readAnnotation = null, string writeAnnotation = null, bool recordable = false)
|
||||
TRU valueType, string readAnnotation = null, string writeAnnotation = null, bool recordable = false)
|
||||
: base(template, index, name, inherited)
|
||||
{
|
||||
this.Recordable = recordable;
|
||||
@@ -152,8 +152,8 @@ public class PropertyTemplate : MemberTemplate
|
||||
var genericPropType = pi.PropertyType.IsGenericType ? pi.PropertyType.GetGenericTypeDefinition() : null;
|
||||
|
||||
var propType = genericPropType == typeof(PropertyContext<>) ?
|
||||
RepresentationType.FromType(pi.PropertyType.GetGenericArguments()[0]) :
|
||||
RepresentationType.FromType(pi.PropertyType);
|
||||
TRU.FromType(pi.PropertyType.GetGenericArguments()[0]) :
|
||||
TRU.FromType(pi.PropertyType);
|
||||
|
||||
if (propType == null)
|
||||
throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`");
|
||||
|
||||
@@ -380,7 +380,7 @@ public class TypeTemplate
|
||||
{
|
||||
var annotationAttr = ci.GetCustomAttribute<AnnotationAttribute>(true);
|
||||
|
||||
var valueType = RepresentationType.FromType(ci.FieldType);
|
||||
var valueType = TRU.FromType(ci.FieldType);
|
||||
|
||||
if (valueType == null)
|
||||
throw new Exception($"Unsupported type `{ci.FieldType}` in constant `{type.Name}.{ci.Name}`");
|
||||
@@ -783,7 +783,7 @@ public class TypeTemplate
|
||||
offset += (uint)data[offset] + 1;
|
||||
|
||||
// return type
|
||||
var (rts, returnType) = RepresentationType.Parse(data, offset);
|
||||
var (rts, returnType) = TRU.Parse(data, offset);
|
||||
offset += rts;
|
||||
|
||||
// arguments count
|
||||
@@ -823,7 +823,7 @@ public class TypeTemplate
|
||||
|
||||
offset += (uint)data[offset] + 1;
|
||||
|
||||
var (dts, valueType) = RepresentationType.Parse(data, offset);
|
||||
var (dts, valueType) = TRU.Parse(data, offset);
|
||||
|
||||
offset += dts;
|
||||
|
||||
@@ -857,7 +857,7 @@ public class TypeTemplate
|
||||
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
|
||||
offset += (uint)data[offset] + 1;
|
||||
|
||||
var (dts, argType) = RepresentationType.Parse(data, offset);
|
||||
var (dts, argType) = TRU.Parse(data, offset);
|
||||
|
||||
offset += dts;
|
||||
|
||||
@@ -883,7 +883,7 @@ public class TypeTemplate
|
||||
var name = data.GetString(offset + 1, data[offset]);
|
||||
offset += (uint)data[offset] + 1;
|
||||
|
||||
var (dts, valueType) = RepresentationType.Parse(data, offset);
|
||||
var (dts, valueType) = TRU.Parse(data, offset);
|
||||
|
||||
offset += dts;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user