2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-10-29 07:10:29 +00:00
This commit is contained in:
2025-10-15 17:34:18 +03:00
parent 9386cc7a84
commit a63a9b5511
11 changed files with 477 additions and 172 deletions

View File

@@ -189,42 +189,53 @@ public static class Codec
/// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end.</param> /// <param name="connection">DistributedConnection is required in case a structure in the array holds items at the other end.</param>
/// <param name="dataType">DataType, in case the data is not prepended with DataType</param> /// <param name="dataType">DataType, in case the data is not prepended with DataType</param>
/// <returns>Value</returns> /// <returns>Value</returns>
public static (uint, object) ParseAsync(byte[] data, uint offset, DistributedConnection connection, uint[] requestSequence, ParsedTDU? dataType = null) public static (uint, object) ParseAsync(byte[] data, uint offset, DistributedConnection connection, uint[] requestSequence)
{ {
uint len = 0;
if (dataType == null) var tdu = ParsedTDU.Parse(data, offset, (uint)data.Length);
if (tdu.Class == TDUClass.Invalid)
throw new NullReferenceException("DataType can't be parsed.");
if (tdu.Class == TDUClass.Fixed)
{ {
(var longLen, dataType) = ParsedTDU.Parse(data, offset, (uint)data.Length); return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence));
if (dataType == null)
throw new NullReferenceException("DataType can't be parsed.");
len = (uint)longLen;
offset = dataType.Value.Offset;
} }
else else if (tdu.Class == TDUClass.Dynamic)
len = (uint)dataType.Value.ContentLength;
var tt = dataType.Value;
//Console.WriteLine("Parsing " + tt.Class + " " + tt.Identifier);
if (tt.Class == TDUClass.Fixed)
{ {
return (len, FixedAsyncParsers[tt.Exponent][tt.Index](tt, connection, requestSequence)); return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence));
} }
else if (tt.Class == TDUClass.Dynamic) else if (tdu.Class == TDUClass.Typed)
{ {
return (len, DynamicAsyncParsers[tt.Index](tt, connection, requestSequence)); return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
} }
else if (tt.Class == TDUClass.Typed) else // if (tt.Class == TDUClass.Extension)
{ {
return (len, TypedAsyncParsers[tt.Index](tt, connection, requestSequence)); return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
} }
else if (tt.Class == TDUClass.Extension) }
public static (uint, object) ParseAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence)
{
if (tdu.Class == TDUClass.Invalid)
throw new NullReferenceException("DataType can't be parsed.");
if (tdu.Class == TDUClass.Fixed)
{ {
return (len, ExtendedAsyncParsers[tt.Index](tt, connection, requestSequence)); return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence));
}
else if (tdu.Class == TDUClass.Dynamic)
{
return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence));
}
else if (tdu.Class == TDUClass.Typed)
{
return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
}
else // if (tt.Class == TDUClass.Extension)
{
return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence));
} }
} }
@@ -252,34 +263,27 @@ public static class Codec
public static (uint, object) ParseSync(byte[] data, uint offset, Warehouse warehouse) public static (uint, object) ParseSync(byte[] data, uint offset, Warehouse warehouse)
{ {
uint len = 0; var tdu = ParsedTDU.Parse(data, offset, (uint)data.Length);
if (tdu.Class == TDUClass.Invalid)
var (longLen, dataType) = ParsedTDU.Parse(data, offset, (uint)data.Length);
if (dataType == null)
throw new NullReferenceException("DataType can't be parsed."); throw new NullReferenceException("DataType can't be parsed.");
len = (uint)longLen;
offset = dataType.Value.Offset;
var tt = dataType.Value; if (tdu.Class == TDUClass.Fixed)
if (tt.Class == TDUClass.Fixed)
{ {
return (len, FixedParsers[tt.Exponent][tt.Index](tt, warehouse)); return ((uint)tdu.TotalLength, FixedParsers[tdu.Exponent][tdu.Index](tdu, warehouse));
} }
else if (tt.Class == TDUClass.Dynamic) else if (tdu.Class == TDUClass.Dynamic)
{ {
return (len, DynamicParsers[tt.Index](tt, warehouse)); return ((uint)tdu.TotalLength, DynamicParsers[tdu.Index](tdu, warehouse));
} }
else if (tt.Class == TDUClass.Typed) else if (tdu.Class == TDUClass.Typed)
{ {
return (len, TypedParsers[tt.Index](tt, warehouse)); return ((uint)tdu.TotalLength, TypedParsers[tdu.Index](tdu, warehouse));
} }
else else
{ {
return (len, ExtendedParsers[tt.Index](tt, warehouse)); return ((uint)tdu.TotalLength, ExtendedParsers[tdu.Index](tdu, warehouse));
} }
} }
/// <summary> /// <summary>
@@ -326,8 +330,8 @@ public static class Codec
[typeof(float?)] = DataSerializer.Float32Composer, [typeof(float?)] = DataSerializer.Float32Composer,
[typeof(long)] = DataSerializer.Int64Composer, [typeof(long)] = DataSerializer.Int64Composer,
[typeof(long?)] = DataSerializer.Int64Composer, [typeof(long?)] = DataSerializer.Int64Composer,
[typeof(ulong)] = DataSerializer.UIn64Composer, [typeof(ulong)] = DataSerializer.UInt64Composer,
[typeof(ulong?)] = DataSerializer.UIn64Composer, [typeof(ulong?)] = DataSerializer.UInt64Composer,
[typeof(double)] = DataSerializer.Float64Composer, [typeof(double)] = DataSerializer.Float64Composer,
[typeof(double?)] = DataSerializer.Float64Composer, [typeof(double?)] = DataSerializer.Float64Composer,
[typeof(DateTime)] = DataSerializer.DateTimeComposer, [typeof(DateTime)] = DataSerializer.DateTimeComposer,

