mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-10-29 23:21:36 +00:00
Encoding
This commit is contained in:
@@ -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="dataType">DataType, in case the data is not prepended with DataType</param>
|
||||
/// <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);
|
||||
|
||||
if (dataType == null)
|
||||
throw new NullReferenceException("DataType can't be parsed.");
|
||||
|
||||
len = (uint)longLen;
|
||||
offset = dataType.Value.Offset;
|
||||
return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence));
|
||||
}
|
||||
else
|
||||
len = (uint)dataType.Value.ContentLength;
|
||||
|
||||
var tt = dataType.Value;
|
||||
|
||||
//Console.WriteLine("Parsing " + tt.Class + " " + tt.Identifier);
|
||||
|
||||
if (tt.Class == TDUClass.Fixed)
|
||||
else if (tdu.Class == TDUClass.Dynamic)
|
||||
{
|
||||
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)
|
||||
{
|
||||
uint len = 0;
|
||||
var tdu = ParsedTDU.Parse(data, offset, (uint)data.Length);
|
||||
|
||||
|
||||
var (longLen, dataType) = ParsedTDU.Parse(data, offset, (uint)data.Length);
|
||||
|
||||
if (dataType == null)
|
||||
if (tdu.Class == TDUClass.Invalid)
|
||||
throw new NullReferenceException("DataType can't be parsed.");
|
||||
|
||||
len = (uint)longLen;
|
||||
offset = dataType.Value.Offset;
|
||||
|
||||
var tt = dataType.Value;
|
||||
|
||||
if (tt.Class == TDUClass.Fixed)
|
||||
if (tdu.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
|
||||
{
|
||||
return (len, ExtendedParsers[tt.Index](tt, warehouse));
|
||||
return ((uint)tdu.TotalLength, ExtendedParsers[tdu.Index](tdu, warehouse));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -326,8 +330,8 @@ public static class Codec
|
||||
[typeof(float?)] = DataSerializer.Float32Composer,
|
||||
[typeof(long)] = DataSerializer.Int64Composer,
|
||||
[typeof(long?)] = DataSerializer.Int64Composer,
|
||||
[typeof(ulong)] = DataSerializer.UIn64Composer,
|
||||
[typeof(ulong?)] = DataSerializer.UIn64Composer,
|
||||
[typeof(ulong)] = DataSerializer.UInt64Composer,
|
||||
[typeof(ulong?)] = DataSerializer.UInt64Composer,
|
||||
[typeof(double)] = DataSerializer.Float64Composer,
|
||||
[typeof(double?)] = DataSerializer.Float64Composer,
|
||||
[typeof(DateTime)] = DataSerializer.DateTimeComposer,
|
||||
|
||||
@@ -450,7 +450,7 @@ public static class DataDeserializer
|
||||
{
|
||||
|
||||
var classId = tdu.Metadata.GetUUID(0);
|
||||
|
||||
|
||||
|
||||
var template = warehouse.GetTemplateByClassId(classId, TemplateType.Record);
|
||||
|
||||
@@ -535,7 +535,7 @@ public static class DataDeserializer
|
||||
{
|
||||
|
||||
var classId = tdu.Metadata.GetUUID(0);
|
||||
|
||||
|
||||
var index = tdu.Data[tdu.Offset];
|
||||
|
||||
var template = warehouse.GetTemplateByClassId(classId, TemplateType.Enum);
|
||||
@@ -794,7 +794,7 @@ public static class DataDeserializer
|
||||
|
||||
var (keyCs, keyRepType) = RepresentationType.Parse(tdu.Metadata, 0);
|
||||
var (valueCs, valueRepType) = RepresentationType.Parse(tdu.Metadata, keyCs);
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
var rt = new AsyncReply();
|
||||
|
||||
var results = new List<object>();
|
||||
var results = new AsyncBag<object>();
|
||||
var tupleSize = tdu.Metadata[0];
|
||||
|
||||
var types = new List<Type>();
|
||||
@@ -919,7 +920,7 @@ public static class DataDeserializer
|
||||
|
||||
var length = tdu.ContentLength;
|
||||
var offset = tdu.Offset;
|
||||
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var (cs, reply) = Codec.ParseSync(tdu.Data, offset, warehouse);
|
||||
@@ -977,20 +978,37 @@ public static class DataDeserializer
|
||||
var rt = new AsyncBag<object>();
|
||||
|
||||
// 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);
|
||||
|
||||
rt.ArrayType = runtimeType;
|
||||
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
var offset = tdu.Offset;
|
||||
var length = tdu.ContentLength;
|
||||
var ends = offset + (uint)length;
|
||||
|
||||
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);
|
||||
|
||||
@@ -1021,7 +1039,7 @@ public static class DataDeserializer
|
||||
|
||||
var list = new List<object>();
|
||||
|
||||
ParsedTDU? current;
|
||||
ParsedTDU current;
|
||||
ParsedTDU? previous = null;
|
||||
|
||||
var offset = tdu.Offset;
|
||||
@@ -1030,21 +1048,20 @@ public static class DataDeserializer
|
||||
|
||||
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.");
|
||||
|
||||
var cur = (ParsedTDU)current.Value;
|
||||
|
||||
if (cur.Identifier == TDUIdentifier.TypeContinuation)
|
||||
if (current.Identifier == TDUIdentifier.TypeContinuation)
|
||||
{
|
||||
cur.Class = previous.Value.Class;
|
||||
cur.Identifier = previous.Value.Identifier;
|
||||
cur.Metadata = previous.Value.Metadata;
|
||||
current.Class = previous.Value.Class;
|
||||
current.Identifier = previous.Value.Identifier;
|
||||
current.Metadata = previous.Value.Metadata;
|
||||
}
|
||||
|
||||
var (cs, reply) = Codec.ParseSync(cur, warehouse);
|
||||
var (cs, reply) = Codec.ParseSync(current, warehouse);
|
||||
|
||||
list.Add(reply);
|
||||
|
||||
@@ -1052,7 +1069,7 @@ public static class DataDeserializer
|
||||
{
|
||||
offset += (uint)cs;
|
||||
length -= (uint)cs;
|
||||
previous = cur;
|
||||
previous = current;
|
||||
}
|
||||
else
|
||||
throw new Exception("Error while parsing structured data");
|
||||
@@ -1061,7 +1078,7 @@ public static class DataDeserializer
|
||||
|
||||
var rt = Array.CreateInstance(runtimeType, list.Count);
|
||||
Array.Copy(list.ToArray(), rt, rt.Length);
|
||||
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
@@ -1070,7 +1087,8 @@ public static class DataDeserializer
|
||||
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 pvs = new List<PropertyValue>();
|
||||
|
||||
@@ -3,6 +3,7 @@ using Esiur.Net.IIP;
|
||||
using Esiur.Resource;
|
||||
using Esiur.Resource.Template;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -17,77 +18,271 @@ public static class DataSerializer
|
||||
public static unsafe TDU Int32Composer(object value, Warehouse warehouse, DistributedConnection connection)
|
||||
{
|
||||
var v = (int)value;
|
||||
var rt = new byte[4];
|
||||
fixed (byte* ptr = rt)
|
||||
*((int*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.Int32, rt, 4);
|
||||
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
var rt = new byte[4];
|
||||
fixed (byte* ptr = rt)
|
||||
*((float*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.Float32, rt, 4);
|
||||
float v = (float)value;
|
||||
|
||||
// Special IEEE-754 values
|
||||
if (float.IsNaN(v) || float.IsInfinity(v))
|
||||
{
|
||||
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;
|
||||
var rt = new byte[8];
|
||||
fixed (byte* ptr = rt)
|
||||
*((double*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.Float64, rt, 8);
|
||||
}
|
||||
double v = (double)value;
|
||||
|
||||
// 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)
|
||||
{
|
||||
var v = (long)value;
|
||||
var rt = new byte[8];
|
||||
fixed (byte* ptr = rt)
|
||||
*((long*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.Int64, rt, 8);
|
||||
|
||||
if (v >= sbyte.MinValue && v <= sbyte.MaxValue)
|
||||
{
|
||||
// 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 rt = new byte[8];
|
||||
fixed (byte* ptr = rt)
|
||||
*((ulong*)ptr) = v;
|
||||
return new TDU(TDUIdentifier.UInt64, rt, 8);
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var b = Encoding.UTF8.GetBytes((string)value);
|
||||
@@ -228,8 +494,6 @@ public static class DataSerializer
|
||||
{
|
||||
var composed = ArrayComposer((IEnumerable)value, warehouse, connection);
|
||||
|
||||
Console.WriteLine(composed.ToHex());
|
||||
|
||||
if (composed == null)
|
||||
return new TDU(TDUIdentifier.Null, new byte[0], 0);
|
||||
|
||||
@@ -331,12 +595,12 @@ public static class DataSerializer
|
||||
foreach (var i in value)
|
||||
{
|
||||
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,
|
||||
(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);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Esiur.Data
|
||||
public ulong TotalLength;
|
||||
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++];
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Esiur.Data
|
||||
var exp = (h & 0x38) >> 3;
|
||||
|
||||
if (exp == 0)
|
||||
return (1, new ParsedTDU()
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Identifier = (TDUIdentifier)h,
|
||||
Data = data,
|
||||
@@ -37,16 +37,20 @@ namespace Esiur.Data
|
||||
Index = (byte)h & 0x7,
|
||||
ContentLength = 0,
|
||||
TotalLength = 1,
|
||||
});
|
||||
};
|
||||
|
||||
ulong cl = (ulong)(1 << (exp - 1));
|
||||
|
||||
if (ends - offset < cl)
|
||||
return (cl - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Class = TDUClass.Invalid,
|
||||
TotalLength = (cl - (ends - offset))
|
||||
};
|
||||
|
||||
//offset += (uint)cl;
|
||||
|
||||
return (1 + cl, new ParsedTDU()
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Identifier = (TDUIdentifier)h,
|
||||
Data = data,
|
||||
@@ -56,14 +60,18 @@ namespace Esiur.Data
|
||||
TotalLength = 1 + cl,
|
||||
Exponent = (byte)exp,
|
||||
Index = (byte)h & 0x7,
|
||||
});
|
||||
};
|
||||
}
|
||||
else if (cls == TDUClass.Typed)
|
||||
{
|
||||
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||
|
||||
if (ends - offset < cll)
|
||||
return (cll - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Class = TDUClass.Invalid,
|
||||
TotalLength = (cll - (ends - offset))
|
||||
};
|
||||
|
||||
ulong cl = 0;
|
||||
|
||||
@@ -71,13 +79,17 @@ namespace Esiur.Data
|
||||
cl = cl << 8 | data[offset++];
|
||||
|
||||
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]);
|
||||
offset += data[offset] + (uint)1;
|
||||
|
||||
|
||||
return (1 + cl + cll, new ParsedTDU()
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Identifier = (TDUIdentifier)(h & 0xC7),
|
||||
Data = data,
|
||||
@@ -87,14 +99,18 @@ namespace Esiur.Data
|
||||
TotalLength = 1 + cl + cll,
|
||||
Index = (byte)h & 0x7,
|
||||
Metadata = metaData,
|
||||
});
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong cll = (ulong)(h >> 3) & 0x7;
|
||||
|
||||
if (ends - offset < cll)
|
||||
return (cll - (ends - offset), null);
|
||||
return new ParsedTDU()
|
||||
{
|
||||
Class = TDUClass.Invalid,
|
||||
TotalLength = (cll - (ends - offset))
|
||||
};
|
||||
|
||||
ulong cl = 0;
|
||||
|
||||
@@ -102,10 +118,14 @@ namespace Esiur.Data
|
||||
cl = cl << 8 | data[offset++];
|
||||
|
||||
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()
|
||||
{
|
||||
Identifier = (TDUIdentifier)(h & 0xC7),
|
||||
@@ -115,7 +135,7 @@ namespace Esiur.Data
|
||||
ContentLength = cl,
|
||||
TotalLength = 1 + cl + cll,
|
||||
Index = (byte)h & 0x7
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Esiur.Data
|
||||
Fixed = 0x0,
|
||||
Dynamic = 0x1,
|
||||
Typed = 0x2,
|
||||
Extension = 0x3
|
||||
Extension = 0x3,
|
||||
Invalid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Esiur.Data
|
||||
False = 0x1,
|
||||
True = 0x2,
|
||||
NotModified = 0x3,
|
||||
Infinity = 0x4,
|
||||
UInt8 = 0x8,
|
||||
Int8 = 0x9,
|
||||
Char8 = 0xA,
|
||||
|
||||
Reference in New Issue
Block a user