From 746f12320eeeb1e693e0ab24b099a443099b23e8 Mon Sep 17 00:00:00 2001 From: ahmed Date: Thu, 30 Oct 2025 12:45:29 +0300 Subject: [PATCH] Pull Stream --- Esiur/Data/Codec.cs | 6 +- Esiur/Data/DataConverter.cs | 4 + Esiur/Data/DataDeserializer.cs | 212 ++++---- Esiur/Data/DataSerializer.cs | 120 ++++- Esiur/Data/GVWIE/GroupInt16Codec.cs | 137 +++++ Esiur/Data/GVWIE/GroupInt32Codec.cs | 129 +++++ Esiur/Data/GVWIE/GroupInt64Codec.cs | 135 +++++ Esiur/Data/GVWIE/GroupUInt16Codec.cs | 121 +++++ Esiur/Data/GVWIE/GroupUInt32Codec.cs | 125 +++++ Esiur/Data/GVWIE/GroupUInt64Codec.cs | 132 +++++ Esiur/Data/RepresentationType.cs | 536 -------------------- Esiur/Data/TDU.cs | 6 +- Esiur/Data/TDUIdentifier.cs | 2 +- Esiur/Data/TRU.cs | 502 ++++++++++++++++++ Esiur/Data/TRUIdentifier.cs | 46 ++ Esiur/Net/Packets/IIPPacketReply.cs | 1 + Esiur/Net/Packets/IIPPacketRequest.cs | 7 +- Esiur/Proxy/TemplateGenerator.cs | 64 +-- Esiur/Resource/Storable.cs | 6 +- Esiur/Resource/Template/ArgumentTemplate.cs | 6 +- Esiur/Resource/Template/ConstantTemplate.cs | 6 +- Esiur/Resource/Template/EventTemplate.cs | 6 +- Esiur/Resource/Template/FunctionTemplate.cs | 14 +- Esiur/Resource/Template/PropertyTemplate.cs | 8 +- Esiur/Resource/Template/TypeTemplate.cs | 10 +- 25 files changed, 1637 insertions(+), 704 deletions(-) create mode 100644 Esiur/Data/GVWIE/GroupInt16Codec.cs create mode 100644 Esiur/Data/GVWIE/GroupInt32Codec.cs create mode 100644 Esiur/Data/GVWIE/GroupInt64Codec.cs create mode 100644 Esiur/Data/GVWIE/GroupUInt16Codec.cs create mode 100644 Esiur/Data/GVWIE/GroupUInt32Codec.cs create mode 100644 Esiur/Data/GVWIE/GroupUInt64Codec.cs delete mode 100644 Esiur/Data/RepresentationType.cs create mode 100644 Esiur/Data/TRU.cs create mode 100644 Esiur/Data/TRUIdentifier.cs diff --git a/Esiur/Data/Codec.cs b/Esiur/Data/Codec.cs index fec47bf..ff7ac81 100644 --- a/Esiur/Data/Codec.cs +++ b/Esiur/Data/Codec.cs @@ -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); } diff --git a/Esiur/Data/DataConverter.cs b/Esiur/Data/DataConverter.cs index 92cec05..dfa3b23 100644 --- a/Esiur/Data/DataConverter.cs +++ b/Esiur/Data/DataConverter.cs @@ -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) diff --git a/Esiur/Data/DataDeserializer.cs b/Esiur/Data/DataDeserializer.cs index f0a7b5c..51d6b95 100644 --- a/Esiur/Data/DataDeserializer.cs +++ b/Esiur/Data/DataDeserializer.cs @@ -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(); - // 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(); - 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(); - - 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(); - 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 PropertyValueArrayParserAsync(byte[] data, uint offset, uint length, DistributedConnection connection, uint[] requestSequence)//, bool ageIncluded = true) diff --git a/Esiur/Data/DataSerializer.cs b/Esiur/Data/DataSerializer.cs index 60bb72b..4787a6e 100644 --- a/Esiur/Data/DataSerializer.cs +++ b/Esiur/Data/DataSerializer.cs @@ -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)value); + } + else if (type == typeof(long)) + { + composed = GroupInt64Codec.Encode((IList)value); + } + else if (type == typeof(short)) + { + composed = GroupInt16Codec.Encode((IList)value); + } + else if (type == typeof(uint)) + { + composed = GroupUInt32Codec.Encode((IList)value); + } + else if (type == typeof(ulong)) + { + composed = GroupUInt64Codec.Encode((IList)value); + } + else if (type == typeof(ushort)) + { + composed = GroupUInt16Codec.Encode((IList)value); + } + else + { + var rt = new List(); + + 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(); @@ -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(); @@ -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 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(); diff --git a/Esiur/Data/GVWIE/GroupInt16Codec.cs b/Esiur/Data/GVWIE/GroupInt16Codec.cs new file mode 100644 index 0000000..b173137 --- /dev/null +++ b/Esiur/Data/GVWIE/GroupInt16Codec.cs @@ -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 values) + { + var dst = new List(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 src) + { + var result = new List(); + 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 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 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; + } +} diff --git a/Esiur/Data/GVWIE/GroupInt32Codec.cs b/Esiur/Data/GVWIE/GroupInt32Codec.cs new file mode 100644 index 0000000..36f0648 --- /dev/null +++ b/Esiur/Data/GVWIE/GroupInt32Codec.cs @@ -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 values) + { + //var values = value as int[]; + + var dst = new List(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 src) + { + var result = new List(); + 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 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 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; + } +} diff --git a/Esiur/Data/GVWIE/GroupInt64Codec.cs b/Esiur/Data/GVWIE/GroupInt64Codec.cs new file mode 100644 index 0000000..ae585f6 --- /dev/null +++ b/Esiur/Data/GVWIE/GroupInt64Codec.cs @@ -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 values) + { + var dst = new List(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 src) + { + var result = new List(); + 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 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 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; + } +} diff --git a/Esiur/Data/GVWIE/GroupUInt16Codec.cs b/Esiur/Data/GVWIE/GroupUInt16Codec.cs new file mode 100644 index 0000000..63973ba --- /dev/null +++ b/Esiur/Data/GVWIE/GroupUInt16Codec.cs @@ -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 values) + { + if (values is null) throw new ArgumentNullException(nameof(values)); + + var dst = new List(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 src) + { + var result = new List(); + 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 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 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; + } +} diff --git a/Esiur/Data/GVWIE/GroupUInt32Codec.cs b/Esiur/Data/GVWIE/GroupUInt32Codec.cs new file mode 100644 index 0000000..9b26a24 --- /dev/null +++ b/Esiur/Data/GVWIE/GroupUInt32Codec.cs @@ -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 values) + { + if (values is null) throw new ArgumentNullException(nameof(values)); + + var dst = new List(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 src) + { + var result = new List(); + 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 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 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; + } +} diff --git a/Esiur/Data/GVWIE/GroupUInt64Codec.cs b/Esiur/Data/GVWIE/GroupUInt64Codec.cs new file mode 100644 index 0000000..1e4506c --- /dev/null +++ b/Esiur/Data/GVWIE/GroupUInt64Codec.cs @@ -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 values) + { + if (values is null) throw new ArgumentNullException(nameof(values)); + + var dst = new List(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 src) + { + var result = new List(); + 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 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 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; + } +} diff --git a/Esiur/Data/RepresentationType.cs b/Esiur/Data/RepresentationType.cs deleted file mode 100644 index c95be52..0000000 --- a/Esiur/Data/RepresentationType.cs +++ /dev/null @@ -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 typesMap = new Map() - { - [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 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 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) - || type == typeof(Dictionary)) - 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)); - } - } - - } -} \ No newline at end of file diff --git a/Esiur/Data/TDU.cs b/Esiur/Data/TDU.cs index 08bd9ec..0ffcdf5 100644 --- a/Esiur/Data/TDU.cs +++ b/Esiur/Data/TDU.cs @@ -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) diff --git a/Esiur/Data/TDUIdentifier.cs b/Esiur/Data/TDUIdentifier.cs index d999735..b170978 100644 --- a/Esiur/Data/TDUIdentifier.cs +++ b/Esiur/Data/TDUIdentifier.cs @@ -58,7 +58,7 @@ namespace Esiur.Data TypedConstant = 0x85, TypeContinuation = 0xC0, - + TypeOfTarget = 0xC1, } } diff --git a/Esiur/Data/TRU.cs b/Esiur/Data/TRU.cs new file mode 100644 index 0000000..ceb5de5 --- /dev/null +++ b/Esiur/Data/TRU.cs @@ -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 typesMap = new Map() + { + [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 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 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) + || type == typeof(Dictionary)) + 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)); + } + } + + } +} \ No newline at end of file diff --git a/Esiur/Data/TRUIdentifier.cs b/Esiur/Data/TRUIdentifier.cs new file mode 100644 index 0000000..588629f --- /dev/null +++ b/Esiur/Data/TRUIdentifier.cs @@ -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 + } + +} diff --git a/Esiur/Net/Packets/IIPPacketReply.cs b/Esiur/Net/Packets/IIPPacketReply.cs index 0827d29..7518b61 100644 --- a/Esiur/Net/Packets/IIPPacketReply.cs +++ b/Esiur/Net/Packets/IIPPacketReply.cs @@ -9,6 +9,7 @@ namespace Esiur.Net.Packets // Success Completed = 0x0, Propagated = 0x1, + Stream = 0x2, // Error PermissionError = 0x81, diff --git a/Esiur/Net/Packets/IIPPacketRequest.cs b/Esiur/Net/Packets/IIPPacketRequest.cs index c706aa3..306a67b 100644 --- a/Esiur/Net/Packets/IIPPacketRequest.cs +++ b/Esiur/Net/Packets/IIPPacketRequest.cs @@ -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, + } } diff --git a/Esiur/Proxy/TemplateGenerator.cs b/Esiur/Proxy/TemplateGenerator.cs index b36f549..894f14d 100644 --- a/Esiur/Proxy/TemplateGenerator.cs +++ b/Esiur/Proxy/TemplateGenerator.cs @@ -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", - 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", + TRUIdentifier.UInt16 => "ushort", + TRUIdentifier.UInt32 => "uint", + TRUIdentifier.UInt64 => "ulong", + TRUIdentifier.UInt8 => "byte", + TRUIdentifier.List => "object[]", + TRUIdentifier.Resource => "IResource", + TRUIdentifier.Record => "IRecord", _ => "object" }; } diff --git a/Esiur/Resource/Storable.cs b/Esiur/Resource/Storable.cs index 7e7216d..c91c9aa 100644 --- a/Esiur/Resource/Storable.cs +++ b/Esiur/Resource/Storable.cs @@ -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; diff --git a/Esiur/Resource/Template/ArgumentTemplate.cs b/Esiur/Resource/Template/ArgumentTemplate.cs index b3e4f2c..e0367a0 100644 --- a/Esiur/Resource/Template/ArgumentTemplate.cs +++ b/Esiur/Resource/Template/ArgumentTemplate.cs @@ -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; diff --git a/Esiur/Resource/Template/ConstantTemplate.cs b/Esiur/Resource/Template/ConstantTemplate.cs index eb9ec31..6e876d3 100644 --- a/Esiur/Resource/Template/ConstantTemplate.cs +++ b/Esiur/Resource/Template/ConstantTemplate.cs @@ -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(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}`"); diff --git a/Esiur/Resource/Template/EventTemplate.cs b/Esiur/Resource/Template/EventTemplate.cs index 6a0e0a6..b782997 100644 --- a/Esiur/Resource/Template/EventTemplate.cs +++ b/Esiur/Resource/Template/EventTemplate.cs @@ -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}`"); diff --git a/Esiur/Resource/Template/FunctionTemplate.cs b/Esiur/Resource/Template/FunctionTemplate.cs index 04bcba7..0858265 100644 --- a/Esiur/Resource/Template/FunctionTemplate.cs +++ b/Esiur/Resource/Template/FunctionTemplate.cs @@ -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}`"); diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs index ac73361..c7a4855 100644 --- a/Esiur/Resource/Template/PropertyTemplate.cs +++ b/Esiur/Resource/Template/PropertyTemplate.cs @@ -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}`"); diff --git a/Esiur/Resource/Template/TypeTemplate.cs b/Esiur/Resource/Template/TypeTemplate.cs index 39a0945..95176de 100644 --- a/Esiur/Resource/Template/TypeTemplate.cs +++ b/Esiur/Resource/Template/TypeTemplate.cs @@ -380,7 +380,7 @@ public class TypeTemplate { var annotationAttr = ci.GetCustomAttribute(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;