View File

@@ -450,7 +450,7 @@ public static class DataDeserializer
{ {
var classId = tdu.Metadata.GetUUID(0); var classId = tdu.Metadata.GetUUID(0);
var template = warehouse.GetTemplateByClassId(classId, TemplateType.Record); var template = warehouse.GetTemplateByClassId(classId, TemplateType.Record);
@@ -535,7 +535,7 @@ public static class DataDeserializer
{ {
var classId = tdu.Metadata.GetUUID(0); var classId = tdu.Metadata.GetUUID(0);
var index = tdu.Data[tdu.Offset]; var index = tdu.Data[tdu.Offset];
var template = warehouse.GetTemplateByClassId(classId, TemplateType.Enum); var template = warehouse.GetTemplateByClassId(classId, TemplateType.Enum);
@@ -794,7 +794,7 @@ public static class DataDeserializer
var (keyCs, keyRepType) = RepresentationType.Parse(tdu.Metadata, 0); var (keyCs, keyRepType) = RepresentationType.Parse(tdu.Metadata, 0);
var (valueCs, valueRepType) = RepresentationType.Parse(tdu.Metadata, keyCs); var (valueCs, valueRepType) = RepresentationType.Parse(tdu.Metadata, keyCs);
var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType(keyRepType.GetRuntimeType(warehouse), valueRepType.GetRuntimeType(warehouse))); var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType(keyRepType.GetRuntimeType(warehouse), valueRepType.GetRuntimeType(warehouse)));
@@ -828,8 +828,9 @@ public static class DataDeserializer
public static AsyncReply TupleParserAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence) public static AsyncReply TupleParserAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence)
{ {
var rt = new AsyncReply();
var results = new List<object>(); var results = new AsyncBag<object>();
var tupleSize = tdu.Metadata[0]; var tupleSize = tdu.Metadata[0];
var types = new List<Type>(); var types = new List<Type>();
@@ -919,7 +920,7 @@ public static class DataDeserializer
var length = tdu.ContentLength; var length = tdu.ContentLength;
var offset = tdu.Offset; var offset = tdu.Offset;
while (length > 0) while (length > 0)
{ {
var (cs, reply) = Codec.ParseSync(tdu.Data, offset, warehouse); var (cs, reply) = Codec.ParseSync(tdu.Data, offset, warehouse);
@@ -977,20 +978,37 @@ public static class DataDeserializer
var rt = new AsyncBag<object>(); var rt = new AsyncBag<object>();
// get the type // get the type
var (hdrCs, rep) = RepresentationType.Parse(data, offset); var (hdrCs, rep) = RepresentationType.Parse(tdu.Metadata, 0);
offset += hdrCs;
length -= hdrCs;
var runtimeType = rep.GetRuntimeType(connection.Instance.Warehouse); var runtimeType = rep.GetRuntimeType(connection.Instance.Warehouse);
rt.ArrayType = runtimeType; rt.ArrayType = runtimeType;
ParsedTDU current;
ParsedTDU? previous = null;
var offset = tdu.Offset;
var length = tdu.ContentLength;
var ends = offset + (uint)length;
while (length > 0) while (length > 0)
{ {
var (cs, reply) = Codec.ParseAsync(data, offset, connection, requestSequence);
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.ParseAsync(tdu.Data, offset, connection, requestSequence);
rt.Add(reply); rt.Add(reply);
@@ -1021,7 +1039,7 @@ public static class DataDeserializer
var list = new List<object>(); var list = new List<object>();
ParsedTDU? current; ParsedTDU current;
ParsedTDU? previous = null; ParsedTDU? previous = null;
var offset = tdu.Offset; var offset = tdu.Offset;
@@ -1030,21 +1048,20 @@ public static class DataDeserializer
while (length > 0) while (length > 0)
{ {
(var longLen, current) = ParsedTDU.Parse(tdu.Data, offset, ends); current = ParsedTDU.Parse(tdu.Data, offset, ends);
if (current == null) if (current.Class == TDUClass.Invalid)
throw new Exception("Unknown type."); throw new Exception("Unknown type.");
var cur = (ParsedTDU)current.Value;
if (cur.Identifier == TDUIdentifier.TypeContinuation) if (current.Identifier == TDUIdentifier.TypeContinuation)
{ {
cur.Class = previous.Value.Class; current.Class = previous.Value.Class;
cur.Identifier = previous.Value.Identifier; current.Identifier = previous.Value.Identifier;
cur.Metadata = previous.Value.Metadata; current.Metadata = previous.Value.Metadata;
} }
var (cs, reply) = Codec.ParseSync(cur, warehouse); var (cs, reply) = Codec.ParseSync(current, warehouse);
list.Add(reply); list.Add(reply);
@@ -1052,7 +1069,7 @@ public static class DataDeserializer
{ {
offset += (uint)cs; offset += (uint)cs;
length -= (uint)cs; length -= (uint)cs;
previous = cur; previous = current;
} }
else else
throw new Exception("Error while parsing structured data"); throw new Exception("Error while parsing structured data");
@@ -1061,7 +1078,7 @@ public static class DataDeserializer
var rt = Array.CreateInstance(runtimeType, list.Count); var rt = Array.CreateInstance(runtimeType, list.Count);
Array.Copy(list.ToArray(), rt, rt.Length); Array.Copy(list.ToArray(), rt, rt.Length);
return rt; return rt;
} }
@@ -1070,7 +1087,8 @@ public static class DataDeserializer
var rt = new AsyncBag<PropertyValue>(); var rt = new AsyncBag<PropertyValue>();
ListParserAsync(data, offset, length, connection, requestSequence).Then(x => ListParserAsync(new ParsedTDU() { Data = data, Offset = offset, ContentLength = length }
, connection, requestSequence).Then(x =>
{ {
var ar = (object[])x; var ar = (object[])x;
var pvs = new List<PropertyValue>(); var pvs = new List<PropertyValue>();

View File

@@ -3,6 +3,7 @@ using Esiur.Net.IIP;
using Esiur.Resource; using Esiur.Resource;
using Esiur.Resource.Template; using Esiur.Resource.Template;
using System; using System;
using System.Buffers.Binary;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -17,77 +18,271 @@ public static class DataSerializer
public static unsafe TDU Int32Composer(object value, Warehouse warehouse, DistributedConnection connection) public static unsafe TDU Int32Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (int)value; var v = (int)value;
var rt = new byte[4];
fixed (byte* ptr = rt) if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
*((int*)ptr) = v; {
return new TDU(TDUIdentifier.Int32, rt, 4); return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
}
else if (v >= short.MinValue && v <= short.MaxValue)
{
// Fits in 2 bytes
var rt = new byte[2];
fixed (byte* ptr = rt)
*((short*)ptr) = (short)v;
return new TDU(TDUIdentifier.Int16, rt, 2);
}
else
{
// Use full 4 bytes
var rt = new byte[4];
fixed (byte* ptr = rt)
*((int*)ptr) = v;
return new TDU(TDUIdentifier.Int32, rt, 4);
}
} }
public static unsafe TDU UInt32Composer(object value, Warehouse warehouse, DistributedConnection connection) public static unsafe TDU UInt32Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (uint)value; var v = (uint)value;
var rt = new byte[4];
fixed (byte* ptr = rt)
*((uint*)ptr) = v;
return new TDU(TDUIdentifier.UInt32, rt, 4); if (v <= byte.MaxValue)
{
// Fits in 1 byte
return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1);
}
else if (v <= ushort.MaxValue)
{
// Fits in 2 bytes
var rt = new byte[2];
fixed (byte* ptr = rt)
*((ushort*)ptr) = (ushort)v;
return new TDU(TDUIdentifier.UInt16, rt, 2);
}
else
{
// Use full 4 bytes
var rt = new byte[4];
fixed (byte* ptr = rt)
*((uint*)ptr) = v;
return new TDU(TDUIdentifier.UInt32, rt, 4);
}
} }
public static unsafe TDU Int16Composer(object value, Warehouse warehouse, DistributedConnection connection) public static unsafe TDU Int16Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (short)value; var v = (short)value;
var rt = new byte[2];
fixed (byte* ptr = rt)
*((short*)ptr) = v;
return new TDU(TDUIdentifier.Int16, rt, 2); if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
{
// Fits in 1 byte
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
}
else
{
// Use full 2 bytes
var rt = new byte[2];
fixed (byte* ptr = rt)
*((short*)ptr) = v;
return new TDU(TDUIdentifier.Int16, rt, 2);
}
} }
public static unsafe TDU UInt16Composer(object value, Warehouse warehouse, DistributedConnection connection) public static unsafe TDU UInt16Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (ushort)value; var v = (ushort)value;
var rt = new byte[2];
fixed (byte* ptr = rt)
*((ushort*)ptr) = v;
return new TDU(TDUIdentifier.UInt16, rt, 2); if (v <= byte.MaxValue)
{
// Fits in 1 byte
return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1);
}
else
{
// Use full 2 bytes
var rt = new byte[2];
fixed (byte* ptr = rt)
*((ushort*)ptr) = v;
return new TDU(TDUIdentifier.UInt16, rt, 2);
}
} }
public static unsafe TDU Float32Composer(object value, Warehouse warehouse, DistributedConnection connection)
public static unsafe TDU Float32Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (float)value; float v = (float)value;
var rt = new byte[4];
fixed (byte* ptr = rt) // Special IEEE-754 values
*((float*)ptr) = v; if (float.IsNaN(v) || float.IsInfinity(v))
return new TDU(TDUIdentifier.Float32, rt, 4); {
return new TDU(TDUIdentifier.Infinity, new byte[0], 0);
}
// If v is an exact integer, prefer smallest signed width up to Int32
if (v == Math.Truncate(v))
{
// Note: casts are safe because we check bounds first.
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
{
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
}
if (v >= short.MinValue && v <= short.MaxValue)
{
var rt = new byte[2];
fixed (byte* ptr = rt)
*((short*)ptr) = (short)v;
return new TDU(TDUIdentifier.Int16, rt, 2);
}
}
// Default: Float32
{
var rt = new byte[4];
fixed (byte* ptr = rt)
*((float*)ptr) = v;
return new TDU(TDUIdentifier.Float32, rt, 4);
}
} }
public static unsafe TDU Float64Composer(object value, Warehouse warehouse, DistributedConnection connection)
public unsafe static TDU Float64Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (double)value; double v = (double)value;
var rt = new byte[8];
fixed (byte* ptr = rt)
*((double*)ptr) = v;
return new TDU(TDUIdentifier.Float64, rt, 8);
}
// Special IEEE-754 values
if (double.IsNaN(v) || double.IsInfinity(v))
{
return new TDU(TDUIdentifier.Infinity, new byte[0], 0);
}
// If v is an exact integer, choose the smallest signed width
if (v == Math.Truncate(v))
{
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
if (v >= short.MinValue && v <= short.MaxValue)
{
var rt = new byte[2];
fixed (byte* ptr = rt)
*((short*)ptr) = (short)v;
return new TDU(TDUIdentifier.Int16, rt, 2);
}
if (v >= int.MinValue && v <= int.MaxValue)
{
var rt = new byte[4];
fixed (byte* ptr = rt)
*((int*)ptr) = (int)v;
return new TDU(TDUIdentifier.Int32, rt, 4);
}
// If it's integral but outside Int64 range, fall through to Float64.
}
// Try exact Float32 (decimal subset of doubles)
var f = (float)v;
if ((double)f == v)
{
var rt = new byte[4];
fixed (byte* ptr = rt)
*((float*)ptr) = (byte)v;
return new TDU(TDUIdentifier.Float32, rt, 4);
}
// Default: Float64
{
var rt = new byte[8];
fixed (byte* ptr = rt)
*((double*)ptr) = v;
return new TDU(TDUIdentifier.Float64, rt, 8);
}
}
public static unsafe TDU Int64Composer(object value, Warehouse warehouse, DistributedConnection connection) public static unsafe TDU Int64Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (long)value; var v = (long)value;
var rt = new byte[8];
fixed (byte* ptr = rt) if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
*((long*)ptr) = v; {
return new TDU(TDUIdentifier.Int64, rt, 8); // Fits in 1 byte
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
}
else if (v >= short.MinValue && v <= short.MaxValue)
{
// Fits in 2 bytes
var rt = new byte[2];
fixed (byte* ptr = rt)
*((short*)ptr) = (short)v;
return new TDU(TDUIdentifier.Int16, rt, 2);
}
else if (v >= int.MinValue && v <= int.MaxValue)
{
// Fits in 4 bytes
var rt = new byte[4];
fixed (byte* ptr = rt)
*((int*)ptr) = (int)v;
return new TDU(TDUIdentifier.Int32, rt, 4);
}
else
{
// Use full 8 bytes
var rt = new byte[8];
fixed (byte* ptr = rt)
*((long*)ptr) = v;
return new TDU(TDUIdentifier.Int64, rt, 8);
}
} }
public static unsafe TDU UIn64Composer(object value, Warehouse warehouse, DistributedConnection connection) public static unsafe TDU UInt64Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (ulong)value; var v = (ulong)value;
var rt = new byte[8];
fixed (byte* ptr = rt) if (v <= byte.MaxValue)
*((ulong*)ptr) = v; {
return new TDU(TDUIdentifier.UInt64, rt, 8); // Fits in 1 byte
return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1);
}
else if (v <= ushort.MaxValue)
{
// Fits in 2 bytes
var rt = new byte[2];
fixed (byte* ptr = rt)
*((ushort*)ptr) = (ushort)v;
return new TDU(TDUIdentifier.UInt16, rt, 2);
}
else if (v <= uint.MaxValue)
{
// Fits in 4 bytes
var rt = new byte[4];
fixed (byte* ptr = rt)
*((uint*)ptr) = (uint)v;
return new TDU(TDUIdentifier.UInt32, rt, 4);
}
else
{
// Use full 8 bytes
var rt = new byte[8];
fixed (byte* ptr = rt)
*((ulong*)ptr) = v;
return new TDU(TDUIdentifier.UInt64, rt, 8);
}
} }
@@ -101,18 +296,89 @@ public static class DataSerializer
return new TDU(TDUIdentifier.DateTime, rt, 8); return new TDU(TDUIdentifier.DateTime, rt, 8);
} }
//public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, DistributedConnection connection)
//{
// var v = (decimal)value;
// var rt = new byte[16];
// fixed (byte* ptr = rt)
// *((decimal*)ptr) = v;
// return new TDU(TDUIdentifier.Decimal128, rt, 16);
//}
public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, DistributedConnection connection) public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var v = (decimal)value; var v = (decimal)value;
var rt = new byte[16];
fixed (byte* ptr = rt)
*((decimal*)ptr) = v;
return new TDU(TDUIdentifier.Decimal128, rt, 16); // Prefer smallest exact signed integer if no fractional part
int[] bits = decimal.GetBits(v);
int flags = bits[3];
int scale = (flags >> 16) & 0x7F;
if (scale == 0)
{
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1);
if (v >= short.MinValue && v <= short.MaxValue)
{
var b = new byte[2];
BinaryPrimitives.WriteInt16LittleEndian(b, (short)v);
return new TDU(TDUIdentifier.Int16, b, 2);
}
if (v >= int.MinValue && v <= int.MaxValue)
{
var b = new byte[4];
BinaryPrimitives.WriteInt32LittleEndian(b, (int)v);
return new TDU(TDUIdentifier.Int32, b, 4);
}
if (v >= long.MinValue && v <= long.MaxValue)
{
var b = new byte[8];
BinaryPrimitives.WriteInt64LittleEndian(b, (long)v);
return new TDU(TDUIdentifier.Int64, b, 8);
}
// else fall through (needs 96+ bits)
}
// Try exact Float32 (4 bytes)
// Exactness test: decimal -> float -> decimal must equal original
float f = (float)v;
if ((decimal)f == v)
{
var rt = new byte[4];
fixed (byte* ptr = rt)
*((float*)ptr) = f;
return new TDU(TDUIdentifier.Float32, rt, 4);
}
// Try exact Float64 (8 bytes)
double d = (double)v;
if ((decimal)d == v)
{
var rt = new byte[4];
fixed (byte* ptr = rt)
*((double*)ptr) = d;
return new TDU(TDUIdentifier.Float64, rt, 8);
}
{
// Fallback: full .NET decimal (16 bytes): lo, mid, hi, flags (scale/sign)
var rt = new byte[16];
fixed (byte* ptr = rt)
*((decimal*)ptr) = v;
return new TDU(TDUIdentifier.Decimal128, rt, 16);
}
} }
public static TDU StringComposer(object value, Warehouse warehouse, DistributedConnection connection) public static TDU StringComposer(object value, Warehouse warehouse, DistributedConnection connection)
{ {
var b = Encoding.UTF8.GetBytes((string)value); var b = Encoding.UTF8.GetBytes((string)value);
@@ -228,8 +494,6 @@ public static class DataSerializer
{ {
var composed = ArrayComposer((IEnumerable)value, warehouse, connection); var composed = ArrayComposer((IEnumerable)value, warehouse, connection);
Console.WriteLine(composed.ToHex());
if (composed == null) if (composed == null)
return new TDU(TDUIdentifier.Null, new byte[0], 0); return new TDU(TDUIdentifier.Null, new byte[0], 0);
@@ -331,12 +595,12 @@ public static class DataSerializer
foreach (var i in value) foreach (var i in value)
{ {
var tdu = Codec.ComposeInternal(i, warehouse, connection); var tdu = Codec.ComposeInternal(i, warehouse, connection);
if (previous != null && tdu.MatchType(previous.Value)) if (previous != null && tdu.MatchType(previous.Value))
{ {
var d = tdu.Composed.Clip(tdu.ContentOffset, var d = tdu.Composed.Clip(tdu.ContentOffset,
(uint)tdu.Composed.Length - tdu.ContentOffset); (uint)tdu.Composed.Length - tdu.ContentOffset);
var ntd = new TDU(TDUIdentifier.TypeContinuation, d,(ulong) d.Length); var ntd = new TDU(TDUIdentifier.TypeContinuation, d, (ulong)d.Length);
rt.AddRange(ntd.Composed); rt.AddRange(ntd.Composed);
} }
else else

View File

@@ -16,7 +16,7 @@ namespace Esiur.Data
public ulong TotalLength; public ulong TotalLength;
public byte[] Metadata; public byte[] Metadata;
public static (ulong, ParsedTDU?) Parse(byte[] data, uint offset, uint ends) public static ParsedTDU Parse(byte[] data, uint offset, uint ends)
{ {
var h = data[offset++]; var h = data[offset++];
@@ -27,7 +27,7 @@ namespace Esiur.Data
var exp = (h & 0x38) >> 3; var exp = (h & 0x38) >> 3;
if (exp == 0) if (exp == 0)
return (1, new ParsedTDU() return new ParsedTDU()
{ {
Identifier = (TDUIdentifier)h, Identifier = (TDUIdentifier)h,
Data = data, Data = data,
@@ -37,16 +37,20 @@ namespace Esiur.Data
Index = (byte)h & 0x7, Index = (byte)h & 0x7,
ContentLength = 0, ContentLength = 0,
TotalLength = 1, TotalLength = 1,
}); };
ulong cl = (ulong)(1 << (exp - 1)); ulong cl = (ulong)(1 << (exp - 1));
if (ends - offset < cl) if (ends - offset < cl)
return (cl - (ends - offset), null); return new ParsedTDU()
{
Class = TDUClass.Invalid,
TotalLength = (cl - (ends - offset))
};
//offset += (uint)cl; //offset += (uint)cl;
return (1 + cl, new ParsedTDU() return new ParsedTDU()
{ {
Identifier = (TDUIdentifier)h, Identifier = (TDUIdentifier)h,
Data = data, Data = data,
@@ -56,14 +60,18 @@ namespace Esiur.Data
TotalLength = 1 + cl, TotalLength = 1 + cl,
Exponent = (byte)exp, Exponent = (byte)exp,
Index = (byte)h & 0x7, Index = (byte)h & 0x7,
}); };
} }
else if (cls == TDUClass.Typed) else if (cls == TDUClass.Typed)
{ {
ulong cll = (ulong)(h >> 3) & 0x7; ulong cll = (ulong)(h >> 3) & 0x7;
if (ends - offset < cll) if (ends - offset < cll)
return (cll - (ends - offset), null); return new ParsedTDU()
{
Class = TDUClass.Invalid,
TotalLength = (cll - (ends - offset))
};
ulong cl = 0; ulong cl = 0;
@@ -71,13 +79,17 @@ namespace Esiur.Data
cl = cl << 8 | data[offset++]; cl = cl << 8 | data[offset++];
if (ends - offset < cl) if (ends - offset < cl)
return (cl - (ends - offset), null); return new ParsedTDU()
{
TotalLength = (cl - (ends - offset)),
Class = TDUClass.Invalid,
};
var metaData = DC.Clip(data, offset + 1, data[offset]); var metaData = DC.Clip(data, offset + 1, data[offset]);
offset += data[offset] + (uint)1; offset += data[offset] + (uint)1;
return (1 + cl + cll, new ParsedTDU() return new ParsedTDU()
{ {
Identifier = (TDUIdentifier)(h & 0xC7), Identifier = (TDUIdentifier)(h & 0xC7),
Data = data, Data = data,
@@ -87,14 +99,18 @@ namespace Esiur.Data
TotalLength = 1 + cl + cll, TotalLength = 1 + cl + cll,
Index = (byte)h & 0x7, Index = (byte)h & 0x7,
Metadata = metaData, Metadata = metaData,
}); };
} }
else else
{ {
ulong cll = (ulong)(h >> 3) & 0x7; ulong cll = (ulong)(h >> 3) & 0x7;
if (ends - offset < cll) if (ends - offset < cll)
return (cll - (ends - offset), null); return new ParsedTDU()
{
Class = TDUClass.Invalid,
TotalLength = (cll - (ends - offset))
};
ulong cl = 0; ulong cl = 0;
@@ -102,10 +118,14 @@ namespace Esiur.Data
cl = cl << 8 | data[offset++]; cl = cl << 8 | data[offset++];
if (ends - offset < cl) if (ends - offset < cl)
return (cl - (ends - offset), null); return new ParsedTDU()
{
Class = TDUClass.Invalid,
TotalLength = (cl - (ends - offset))
};
return (1 + cl + cll, return
new ParsedTDU() new ParsedTDU()
{ {
Identifier = (TDUIdentifier)(h & 0xC7), Identifier = (TDUIdentifier)(h & 0xC7),
@@ -115,7 +135,7 @@ namespace Esiur.Data
ContentLength = cl, ContentLength = cl,
TotalLength = 1 + cl + cll, TotalLength = 1 + cl + cll,
Index = (byte)h & 0x7 Index = (byte)h & 0x7
}); };
} }
} }

View File

@@ -9,6 +9,7 @@ namespace Esiur.Data
Fixed = 0x0, Fixed = 0x0,
Dynamic = 0x1, Dynamic = 0x1,
Typed = 0x2, Typed = 0x2,
Extension = 0x3 Extension = 0x3,
Invalid
} }
} }

