using Esiur.Core; using Esiur.Data; using Esiur.Data.Gvwie; using Esiur.Data.Types; using Esiur.Misc; using Esiur.Protocol; using Esiur.Resource; using Esiur.Security.Membership; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Runtime.InteropServices.ComTypes; using System.Text; namespace Esiur.Data; public static class DataDeserializer { public static object NullParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return null; } public static object NullParser(ParsedTdu tdu, Warehouse warehouse) { return null; } public static object BooleanTrueParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return true; } public static object BooleanTrueParser(ParsedTdu tdu, Warehouse warehouse) { return true; } public static object BooleanFalseParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return false; } public static object BooleanFalseParser(ParsedTdu tdu, Warehouse warehouse) { return false; } public static object NotModifiedParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return NotModified.Default; } public static object NotModifiedParser(ParsedTdu tdu, Warehouse warehouse) { return NotModified.Default; } public static object UInt8ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return tdu.Data[tdu.PayloadOffset]; } public static object UInt8Parser(ParsedTdu tdu, Warehouse warehouse) { return tdu.Data[tdu.PayloadOffset]; } public static object Int8ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return (sbyte)tdu.Data[tdu.PayloadOffset]; } public static object Int8Parser(ParsedTdu tdu, Warehouse warehouse) { return (sbyte)tdu.Data[tdu.PayloadOffset]; } public static unsafe object Char16ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(char*)ptr; } public static unsafe object Char16Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(char*)ptr; } public static object Char8ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return (char)tdu.Data[tdu.PayloadOffset]; } public static object Char8Parser(ParsedTdu tdu, Warehouse warehouse) { return (char)tdu.Data[tdu.PayloadOffset]; } public static unsafe object Int16ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(short*)ptr; } public static unsafe object Int16Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(short*)ptr; } public static unsafe object UInt16ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(ushort*)ptr; } public static unsafe object UInt16Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(ushort*)ptr; } public static unsafe object Int32ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(int*)ptr; } public static unsafe object Int32Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(int*)ptr; } public static unsafe object UInt32ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(uint*)ptr; } public static unsafe object UInt32Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(uint*)ptr; } public static unsafe object Float32ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(float*)ptr; } public static unsafe object Float32Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(float*)ptr; } public static unsafe object Float64ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(double*)ptr; } public static unsafe object Float64Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(double*)ptr; } public static unsafe object Decimal128ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(decimal*)ptr; } public static unsafe object Decimal128Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(decimal*)ptr; } public static unsafe object UUIDParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return new Uuid(tdu.Data, tdu.PayloadOffset); } public static unsafe object UUIDParser(ParsedTdu tdu, Warehouse warehouse) { return new Uuid(tdu.Data, tdu.PayloadOffset); } public static unsafe object Int128ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr1 = &tdu.Data[tdu.PayloadOffset]) fixed (byte* ptr2 = &tdu.Data[tdu.PayloadOffset + 8]) return new Int128(*(ulong*)ptr1, *(ulong*)ptr2); } public static unsafe object Int128Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr1 = &tdu.Data[tdu.PayloadOffset]) fixed (byte* ptr2 = &tdu.Data[tdu.PayloadOffset + 8]) return new Int128(*(ulong*)ptr1, *(ulong*)ptr2); } public static unsafe object UInt128ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr1 = &tdu.Data[tdu.PayloadOffset]) fixed (byte* ptr2 = &tdu.Data[tdu.PayloadOffset + 8]) return new UInt128(*(ulong*)ptr1, *(ulong*)ptr2); } public static unsafe object UInt128Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr1 = &tdu.Data[tdu.PayloadOffset]) fixed (byte* ptr2 = &tdu.Data[tdu.PayloadOffset + 8]) return new UInt128(*(ulong*)ptr1, *(ulong*)ptr2); } public static unsafe object Int64ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(long*)ptr; } public static unsafe object Int64Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(long*)ptr; } public static unsafe object UInt64ParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(ulong*)ptr; } public static unsafe object UInt64Parser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return *(ulong*)ptr; } public static unsafe object DateTimeParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return new DateTime(*(long*)ptr, DateTimeKind.Utc); } public static unsafe object DateTimeParser(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return new DateTime(*(long*)ptr, DateTimeKind.Utc); } public static object ResourceLinkParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { var link = tdu.Data.GetString(tdu.PayloadOffset, (uint)tdu.PayloadLength); if (connection == null) { return new ResourceLink(link); } else { return connection.Instance.Warehouse.Get(link); } } public static object ResourceLinkParser(ParsedTdu tdu, Warehouse warehouse) { var link = tdu.Data.GetString(tdu.PayloadOffset, (uint)tdu.PayloadLength); return new ResourceLink(link); } public static unsafe object ResourceParser8Async(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { if (connection == null) return new ResourceId(false, tdu.Data[tdu.PayloadOffset]); else return connection.FetchResource(tdu.Data[tdu.PayloadOffset], requestSequence); } public static unsafe object ResourceParser8(ParsedTdu tdu, Warehouse warehouse) { return new ResourceId(false, tdu.Data[tdu.PayloadOffset]); } public static unsafe object LocalResourceParser8Async(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { if (connection == null) return new ResourceId(true, tdu.Data[tdu.PayloadOffset]); else return connection.Instance.Warehouse.GetById(tdu.Data[tdu.PayloadOffset]); } public static unsafe object LocalResourceParser8(ParsedTdu tdu, Warehouse warehouse) { return new ResourceId(true, tdu.Data[tdu.PayloadOffset]); } public static unsafe object ResourceParser16Async(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) if (connection == null) return new ResourceId(false, *(ushort*)ptr); else return connection.FetchResource(*(ushort*)ptr, requestSequence); } public static unsafe object ResourceParser16(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return new ResourceId(false, *(ushort*)ptr); } public static unsafe object LocalResourceParser16Async(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) if (connection == null) return new ResourceId(true, *(ushort*)ptr); else return connection.Instance.Warehouse.GetById(*(ushort*)ptr); } public static unsafe object LocalResourceParser16(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return new ResourceId(true, *(ushort*)ptr); } public static unsafe object ResourceParser32Async(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) if (connection == null) return new ResourceId(false, *(uint*)ptr); else return connection.FetchResource(*(uint*)ptr, requestSequence); } public static unsafe object ResourceParser32(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return new ResourceId(false, *(uint*)ptr); } public static unsafe object LocalResourceParser32Async(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) if (connection == null) return new ResourceId(true, *(uint*)ptr); else return connection.Instance.Warehouse.GetById(*(uint*)ptr); } public static unsafe object LocalResourceParser32(ParsedTdu tdu, Warehouse warehouse) { fixed (byte* ptr = &tdu.Data[tdu.PayloadOffset]) return new ResourceId(true, *(uint*)ptr); } public static unsafe object RawDataParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return tdu.Data.Clip(tdu.PayloadOffset, (uint)tdu.PayloadLength); } public static unsafe object RawDataParser(ParsedTdu tdu, Warehouse warehouse) { return tdu.Data.Clip(tdu.PayloadOffset, (uint)tdu.PayloadLength); } public static unsafe object StringParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { return tdu.Data.GetString(tdu.PayloadOffset, (uint)tdu.PayloadLength); } public static unsafe object StringParser(ParsedTdu tdu, Warehouse warehouse) { return tdu.Data.GetString(tdu.PayloadOffset, (uint)tdu.PayloadLength); } public static async AsyncReply RecordParserAsync(ParsedTdu tdu, TypeDef recordTypeDef, EpConnection connection, uint[] requestSequence) { //if (tdu.Metadata.TypeDefId == null) // throw new Exception("TypeDefId metadata is required for record parsing."); //TypeDefId typeDefId = tdu.Metadata.TypeDefId.Value; //TypeDef typeDef = null; //.GetUInt32(0); //var typeDef = connection.Instance.Warehouse.GetTypeDefById(tdu.Metadata.TypeDefId, // TypeDefKind.Record); var rt = new AsyncReply(); var list = new AsyncBag(); ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; for (var i = 0; i < recordTypeDef.Properties.Length; i++) { current = await ParsedTdu.ParseAsync(tdu.Data, offset, ends, connection); 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; } else if (current.Identifier == TduIdentifier.TypeOfTarget) { //var idf = typeDef.Properties[i].ValueType.GetMetadata(); var propTru = recordTypeDef.Properties[i].ValueType; current.Class = TduClass.Typed; current.Identifier = TduIdentifier.Typed;// propTru.Identifier;// idf; current.Metadata = propTru;// mt; current.Index = (int)TduIdentifier.Typed & 0x7;// (int)idf & 0x7; } var value = Codec.ParseAsync(current, connection, requestSequence); list.Add(value); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; previous = current; } else throw new Exception("Error while parsing structured data"); } list.Seal(); var results = await list; Type recordType = recordTypeDef is LocalTypeDef localTypeDef ? localTypeDef.DefinedType : recordTypeDef is RemoteTypeDef remoteTypeDef ? remoteTypeDef.ProxyType : null; if (recordType != null) { var record = Activator.CreateInstance(recordType) as IRecord; for (var i = 0; i < recordTypeDef.Properties.Length; i++) { try { var v = RuntimeCaster.Cast(results[i], recordTypeDef.Properties[i].PropertyInfo.PropertyType); recordTypeDef.Properties[i].PropertyInfo.SetValue(record, v); } catch (Exception ex) { Global.Log(ex); } } return record; } else { var record = new Record(recordTypeDef); for (var i = 0; i < recordTypeDef.Properties.Length; i++) record.Add(recordTypeDef.Properties[i].Name, results[i]); return record; } //list.Then(results => //{ // Type recordType = recordTypeDef is LocalTypeDef localTypeDef ? localTypeDef.DefinedType // : recordTypeDef is RemoteTypeDef remoteTypeDef ? remoteTypeDef.ProxyType : null; // if (recordType != null) // { // var record = Activator.CreateInstance(recordType) as IRecord; // for (var i = 0; i < recordTypeDef.Properties.Length; i++) // { // try // { // var v = RuntimeCaster.Cast(results[i], recordTypeDef.Properties[i].PropertyInfo.PropertyType); // recordTypeDef.Properties[i].PropertyInfo.SetValue(record, v); // } // catch (Exception ex) // { // Global.Log(ex); // } // } // rt.Trigger(record); // } // else // { // var record = new Record(recordTypeDef); // for (var i = 0; i < recordTypeDef.Properties.Length; i++) // record.Add(recordTypeDef.Properties[i].Name, results[i]); // rt.Trigger(record); // } //}).Error(e => //{ // rt.TriggerError(e); //}); //return rt; } public static unsafe object RecordParser(ParsedTdu tdu, LocalTypeDef recordTypeDef, Warehouse warehouse) { //if (tdu.Metadata is not TypeDefId) // throw new Exception("Unsupported metadata."); //TypeDefId typeDefId = (TypeDefId)tdu.Metadata; //if (typeDefId.Remote) // throw new Exception("Unsupported in synchronous parsing."); //var typeDef = warehouse.GetLocalTypeDefById(recordTypeDef.Value); if (recordTypeDef == null) { // @TODO: add parse if no TypeDef settings throw new AsyncException(ErrorType.Management, (ushort)ExceptionCode.TypeDefNotFound, "TypeDef not found for record."); } var list = new List(); ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; for (var i = 0; i < recordTypeDef.Properties.Length; i++) { current = ParsedTdu.ParseSync(tdu.Data, offset, ends, warehouse); 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; } else if (current.Identifier == TduIdentifier.TypeOfTarget) { //var (idf, mt) = recordTypeDef.Properties[i].ValueType.GetMetadata(); var propTru = recordTypeDef.Properties[i].ValueType; current.Class = TduClass.Typed; current.Identifier = TduIdentifier.Typed;// idf; current.Metadata = propTru;// mt; current.Index = (int)TduIdentifier.Typed & 0x7; } var reply = Codec.ParseSync(current, warehouse); list.Add(reply); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; previous = current; } else throw new Exception("Error while parsing structured data"); } if (recordTypeDef.DefinedType != null) { var record = Activator.CreateInstance(recordTypeDef.DefinedType) as IRecord; for (var i = 0; i < recordTypeDef.Properties.Length; i++) { try { var v = RuntimeCaster.Cast(list[i], recordTypeDef.Properties[i].PropertyInfo.PropertyType); recordTypeDef.Properties[i].PropertyInfo.SetValue(record, v); } catch (Exception ex) { Global.Log(ex); } } return record; } else { var record = new Record(recordTypeDef); for (var i = 0; i < recordTypeDef.Properties.Length; i++) record.Add(recordTypeDef.Properties[i].Name, list[i]); return record; } } public static unsafe object ConstantParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { throw new NotImplementedException(); } public static unsafe object ConstantParser(ParsedTdu tdu, Warehouse warehouse) { throw new NotImplementedException(); } public static unsafe AsyncReply EnumParserAsync(ParsedTdu tdu, TypeDef enumTypeDef, EpConnection connection, uint[] requestSequence) { var index = tdu.Data[tdu.PayloadOffset]; return new AsyncReply(enumTypeDef.Constants[index].Value); //TypeDef typeDef = null; //if (tdu.Metadata is TypeDefId typeDefId) //{ // if (typeDefId.Remote) // { // typeDef = connection.Instance.Warehouse.GetRemoteTypeDefById(connection.RemoteDomain, typeDefId.Value); // var index = tdu.Data[tdu.Offset]; // if (typeDef == null) // { // var reply = new AsyncReply(); // connection.GetTypeDefById(typeDefId.Value).Then(td => // { // reply.Trigger(td.Constants[index].Value); // }).Error(x => reply.TriggerError(x)); // return reply; // } // else // { // return new AsyncReply(typeDef.Constants[index].Value); // } // } // else // { // typeDef = connection.Instance.Warehouse.GetLocalTypeDefById(typeDefId.Value); // if (typeDef == null) // { // throw new AsyncException(ErrorType.Management, (ushort)ExceptionCode.TypeDefNotFound, // "TypeDef not found for enum."); // } // var index = tdu.Data[tdu.Offset]; // return new AsyncReply(typeDef.Constants[index].Value); // } //} //else //{ // throw new Exception("Unsupported metadata."); //} } public static unsafe object EnumParser(ParsedTdu tdu, TypeDef enumTypeDef, Warehouse warehouse) { //TypeDef typeDef = null; //if (tdu.Metadata is TypeDefId typeDefId) //{ // if (typeDefId.Remote) // { // throw new Exception("Unsupported in synchronous parsing."); // } // typeDef = warehouse.GetLocalTypeDefById(typeDefId.Value); //} //if (typeDef == null) //{ // throw new AsyncException(ErrorType.Management, (ushort)ExceptionCode.TypeDefNotFound, // "TypeDef not found for enum."); //} var index = tdu.Data[tdu.PayloadOffset]; return enumTypeDef.Constants[index].Value; } public static async AsyncReply RecordListParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { var rt = new AsyncBag(); var length = tdu.PayloadLength; var offset = tdu.PayloadOffset; while (length > 0) { //var (cs, reply) var pr = await Codec.ParseAsync(tdu.Data, offset, connection, requestSequence); rt.Add(pr.Value); if (pr.Size > 0) { offset += (uint)pr.Size; length -= (uint)pr.Size; } else throw new Exception("Error while parsing structured data"); } rt.Seal(); var results = await rt; return results; } public static object RecordListParser(ParsedTdu tdu, Warehouse warehouse) { var rt = new List(); var length = tdu.PayloadLength; var offset = tdu.PayloadOffset; while (length > 0) { var (cs, reply) = Codec.ParseSync(tdu.Data, offset, warehouse); rt.Add(reply as IRecord); if (cs > 0) { offset += (uint)cs; length -= (uint)cs; } else throw new Exception("Error while parsing structured data"); } return rt.ToArray(); } public static async AsyncReply ResourceListParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { var rt = new AsyncBag(); var length = tdu.PayloadLength; var offset = tdu.PayloadOffset; while (length > 0) { //var (cs, reply) var pr = await Codec.ParseAsync(tdu.Data, offset, connection, requestSequence); rt.Add(pr.Value);// reply); if (pr.Size > 0) { offset += (uint)pr.Size; length -= (uint)pr.Size; } else throw new Exception("Error while parsing structured data"); } rt.Seal(); var results = await rt; return results; } public static object ResourceListParser(ParsedTdu tdu, Warehouse warehouse) { var rt = new List(); var length = tdu.PayloadLength; var offset = tdu.PayloadOffset; while (length > 0) { var (cs, reply) = Codec.ParseSync(tdu.Data, offset, warehouse); rt.Add(reply as IResource); if (cs > 0) { offset += (uint)cs; length -= (uint)cs; } else throw new Exception("Error while parsing structured data"); } return rt.ToArray(); } public static async AsyncReply ListParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { //var rt = new AsyncBag(); //var offset = tdu.Offset; //var length = tdu.ContentLength; //while (length > 0) //{ // var (cs, reply) = Codec.ParseAsync(tdu.Data, offset, connection, requestSequence); // rt.Add(reply); // if (cs > 0) // { // offset += (uint)cs; // length -= (uint)cs; // } // else // throw new Exception("Error while parsing structured data"); //} //rt.Seal(); //return rt; var rt = new AsyncBag(); //var list = new List(); ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; while (length > 0) { current = await ParsedTdu.ParseAsync(tdu.Data, offset, ends, connection); 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) var value = Codec.ParseAsync(current, connection, requestSequence); rt.Add(value); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; previous = current; } else throw new Exception("Error while parsing structured data"); } rt.Seal(); var result = await rt; return result; } public static object ListParser(ParsedTdu tdu, Warehouse warehouse) { var list = new List(); ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; while (length > 0) { current = ParsedTdu.ParseSync(tdu.Data, offset, ends, warehouse); 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 reply = Codec.ParseSync(current, warehouse); list.Add(reply); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; previous = current; } else throw new Exception("Error while parsing structured data"); } return list.ToArray(); } public static (uint, ulong, object[]) LimitedCountListParser(byte[] data, uint offset, ulong length, Warehouse warehouse, uint countLimit = uint.MaxValue) { // @TODO: add TypeContinuation var rt = new List(); while (length > 0 && rt.Count < countLimit) { var (cs, reply) = Codec.ParseSync(data, offset, warehouse); rt.Add(reply); if (cs > 0) { offset += (uint)cs; length -= (uint)cs; } else throw new Exception("Error while parsing structured data"); } return (offset, length, rt.ToArray()); } public static async AsyncReply TypedMapParserAsync(ParsedTdu tdu, Tru keyTru, Tru valueTru, EpConnection connection, uint[] requestSequence) { var rt = new AsyncReply(); // get key type //var (keyCs, keysTru) = Tru.Parse(tdu.Metadata, 0); //var (valueCs, valuesTru) = Tru.Parse(tdu.Metadata, keyCs); var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType( keyTru.RuntimeType, valueTru.RuntimeType)); var keysTdu = await ParsedTdu.ParseAsync(tdu.Data, tdu.PayloadOffset, (uint)(tdu.PayloadOffset + tdu.PayloadLength), connection); var valuesTdu = await ParsedTdu.ParseAsync(tdu.Data, (uint)(keysTdu.PayloadOffset + keysTdu.PayloadLength), tdu.Ends, connection); //var keysReply = TypedArrayParserAsync(keysTdu, keyTru, connection, requestSequence); //var valuesReply = TypedArrayParserAsync(valuesTdu, valueTru, connection, requestSequence); //keysReply.Then(keys => //{ // valuesReply.Then(values => // { // for (var i = 0; i < ((Array)keys).Length; i++) // map.Add(((Array)keys).GetValue(i), ((Array)values).GetValue(i)); // rt.Trigger(map); // }).Error(e => rt.TriggerError(e)); //}).Error(e => rt.TriggerError(e)); //return rt; var keys = await TypedArrayParserAsync2(keysTdu, keyTru, connection, requestSequence); var values = await TypedArrayParserAsync2(valuesTdu, valueTru, connection, requestSequence); for (var i = 0; i < ((Array)keys).Length; i++) map.Add(((Array)keys).GetValue(i), ((Array)values).GetValue(i)); return map; //// get key type //var (keyCs, keyRepType) = TRU.Parse(tdu.Metadata, 0); //var (valueCs, valueRepType) = TRU.Parse(tdu.Metadata, keyCs); //var wh = connection.Instance.Warehouse; //var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType(keyRepType.GetRuntimeType(wh), valueRepType.GetRuntimeType(wh))); //var rt = new AsyncReply(); //var results = new AsyncBag(); //var offset = tdu.Offset; //var length = tdu.ContentLength; //while (length > 0) //{ // var (cs, reply) = Codec.ParseAsync(tdu.Data, offset, connection, requestSequence); // results.Add(reply); // if (cs > 0) // { // offset += (uint)cs; // length -= (uint)cs; // } // else // throw new Exception("Error while parsing structured data"); //} //results.Seal(); //results.Then(ar => //{ // for (var i = 0; i < ar.Length; i += 2) // map.Add(ar[i], ar[i + 1]); // rt.Trigger(map); //}); //return rt; } public static Array TypedArrayParser(ParsedTdu tdu, Tru elementTru, Warehouse warehouse) { switch (elementTru.Identifier) { case TruIdentifier.Int32: return GroupInt32Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength)); case TruIdentifier.Int64: return GroupInt64Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength)); case TruIdentifier.Int16: return GroupInt16Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength)); case TruIdentifier.UInt32: return GroupUInt32Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength)); case TruIdentifier.UInt64: return GroupUInt64Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength)); case TruIdentifier.UInt16: return GroupUInt16Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength)); //case TruIdentifier.Enum: // var enumType = tru.GetRuntimeType(warehouse); // var enums = Array.CreateInstance(enumType, (int)tdu.ContentLength); // var enumTypeDef = warehouse.GetTypeDefByType(enumType); // for (var i = 0; i < (int)tdu.ContentLength; i++) // { // var index = tdu.Data[tdu.Offset + i]; // enums.SetValue(enumTypeDef.Constants[index].Value, i); // } // return enums; default: var list = new List(); ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; while (length > 0) { current = ParsedTdu.ParseSync(tdu.Data, offset, ends, warehouse); 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; } else if (current.Identifier == TduIdentifier.TypeOfTarget) { //var (idf, mt) = tru.GetMetadata(); current.Class = TduClass.Typed; current.Identifier = TduIdentifier.Typed; current.Metadata = elementTru; current.Index = (int)TduIdentifier.Typed & 0x7; } var value = Codec.ParseSync(current, warehouse); list.Add(value); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; previous = current; } else throw new Exception("Error while parsing structured data"); } var runtimeType = elementTru.RuntimeType; var rt = Array.CreateInstance(runtimeType, list.Count); Array.Copy(list.ToArray(), rt, rt.Length); return rt; } } // Non-async/await version of TypedArrayParserAsync using continuations public static AsyncReply TypedArrayParserAsync2(ParsedTdu tdu, Tru elementTru, EpConnection connection, uint[] requestSequence) { switch (elementTru.Identifier) { case TruIdentifier.Int32: return new AsyncReply(GroupInt32Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.Int64: return new AsyncReply(GroupInt64Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.Int16: return new AsyncReply(GroupInt16Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.UInt32: return new AsyncReply(GroupUInt32Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.UInt64: return new AsyncReply(GroupUInt64Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.UInt16: return new AsyncReply(GroupUInt16Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); default: var rt = new AsyncReply(); var list = new AsyncBag(); list.ArrayType = elementTru.RuntimeType; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; // Attach error propagation from bag to our reply list.Error(e => rt.TriggerError(e)); // Recursive processor using continuations Action processNext = null; processNext = (curOffset, curLength, previous) => { if (curLength == 0) { try { list.Seal(); (list as AsyncReply).Then(x => rt.Trigger(x)); } catch (Exception ex) { rt.TriggerError(ex); } return; } ParsedTdu.ParseAsync(tdu.Data, curOffset, ends, connection) .Then(currentObj => { var current = (ParsedTdu)currentObj; if (current.Class == TduClass.Invalid) { rt.TriggerError(new AsyncException(ErrorType.Management, 0, "Unknown type.")); return; } if (current.Identifier == TduIdentifier.TypeContinuation) { if (previous.HasValue) { current.Class = previous.Value.Class; current.Identifier = previous.Value.Identifier; current.Metadata = previous.Value.Metadata; } } else if (current.Identifier == TduIdentifier.TypeOfTarget) { current.Class = TduClass.Typed; current.Identifier = TduIdentifier.Typed; current.Metadata = elementTru; current.Index = (int)TduIdentifier.Typed & 0x7; } var reply = Codec.ParseAsync(current, connection, requestSequence); list.Add(reply); if (current.TotalLength > 0) { var nextOffset = curOffset + (uint)current.TotalLength; var nextLength = curLength - (uint)current.TotalLength; processNext(nextOffset, nextLength, current); } else { rt.TriggerError(new AsyncException(ErrorType.Management, 0, "Error while parsing structured data")); return; } }) .Error(e => rt.TriggerError(e)); }; // start processing processNext(offset, (uint)length, null); return rt; } } public static object TypedMapParser(ParsedTdu tdu, Tru keyTru, Tru valueTru, Warehouse warehouse) { // get key type //var (keyCs, keysTru) = Tru.Parse(tdu.Metadata, 0); //var (valueCs, valuesTru) = Tru.Parse(tdu.Metadata, keyCs); var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType(keyTru.RuntimeType, valueTru.RuntimeType)); var keysTdu = ParsedTdu.ParseSync(tdu.Data, tdu.PayloadOffset, (uint)(tdu.PayloadOffset + tdu.PayloadLength), warehouse); var valuesTdu = ParsedTdu.ParseSync(tdu.Data, (uint)(keysTdu.PayloadOffset + keysTdu.PayloadLength), tdu.Ends, warehouse); var keys = TypedArrayParser(keysTdu, keyTru, warehouse); var values = TypedArrayParser(valuesTdu, valueTru, warehouse); for (var i = 0; i < keys.Length; i++) map.Add(keys.GetValue(i), values.GetValue(i)); return map; } public static async AsyncReply TupleParserAsync(ParsedTdu tdu, Tru[] subTrus, EpConnection connection, uint[] requestSequence) { var rt = new AsyncReply(); // var tupleSize = tdu.Metadata[0]; //var trus = new List(); //uint mtOffset = 0; //while (mtOffset < tru.Length) //{ // var (cs, tru) = Tru.Parse(tdu.Metadata, mtOffset); // trus.Add(tru); // mtOffset += cs; //} var results = new AsyncBag(); var subTypes = subTrus.Select(x => x.RuntimeType).ToArray(); ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; for (var i = 0; i < subTypes.Length; i++) { current = await ParsedTdu.ParseAsync(tdu.Data, offset, ends, connection); if (current.Class == TduClass.Invalid) throw new Exception("Unknown type."); if (current.Identifier == TduIdentifier.TypeOfTarget) { //var (idf, mt) = trus[i].GetMetadata(); current.Class = TduClass.Typed; current.Identifier = TduIdentifier.Typed;// idf; current.Metadata = subTrus[i];// mt; current.Index = (int)(TduIdentifier.Typed) & 0x7;// idf & 0x7; } // var (_, reply) var value = Codec.ParseAsync(current, connection, requestSequence); results.Add(value); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; } else throw new Exception("Error while parsing structured data"); } results.Seal(); var ar = await results; if (ar.Length == 2) { var type = typeof(ValueTuple<,>).MakeGenericType(subTypes.ToArray()); return Activator.CreateInstance(type, ar[0], ar[1]); } else if (ar.Length == 3) { var type = typeof(ValueTuple<,,>).MakeGenericType(subTypes.ToArray()); return Activator.CreateInstance(type, ar[0], ar[1], ar[2]); } else if (ar.Length == 4) { var type = typeof(ValueTuple<,,,>).MakeGenericType(subTypes.ToArray()); return Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3]); } else if (ar.Length == 5) { var type = typeof(ValueTuple<,,,,>).MakeGenericType(subTypes.ToArray()); return Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3], ar[4]); } else if (ar.Length == 6) { var type = typeof(ValueTuple<,,,,,>).MakeGenericType(subTypes.ToArray()); return Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3], ar[4], ar[5]); } else if (ar.Length == 7) { var type = typeof(ValueTuple<,,,,,,>).MakeGenericType(subTypes.ToArray()); return Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3], ar[4], ar[5], ar[6]); } throw new Exception("Unknown tuple size."); //results.Then(ar => // { // if (ar.Length == 2) // { // var type = typeof(ValueTuple<,>).MakeGenericType(subTypes.ToArray()); // rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1])); // } // else if (ar.Length == 3) // { // var type = typeof(ValueTuple<,,>).MakeGenericType(subTypes.ToArray()); // rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1], ar[2])); // } // else if (ar.Length == 4) // { // var type = typeof(ValueTuple<,,,>).MakeGenericType(subTypes.ToArray()); // rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3])); // } // else if (ar.Length == 5) // { // var type = typeof(ValueTuple<,,,,>).MakeGenericType(subTypes.ToArray()); // rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3], ar[4])); // } // else if (ar.Length == 6) // { // var type = typeof(ValueTuple<,,,,,>).MakeGenericType(subTypes.ToArray()); // rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3], ar[4], ar[5])); // } // else if (ar.Length == 7) // { // var type = typeof(ValueTuple<,,,,,,>).MakeGenericType(subTypes.ToArray()); // rt.Trigger(Activator.CreateInstance(type, ar[0], ar[1], ar[2], ar[3], ar[4], ar[5], ar[6])); // } // }); //return rt; } public static object TupleParser(ParsedTdu tdu, Tru[] subTrus, Warehouse warehouse) { var tupleSize = subTrus.Length; var trus = new List(); //uint mtOffset = 1; //for (var i = 0; i < tupleSize; i++) //{ // var (cs, tru) = Tru.Parse(tdu.Metadata, mtOffset); // trus.Add(tru); // mtOffset += cs; //} var results = new List(); var types = subTrus.Select(x => x.RuntimeType).ToArray(); ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; for (var i = 0; i < tupleSize; i++) { current = ParsedTdu.ParseSync(tdu.Data, offset, ends, warehouse); if (current.Class == TduClass.Invalid) throw new Exception("Unknown type."); if (current.Identifier == TduIdentifier.TypeOfTarget) { //var (idf, mt) = trus[i].GetMetadata(); current.Class = TduClass.Typed; current.Identifier = TduIdentifier.Typed; current.Metadata = subTrus[i]; current.Index = (int)TduIdentifier.Typed & 0x7; } var reply = Codec.ParseSync(current, warehouse); results.Add(reply); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; } else throw new Exception("Error while parsing structured data"); } if (results.Count == 2) { var type = typeof(ValueTuple<,>).MakeGenericType(types); return Activator.CreateInstance(type, results[0], results[1]); } else if (results.Count == 3) { var type = typeof(ValueTuple<,,>).MakeGenericType(types); return Activator.CreateInstance(type, results[0], results[1], results[2]); } else if (results.Count == 4) { var type = typeof(ValueTuple<,,,>).MakeGenericType(types); return Activator.CreateInstance(type, results[0], results[1], results[2], results[3]); } else if (results.Count == 5) { var type = typeof(ValueTuple<,,,,>).MakeGenericType(types); return Activator.CreateInstance(type, results[0], results[1], results[2], results[3], results[4]); } else if (results.Count == 6) { var type = typeof(ValueTuple<,,,,,>).MakeGenericType(types); return Activator.CreateInstance(type, results[0], results[1], results[2], results[3], results[4], results[5]); } else if (results.Count == 7) { var type = typeof(ValueTuple<,,,,,,>).MakeGenericType(types); return Activator.CreateInstance(type, results[0], results[1], results[2], results[3], results[4], results[5], results[6]); } throw new Exception("Unknown tuple length."); } public static async AsyncReply TypedArrayParserAsyncOld(ParsedTdu tdu, Tru elementTru, EpConnection connection, uint[] requestSequence) { switch (elementTru.Identifier) { case TruIdentifier.Int32: return new AsyncReply(GroupInt32Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.Int64: return new AsyncReply(GroupInt64Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.Int16: return new AsyncReply(GroupInt16Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.UInt32: return new AsyncReply(GroupUInt32Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.UInt64: return new AsyncReply(GroupUInt64Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); case TruIdentifier.UInt16: return new AsyncReply(GroupUInt16Codec.Decode(tdu.Data.AsSpan( (int)tdu.PayloadOffset, (int)tdu.PayloadLength))); //case TruIdentifier.Enum: // var enumType = elementTru.GetRuntimeType(connection.Instance.Warehouse); // var rt = Array.CreateInstance(enumType, (int)tdu.ContentLength); // var enumTypeDef = connection.Instance.Warehouse.GetTypeDefByType(enumType); // for (var i = 0; i < (int)tdu.ContentLength; i++) // { // var index = tdu.Data[tdu.Offset + i]; // rt.SetValue(Enum.ToObject(enumType, enumTypeDef.Constants[index].Value), i); // } // return new AsyncReply(rt); default: var list = new AsyncBag(); list.ArrayType = elementTru.RuntimeType; ParsedTdu current; ParsedTdu? previous = null; var offset = tdu.PayloadOffset; var length = tdu.PayloadLength; var ends = offset + (uint)length; while (length > 0) { current = await ParsedTdu.ParseAsync(tdu.Data, offset, ends, connection); 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; } else if (current.Identifier == TduIdentifier.TypeOfTarget) { //var (idf, mt) = tru.GetMetadata(); current.Class = TduClass.Typed; current.Identifier = TduIdentifier.Typed;// idf; current.Metadata = elementTru;// mt; current.Index = (int)TduIdentifier.Typed & 0x7;// (int)idf & 0x7; } //var (cs, reply) var reply = Codec.ParseAsync(current, connection, requestSequence); list.Add(reply); if (current.TotalLength > 0) { offset += (uint)current.TotalLength; length -= (uint)current.TotalLength; previous = current; } else throw new Exception("Error while parsing structured data"); } list.Seal(); return await list; } } //public static AsyncReply TypedListParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) //{ // // get the type // var (hdrCs, tru) = Tru.Parse(tdu.Metadata, 0); // return TypedArrayParserAsync(tdu, tru, connection, requestSequence); // //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: // // var rt = new AsyncBag(); // // 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; // // } // // var (cs, reply) = Codec.ParseAsync(tdu.Data, offset, connection, requestSequence); // // rt.Add(reply); // // if (cs > 0) // // { // // offset += (uint)cs; // // length -= (uint)cs; // // } // // else // // throw new Exception("Error while parsing structured data"); // // } // // rt.Seal(); // // return rt; // //} //} public static AsyncReply TypedObjectParserAsync(ParsedTdu tdu, TypeDef typeDef, EpConnection connection, uint[] requestSequence) { // get the TypeDef var warehouse = connection.Instance.Warehouse; //TypeDef typeDef = null; var rt = new AsyncReply(); if (typeDef.Kind == TypeDefKind.Record) { // parse record RecordParserAsync(tdu, typeDef, connection, requestSequence) .Then(x => rt.Trigger(x)) .Error(e => rt.TriggerError(e)); } else if (typeDef.Kind == TypeDefKind.Enum) { // paese enum EnumParserAsync(tdu, typeDef, connection, requestSequence) .Then(x => rt.Trigger(x)) .Error(e => rt.TriggerError(e)); } else// if (td.Kind == TypeDefKind.Resource) { // parse resource : this is kept for future support throw new Exception("Typed resource parsing is not supported yet."); } //if (typeDefId.Remote) //{ // typeDef = warehouse.GetRemoteTypeDefById(connection.RemoteDomain, typeDefId.Value); // if (typeDef == null) // { // // get it from the other end // connection.GetTypeDefById(typeDefId.Value) // .Then(x => parseTyped(x)) // .Error(x => rt.TriggerError(x)); // } //} //else //{ // typeDef = warehouse.GetLocalTypeDefById(typeDefId.Value); // if (typeDef == null) // { // throw new Exception("Bad TypeDefId."); // } // parseTyped(typeDef); //} return rt; } public static object TypedObjectParser(ParsedTdu tdu, TypeDef typeDef, Warehouse warehouse) { // get the TypeDef if (typeDef.Kind == TypeDefKind.Record) { // parse record return RecordParser(tdu, typeDef as LocalTypeDef, warehouse); } else if (typeDef.Kind == TypeDefKind.Enum) { // paese enum return EnumParser(tdu, typeDef as LocalTypeDef, warehouse); } else// if (td.Kind == TypeDefKind.Resource) { // parse resource : this is kept for future support throw new Exception("Typed resource parsing is not supported yet."); } } public static AsyncReply TypedParserAsync(ParsedTdu tdu, EpConnection connection, uint[] requestSequence) { var tru = tdu.Metadata; // do we need to get all subtypes typedefs here ? if (tru is TruComposite truComposite) { return tru.Identifier switch { TruIdentifier.TypedList => TypedArrayParserAsync2(tdu, truComposite.SubTypes[0], connection, requestSequence), TruIdentifier.TypedMap => TypedMapParserAsync(tdu, truComposite.SubTypes[0], truComposite.SubTypes[1], connection, requestSequence), TruIdentifier.Tuple2 => TupleParserAsync(tdu, truComposite.SubTypes, connection, requestSequence), TruIdentifier.Tuple3 => TupleParserAsync(tdu, truComposite.SubTypes, connection, requestSequence), TruIdentifier.Tuple4 => TupleParserAsync(tdu, truComposite.SubTypes, connection, requestSequence), TruIdentifier.Tuple5 => TupleParserAsync(tdu, truComposite.SubTypes, connection, requestSequence), TruIdentifier.Tuple6 => TupleParserAsync(tdu, truComposite.SubTypes, connection, requestSequence), TruIdentifier.Tuple7 => TupleParserAsync(tdu, truComposite.SubTypes, connection, requestSequence), _ => throw new Exception("Unsupported type for typed parser.") }; } else if (tru is TruTypeDef truTypeDef) { return TypedObjectParserAsync(tdu, truTypeDef.TypeDef, connection, requestSequence); } throw new Exception("Unknown TRU."); } public static object TypedParser(ParsedTdu tdu, Warehouse warehouse) { var tru = tdu.Metadata; // do we need to get all subtypes typedefs here ? if (tru is TruComposite truComposite) { return tru.Identifier switch { TruIdentifier.TypedList => TypedArrayParser(tdu, truComposite.SubTypes[0], warehouse), TruIdentifier.TypedMap => TypedMapParser(tdu, truComposite.SubTypes[0], truComposite.SubTypes[1], warehouse), TruIdentifier.Tuple2 => TupleParser(tdu, truComposite.SubTypes, warehouse), TruIdentifier.Tuple3 => TupleParser(tdu, truComposite.SubTypes, warehouse), TruIdentifier.Tuple4 => TupleParser(tdu, truComposite.SubTypes, warehouse), TruIdentifier.Tuple5 => TupleParser(tdu, truComposite.SubTypes, warehouse), TruIdentifier.Tuple6 => TupleParser(tdu, truComposite.SubTypes, warehouse), TruIdentifier.Tuple7 => TupleParser(tdu, truComposite.SubTypes, warehouse), _ => throw new Exception("Unsupported type for typed parser.") }; } else if (tru is TruTypeDef truTypeDef) { return TypedObjectParser(tdu, truTypeDef.TypeDef, warehouse); } throw new Exception("Unknown TRU."); } public static AsyncBag PropertyValueArrayParserAsync(byte[] data, uint offset, uint length, EpConnection connection, uint[] requestSequence)//, bool ageIncluded = true) { var rt = new AsyncBag(); ListParserAsync(new ParsedTdu() { Data = data, PayloadOffset = offset, PayloadLength = length } , connection, requestSequence).Then(x => { var ar = (object[])x; var pvs = new List(); for (var i = 0; i < ar.Length; i += 3) pvs.Add(new PropertyValue(ar[i + 2], Convert.ToUInt64(ar[i]), (DateTime?)ar[i + 1])); rt.Trigger(pvs.ToArray()); }); return rt; } public static async AsyncReply> PropertyValueParserAsync(byte[] data, uint offset, EpConnection connection, uint[] requestSequence)//, bool ageIncluded = true) { // var reply = new AsyncReply(); var age = data.GetUInt64(offset, Endian.Little); offset += 8; DateTime date = data.GetDateTime(offset, Endian.Little); offset += 8; //var (valueSize, results) = var pr = await Codec.ParseAsync(data, offset, connection, requestSequence); if (pr.Value is AsyncReply asycReply) { var value = await asycReply; return new ParseResult(new PropertyValue(value, age, date), 16 + pr.Size); //asycReply.Then(value => //{ // reply.Trigger(new PropertyValue(value, age, date)); //}); } else { return new ParseResult(new PropertyValue(pr.Value, age, date), 16 + pr.Size); //reply.Trigger(new PropertyValue(results, age, date)); } // return (16 + valueSize, reply); } public static async AsyncReply> HistoryParserAsync(byte[] data, uint offset, uint length, IResource resource, EpConnection connection, uint[] requestSequence) { //var count = (int)toAge - (int)fromAge; var list = new KeyList(); var reply = new AsyncReply>(); var bagOfBags = new AsyncBag(); var ends = offset + length; while (offset < ends) { var index = data[offset++]; var pt = resource.Instance.Definition.GetPropertyDefByIndex(index); list.Add(pt, null); var cs = data.GetUInt32(offset, Endian.Little); offset += 4; //var (len, pv) = var pr = await PropertyValueParserAsync(data, offset, connection, requestSequence); bagOfBags.Add(pr.Value);// ParsePropertyValueArray(data, offset, cs, connection)); offset += pr.Size; } bagOfBags.Seal(); var x = await bagOfBags; for (var i = 0; i < list.Count; i++) list[list.Keys.ElementAt(i)] = x[i]; return list; //bagOfBags.Then(x => //{ // for (var i = 0; i < list.Count; i++) // list[list.Keys.ElementAt(i)] = x[i]; // reply.Trigger(list); //}); //return reply; } }