View File

@@ -10,6 +10,7 @@ namespace Esiur.Data
False = 0x1, False = 0x1,
True = 0x2, True = 0x2,
NotModified = 0x3, NotModified = 0x3,
Infinity = 0x4,
UInt8 = 0x8, UInt8 = 0x8,
Int8 = 0x9, Int8 = 0x9,
Char8 = 0xA, Char8 = 0xA,

View File

@@ -438,7 +438,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
{ {
// Invoke // Invoke
case IIPPacketNotification.PropertyModified: case IIPPacketNotification.PropertyModified:
IIPNotificationPropertyModified(dt, msg); IIPNotificationPropertyModified(dt);
break; break;
case IIPPacketNotification.EventOccurred: case IIPPacketNotification.EventOccurred:
IIPNotificationEventOccurred(dt, msg); IIPNotificationEventOccurred(dt, msg);
@@ -448,7 +448,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
IIPNotificationResourceDestroyed(dt, msg); IIPNotificationResourceDestroyed(dt, msg);
break; break;
case IIPPacketNotification.ResourceReassigned: case IIPPacketNotification.ResourceReassigned:
IIPNotificationResourceReassigned(dt, msg); IIPNotificationResourceReassigned(dt);
break; break;
case IIPPacketNotification.ResourceMoved: case IIPPacketNotification.ResourceMoved:
IIPNotificationResourceMoved(dt, msg); IIPNotificationResourceMoved(dt, msg);
@@ -537,7 +537,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
switch (packet.Reply) switch (packet.Reply)
{ {
case IIPPacketReply.Completed: case IIPPacketReply.Completed:
IIPReplyCompleted(packet.CallbackId, dt, msg); IIPReplyCompleted(packet.CallbackId, dt);
break; break;
case IIPPacketReply.Propagated: case IIPPacketReply.Propagated:
IIPReplyPropagated(packet.CallbackId, dt, msg); IIPReplyPropagated(packet.CallbackId, dt, msg);
@@ -554,7 +554,7 @@ public partial class DistributedConnection : NetworkConnection, IStore
break; break;
case IIPPacketReply.Chunk: case IIPPacketReply.Chunk:
IIPReplyChunk(packet.CallbackId, dt, msg); IIPReplyChunk(packet.CallbackId, dt);
break; break;
case IIPPacketReply.Warning: case IIPPacketReply.Warning:
@@ -1344,7 +1344,6 @@ public partial class DistributedConnection : NetworkConnection, IStore
protected override void DataReceived(NetworkBuffer data) protected override void DataReceived(NetworkBuffer data)
{ {
//Console.WriteLine("DR " + data.Available + " " + RemoteEndPoint.ToString());
var msg = data.Read(); var msg = data.Read();
uint offset = 0; uint offset = 0;
uint ends = (uint)msg.Length; uint ends = (uint)msg.Length;
@@ -1353,8 +1352,6 @@ public partial class DistributedConnection : NetworkConnection, IStore
var chunkId = (new Random()).Next(1000, 1000000); var chunkId = (new Random()).Next(1000, 1000000);
//var list = new List<Map<string, object>>();// double, IIPPacketCommand>();
this.Socket.Hold(); this.Socket.Hold();

View File

@@ -262,7 +262,7 @@ partial class DistributedConnection
SendReply(IIPPacketReply.Chunk, callbackId, chunk); SendReply(IIPPacketReply.Chunk, callbackId, chunk);
} }
void IIPReplyCompleted(uint callbackId, ParsedTDU dataType, byte[] data) void IIPReplyCompleted(uint callbackId, ParsedTDU dataType)
{ {
var req = requests.Take(callbackId); var req = requests.Take(callbackId);
@@ -272,7 +272,7 @@ partial class DistributedConnection
return; return;
} }
var (_, parsed) = Codec.ParseAsync(data, 0, this, null, dataType); var (_, parsed) = Codec.ParseAsync(dataType, this, null);
if (parsed is AsyncReply reply) if (parsed is AsyncReply reply)
{ {
reply.Then(result => reply.Then(result =>
@@ -374,14 +374,14 @@ partial class DistributedConnection
void IIPReplyChunk(uint callbackId, ParsedTDU dataType, byte[] data) void IIPReplyChunk(uint callbackId, ParsedTDU dataType)
{ {
var req = requests[callbackId]; var req = requests[callbackId];
if (req == null) if (req == null)
return; return;
var (_, parsed) = Codec.ParseAsync(data, dataType.Offset, this, null, dataType); var (_, parsed) = Codec.ParseAsync(dataType, this, null);
if (parsed is AsyncReply reply) if (parsed is AsyncReply reply)
reply.Then(result => req.TriggerChunk(result)); reply.Then(result => req.TriggerChunk(result));
@@ -389,7 +389,7 @@ partial class DistributedConnection
req.TriggerChunk(parsed); req.TriggerChunk(parsed);
} }
void IIPNotificationResourceReassigned(ParsedTDU dataType, byte[] data) void IIPNotificationResourceReassigned(ParsedTDU dataType)
{ {
// uint resourceId, uint newResourceId // uint resourceId, uint newResourceId
} }
@@ -429,11 +429,11 @@ partial class DistributedConnection
} }
void IIPNotificationPropertyModified(ParsedTDU dataType, byte[] data) void IIPNotificationPropertyModified(ParsedTDU dataType)
{ {
// resourceId, index, value // resourceId, index, value
var (valueOffset, valueSize, args) = var (valueOffset, valueSize, args) =
DataDeserializer.LimitedCountListParser(data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2); DataDeserializer.LimitedCountListParser(dataType.Data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2);
var rid = (uint)args[0]; var rid = (uint)args[0];
var index = (byte)args[1]; var index = (byte)args[1];
@@ -447,7 +447,7 @@ partial class DistributedConnection
var item = new AsyncReply<DistributedResourceQueueItem>(); var item = new AsyncReply<DistributedResourceQueueItem>();
queue.Add(item); queue.Add(item);
var (_, parsed) = Codec.ParseAsync(data, valueOffset, this, null); var (_, parsed) = Codec.ParseAsync(dataType.Data, valueOffset, this, null);
if (parsed is AsyncReply) if (parsed is AsyncReply)
{ {
@@ -663,7 +663,7 @@ partial class DistributedConnection
void IIPRequestCreateResource(uint callback, ParsedTDU dataType, byte[] data) void IIPRequestCreateResource(uint callback, ParsedTDU dataType, byte[] data)
{ {
var (_, parsed) = Codec.ParseAsync(data, 0, this, null, dataType); var (_, parsed) = Codec.ParseAsync(dataType, this, null);
var args = (object[])parsed; var args = (object[])parsed;

View File

@@ -117,7 +117,7 @@ public abstract class NetworkServer<TConnection> : IDestructible where TConnecti
if (s == null) if (s == null)
{ {
Console.Write("sock == null"); Global.Log("NetworkServer", LogType.Error, "sock == null");
return; return;
} }

View File

@@ -188,13 +188,13 @@ public class IIPAuthPacket : Packet
if (NotEnough(offset, ends, 1)) if (NotEnough(offset, ends, 1))
return -dataLengthNeeded; return -dataLengthNeeded;
(var size, DataType) = ParsedTDU.Parse(data, offset, ends); DataType = ParsedTDU.Parse(data, offset, ends);
if (DataType == null) if (DataType.Value.Class == TDUClass.Invalid)
return -(int)size; return -(int)DataType.Value.TotalLength;
offset += (uint)size; offset += (uint)DataType.Value.TotalLength;
} }
else if (Command == IIPAuthPacketCommand.Acknowledge) else if (Command == IIPAuthPacketCommand.Acknowledge)
@@ -208,13 +208,13 @@ public class IIPAuthPacket : Packet
if (NotEnough(offset, ends, 1)) if (NotEnough(offset, ends, 1))
return -dataLengthNeeded; return -dataLengthNeeded;
(var size, DataType) = ParsedTDU.Parse(data, offset, ends); DataType = ParsedTDU.Parse(data, offset, ends);
if (DataType == null) if (DataType.Value.Class == TDUClass.Invalid)
return -(int)size; return -(int)DataType.Value.TotalLength;
offset += (uint)size; offset += (uint)DataType.Value.TotalLength;
} }
else if (Command == IIPAuthPacketCommand.Action) else if (Command == IIPAuthPacketCommand.Action)
{ {
@@ -280,12 +280,12 @@ public class IIPAuthPacket : Packet
Reference = data.GetUInt32(offset, Endian.Little); Reference = data.GetUInt32(offset, Endian.Little);
offset += 4; offset += 4;
(var size, DataType) = ParsedTDU.Parse(data, offset, ends); DataType = ParsedTDU.Parse(data, offset, ends);
if (DataType == null) if (DataType.Value.Class == TDUClass.Invalid)
return -(int)size; return -(int)DataType.Value.TotalLength;
offset += (uint)size; offset += (uint)DataType.Value.TotalLength;
} }
else if (Action == IIPAuthPacketAction.IAuthHashed) else if (Action == IIPAuthPacketAction.IAuthHashed)
@@ -445,12 +445,12 @@ public class IIPAuthPacket : Packet
if (NotEnough(offset, ends, 1)) if (NotEnough(offset, ends, 1))
return -dataLengthNeeded; return -dataLengthNeeded;
(var size, DataType) = ParsedTDU.Parse(data, offset, ends); DataType = ParsedTDU.Parse(data, offset, ends);
if (DataType == null) if (DataType.Value.Class == TDUClass.Invalid)
return -(int)size; return -(int)DataType.Value.TotalLength;
offset += (uint)size; offset += (uint)DataType.Value.TotalLength;
} }
} }

View File

@@ -37,10 +37,10 @@ class IIPPacket : Packet
public uint CallbackId { get; set; } public uint CallbackId { get; set; }
public IIPPacketMethod Method { get; set; } public IIPPacketMethod Method { get; set; }
public IIPPacketRequest Request { get; set; } public IIPPacketRequest Request { get; set; }
public IIPPacketReply Reply { get; set; } public IIPPacketReply Reply { get; set; }
public IIPPacketNotification Notification { get; set; } public IIPPacketNotification Notification { get; set; }
public byte Extension { get; set; } public byte Extension { get; set; }
@@ -57,12 +57,12 @@ class IIPPacket : Packet
public override string ToString() public override string ToString()
{ {
return Method switch return Method switch
{ {
IIPPacketMethod.Notification => $"{Method} {Notification}", IIPPacketMethod.Notification => $"{Method} {Notification}",
IIPPacketMethod.Request => $"{Method} {Request}", IIPPacketMethod.Request => $"{Method} {Request}",
IIPPacketMethod.Reply => $"{Method} {Reply}", IIPPacketMethod.Reply => $"{Method} {Reply}",
IIPPacketMethod.Extension => $"{Method} {Extension}", IIPPacketMethod.Extension => $"{Method} {Extension}",
_ => $"{Method}" _ => $"{Method}"
}; };
} }
@@ -124,12 +124,12 @@ class IIPPacket : Packet
if (NotEnough(offset, ends, 1)) if (NotEnough(offset, ends, 1))
return -dataLengthNeeded; return -dataLengthNeeded;
(var size, DataType) = ParsedTDU.Parse(data, offset, ends); DataType = ParsedTDU.Parse(data, offset, ends);
if (DataType == null) if (DataType.Value.Class == TDUClass.Invalid)
return -(int)size; return -(int)DataType.Value.TotalLength;
offset += (uint)size; offset += (uint)DataType.Value.TotalLength;
} }
else else
{ {