static T GetScheme <T>(IContract contract, DsdlType derivedScheme) where T : DsdlType { T result = null; var schemeFromContract = contract.DsdlType; if (schemeFromContract != null) { result = schemeFromContract as T; if (result == null) { throw new InvalidOperationException($"Unexpected DSDL type for type '{contract.UnderlyingType.FullName}'."); } } if (derivedScheme != null) { if (result != null && result != derivedScheme) { throw new InvalidOperationException($"DSDL scheme mismatch for type '{contract.UnderlyingType.FullName}'."); } result = derivedScheme as T; if (result == null) { throw new InvalidOperationException($"Unexpected DSDL type for type '{contract.UnderlyingType.FullName}'."); } } if (result == null) { throw new InvalidOperationException($"Unexpected DSDL type for type '{contract.UnderlyingType.FullName}'."); } return(result); }
object CreateValueInternal( BitStreamReader reader, IContract contract, DsdlProperty member, ContainerContract containerContract, DsdlProperty containerMember, object existingValue, DsdlType scheme, Type objectType, bool tailArrayOptimization = false) { switch (scheme) { case VoidDsdlType t: ReadAlignment(reader, t); return(null); case PrimitiveDsdlType t: var primitive = ReadPrimitiveType(reader, t); return(EnsureType(reader, primitive, CultureInfo.InvariantCulture, contract, objectType)); case ArrayDsdlType t when t.IsStringLike && contract.UnderlyingType == typeof(string): var list = CreateList(reader, StringContract, member, null, t, tailArrayOptimization) as IEnumerable <byte>; return(_encoding.GetString(list.ToArray())); case ArrayDsdlType t: return(CreateList(reader, contract, member, existingValue, t, tailArrayOptimization)); case CompositeDsdlTypeBase t: return(CreateObject(reader, contract, member, containerContract, containerMember, existingValue, objectType, t, tailArrayOptimization)); default: throw new ArgumentOutOfRangeException(nameof(scheme)); } }
static void Print(object obj, StringBuilder sb, int tabs, DsdlType scheme) { if (obj is null) { return; } switch (scheme) { case CompositeDsdlTypeBase t: PrintObject(obj, sb, tabs, t); break; case ArrayDsdlType t when t.IsStringLike: PrintString(obj, sb); break; case ArrayDsdlType t: PrintArray(obj, sb, tabs, t); break; default: PrintPrimitive(obj, sb); break; } }
string GetCSharpType(DsdlType type, bool nullable, string name) { if (name != null) { if (IsEnum(name, type)) { var enumType = GetOrCreateEnum(name, type); return(nullable ? enumType + "?" : enumType); } if (IsString(name, type)) { return("string"); } } switch (type) { case VoidDsdlType _: return(null); case PrimitiveDsdlType t: return(nullable ? GetCSharpType(t) + "?" : GetCSharpType(t)); case ArrayDsdlType t: return(GetCSharpType(t.ElementType, false, name) + "[]"); case CompositeDsdlTypeBase t: return(_compoundTypesLookup[t].CSharpName); default: throw new InvalidOperationException(); } }
static bool CheckDsdlTypeCompatibility(DsdlType schemeType, IContract actualContract) { switch (schemeType) { case PrimitiveDsdlType _: if (!(actualContract is PrimitiveContract)) { return(false); } break; case ArrayDsdlType adt when adt.IsStringLike && actualContract.UnderlyingType == typeof(string): break; case ArrayDsdlType _: if (!(actualContract is ArrayContract)) { return(false); } break; case CompositeDsdlTypeBase dt: if (dt != actualContract.DsdlType) { return(false); } break; } return(true); }
public static string PrintToString(object obj, DsdlType scheme) { var sb = new StringBuilder(); Print(obj, sb, 0, scheme); return(sb.ToString()); }
string GetOrCreateEnum(string name, DsdlType type) { var ut = GetCSharpType(type as PrimitiveDsdlType); var key = "Enum_" + ut; if (!_helperTypes.ContainsKey(key)) { _helperTypes[key] = $" public enum {key} : {ut} {{}}"; } return(key); }
public object Deserialize(Memory <byte> memory, DsdlType dsdlScheme, IContract contract = null) { if (dsdlScheme == null) { throw new ArgumentNullException(nameof(dsdlScheme)); } var stream = new BitStreamReader(memory); var reader = new DsdlSerializerReader(this); return(reader.Deserialize(stream, dsdlScheme, contract)); }
string BuildPythonInitializerMemberElement(DsdlType type, string fieldName, ParseTreeNode node) { switch (type) { case PrimitiveDsdlType _: var text = node.GetText(SourceText); switch (text) { case "true": text = "True"; break; case "false": text = "False"; break; case "null": text = "None"; break; } if (text.EndsWith("f", StringComparison.OrdinalIgnoreCase) && node.FindToken()?.Value is float) // Remove float 'f' suffix. { text = text.Substring(0, text.Length - 1); } return(text); case ArrayDsdlType adt when IsString(fieldName, type): return(node.GetText(SourceText)); case ArrayDsdlType adt: var nestesNodes = node.FindChild("members"); if (nestesNodes == null) { return("[]"); } var arrayContent = nestesNodes.ChildNodes.Select(x => BuildPythonInitializerMemberElement(adt.ElementType, fieldName, x)); return($"[{string.Join(", ", arrayContent)}]"); case CompositeDsdlTypeBase cdt: var t = _compoundTypesLookup[cdt]; return($"{t.Namespace}.{t.Name}(" + string.Join(", ", BuildPythonInitializerMembers(cdt.Fields, node.FindChild("members"))) + ")"); default: throw new InvalidOperationException(); } }
static bool IsSingleLineType(DsdlType type) { switch (type) { case ArrayDsdlType t when t.IsStringLike: return(true); case PrimitiveDsdlType _: return(true); default: return(false); } }
public int Serialize(object value, DsdlType dsdlScheme, Memory <byte> memory) { if (value == null) { throw new ArgumentNullException(nameof(value)); } var streamWriter = new BitStreamWriter(memory); var writer = new DsdlSerializerWriter(this); writer.Serialize(streamWriter, value, dsdlScheme); return(streamWriter.Length); }
public object Deserialize(BitStreamReader reader, DsdlType scheme, IContract contract) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (scheme == null) { throw new ArgumentNullException(nameof(scheme)); } if (HasNoDefinedType(contract)) { return(CreateUnknownObject(reader, scheme, true)); } return(CreateValueInternal(reader, contract, null, null, null, null, scheme, null, true)); }
static string GetCSharpType(DsdlType type, bool nullable) { switch (type) { case VoidDsdlType _: return(null); case PrimitiveDsdlType t: return(nullable ? GetCSharpType(t) + "?" : GetCSharpType(t)); case ArrayDsdlType t: return(GetCSharpType(t.ElementType, false) + "[]"); case CompositeDsdlTypeBase t: return(_namesTypesLookup[t]); default: throw new InvalidOperationException(); } }
static DsdlConstant CreateConstant(DsdlType attrType, string attrName, string expression) { if (!(attrType is PrimitiveDsdlType primitive)) { throw new Exception($"Invalid type for constant {attrName}."); } var value = Evaluate(expression, primitive); if (!primitive.IsInRange(value)) { throw new Exception($"Value {value} is out of range."); } return(new DsdlConstant { Name = attrName, Type = attrType, Value = value, }); }
private void SerializeValue( BitStreamWriter writer, object value, IContract valueContract, DsdlType derivedDsdlType, bool tailArrayOptimization = false) { if (value == null) { throw new ArgumentNullException(nameof(value), "Cannot serialize null value"); } switch (valueContract) { case ObjectContract contract: SerializeObject(writer, value, contract, derivedDsdlType, tailArrayOptimization); break; case ArrayContract contract: if (contract.IsMultidimensionalArray) { throw new NotSupportedException("Multidimensional arrays are not supported."); } SerializeList(writer, (IEnumerable)value, contract, contract.FinalItemContract, derivedDsdlType, tailArrayOptimization); break; case PrimitiveContract contract: SerializePrimitive(writer, value, contract, derivedDsdlType, tailArrayOptimization); break; case DictionaryContract contract: SerializeDictionary(writer, (value is IDictionary dictionary) ? dictionary : contract.CreateWrapper(value), contract, derivedDsdlType, tailArrayOptimization); break; default: throw new ArgumentOutOfRangeException(nameof(valueContract)); } }
string BuildTestMethodMemberElement(DsdlType type, string fieldName, ParseTreeNode node) { if (IsEnum(fieldName, type)) { var enumType = GetOrCreateEnum(fieldName, type); return($"({enumType}){node.GetText(SourceText)}"); } if (IsString(fieldName, type)) { return(node.GetText(SourceText)); } switch (type) { case PrimitiveDsdlType _: return(node.GetText(SourceText)); case ArrayDsdlType adt: var nestesNodes = node.FindChild("members"); if (nestesNodes == null) { return($"new {GetCSharpType(adt, false, fieldName)} {{ }}"); } var arrayContent = nestesNodes.ChildNodes.Select(x => BuildTestMethodMemberElement(adt.ElementType, fieldName, x)); return($"new {GetCSharpType(adt, false, fieldName)} {{ {string.Join(", ", arrayContent)} }}"); case CompositeDsdlTypeBase cdt: var t = _compoundTypesLookup[cdt]; return($"new {t.CSharpName} {{ " + string.Join(", ", BuildTestMethodMembers(cdt.Fields, node.FindChild("members"))) + " }"); default: throw new InvalidOperationException(); } }
void SerializeObject(BitStreamWriter writer, object value, ObjectContract contract, DsdlType derivedDsdlType, bool tailArrayOptimization) { var dsdlScheme = GetScheme <CompositeDsdlTypeBase>(contract, derivedDsdlType); _serializeStack.Push(value); SerializeObjectCore( writer, name => ResolveObjectProperty(value, contract, name), contract, derivedDsdlType, tailArrayOptimization); _serializeStack.Pop(); }
void SerializeDictionary(BitStreamWriter writer, IDictionary values, DictionaryContract contract, DsdlType derivedDsdlType, bool tailArrayOptimization) { object underlyingDictionary = values is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : values; _serializeStack.Push(underlyingDictionary); if (contract.ItemContract == null) { contract.ItemContract = _serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object)); } if (contract.KeyContract == null) { contract.KeyContract = _serializer.ContractResolver.ResolveContract(contract.DictionaryKeyType ?? typeof(object)); } var dictionaryNormalized = PreprocessDictionary(values, contract); SerializeObjectCore( writer, name => ResolveDictionaryProperty(dictionaryNormalized, contract, name), contract, derivedDsdlType, tailArrayOptimization); _serializeStack.Pop(); }
void SerializeObjectCore( BitStreamWriter writer, Func <string, ResolvedProperty?> propertyResolver, ContainerContract containerContract, DsdlType derivedDsdlType, bool tailArrayOptimization) { var dsdlScheme = GetScheme <CompositeDsdlTypeBase>(containerContract, derivedDsdlType); //WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty); VoidDsdlType voidDsdlType = null; int voidDsdlTypeIndex = -1; var isUnion = dsdlScheme.IsUnion; var unionMemberFound = false; for (int i = 0; i < dsdlScheme.Fields.Count; i++) { var dsdlMember = dsdlScheme.Fields[i]; var isLastMember = i == dsdlScheme.Fields.Count - 1; if ((voidDsdlType = (dsdlMember.Type as VoidDsdlType)) != null) { voidDsdlTypeIndex = i; if (!isUnion) { WriteAlignment(writer, voidDsdlType); } continue; } var resolvedProp = propertyResolver(dsdlMember.Name); if (isUnion) { if (resolvedProp == null) { continue; } if (unionMemberFound) { throw new InvalidOperationException($"Cannot find single union value for type '{containerContract.UnderlyingType.FullName}'."); } unionMemberFound = true; WriteUnionFieldIndex(writer, i, dsdlScheme); var rp = resolvedProp.Value; SerializeValue(writer, rp.MemberValue, rp.MemberContact, dsdlMember.Type); } else { if (resolvedProp == null) { throw new InvalidOperationException($"Cannot resove member '{containerContract.UnderlyingType.FullName}.{dsdlMember.Name}'."); } var rp = resolvedProp.Value; var tao = tailArrayOptimization && isLastMember && dsdlMember.Type is ArrayDsdlType adt; SerializeValue(writer, rp.MemberValue, rp.MemberContact, dsdlMember.Type, tao); } } if (isUnion && !unionMemberFound) { if (voidDsdlType != null) { WriteUnionFieldIndex(writer, voidDsdlTypeIndex, dsdlScheme); WriteAlignment(writer, voidDsdlType); } else { throw new InvalidOperationException($"Cannot find union value for '{containerContract.UnderlyingType.FullName}' type."); } } }
void SerializePrimitive(BitStreamWriter writer, object value, PrimitiveContract contract, DsdlType derivedDsdlType, bool tailArrayOptimization) { if (contract.TypeCode == PrimitiveTypeCode.String && derivedDsdlType is ArrayDsdlType adt && adt.IsStringLike) { byte[] stringBytes; if (value == null) { stringBytes = _emptyByteArray; } else { if (!(value is string stringValue)) { throw new ArgumentException("Cannot cast value to string.", nameof(value)); } stringBytes = _encoding.GetBytes(stringValue); } SerializeList(writer, stringBytes, contract, null, adt, tailArrayOptimization); return; } if (!(derivedDsdlType is PrimitiveDsdlType t)) { throw new InvalidOperationException($"Primitive DSDL type expected for type '{contract.UnderlyingType.FullName}'."); } switch (t) { case BooleanDsdlType _: var boolValue = (bool)ConvertUtils.ConvertOrCast(value, CultureInfo.CurrentCulture, typeof(bool)); BitSerializer.Write(writer, boolValue, t.MaxBitlen); break; case IntDsdlType idt: var longValue = (long)ConvertUtils.ConvertOrCast(value, CultureInfo.CurrentCulture, typeof(long)); longValue = ApplyIntegerCastMode(longValue, idt); BitSerializer.Write(writer, longValue, t.MaxBitlen); break; case UIntDsdlType uidt: var ulongValue = (ulong)ConvertUtils.ConvertOrCast(value, CultureInfo.CurrentCulture, typeof(ulong)); ulongValue = ApplyIntegerCastMode(ulongValue, uidt); BitSerializer.Write(writer, ulongValue, t.MaxBitlen); break; case FloatDsdlType fdt: var doubleValue = (double)ConvertUtils.ConvertOrCast(value, CultureInfo.CurrentCulture, typeof(double)); WriteFloatPrimitive(writer, doubleValue, fdt); break; default: throw new ArgumentOutOfRangeException(nameof(t)); } }
object CreateUnknownObject(BitStreamReader reader, DsdlType scheme, bool tailArrayOptimization = false) { switch (scheme) { case VoidDsdlType t: ReadAlignment(reader, t); return(null); case PrimitiveDsdlType t: return(ReadPrimitiveType(reader, t)); case ArrayDsdlType t: switch (t.Mode) { case ArrayDsdlTypeMode.Static: return(ReadStaticArray(reader, t)); case ArrayDsdlTypeMode.Dynamic: return(ReadDynamicArray(reader, t, tailArrayOptimization)); default: throw new ArgumentOutOfRangeException(nameof(ArrayDsdlTypeMode)); } case CompositeDsdlTypeBase t: var dictionary = new Dictionary <string, object>(StringComparer.Ordinal); if (t.IsUnion) { var unionFieldIndex = ReadUnionFieldIndex(reader, t); var field = t.Fields[unionFieldIndex]; if (!(field.Type is VoidDsdlType)) { dictionary[field.Name] = CreateUnknownObject(reader, field.Type); } } else { for (int i = 0; i < t.Fields.Count - 1; i++) { var field = t.Fields[i]; if (!(field.Type is VoidDsdlType)) { dictionary[field.Name] = CreateUnknownObject(reader, field.Type); } } if (t.Fields.Count > 0) { var field = t.Fields[t.Fields.Count - 1]; switch (field.Type) { case VoidDsdlType _: break; case ArrayDsdlType _: dictionary[field.Name] = CreateUnknownObject(reader, field.Type, tailArrayOptimization); break; default: dictionary[field.Name] = CreateUnknownObject(reader, field.Type); break; } } } return(dictionary); default: throw new ArgumentOutOfRangeException(nameof(scheme)); } }
bool SetPropertyValue( DsdlProperty property, ContainerContract containerContract, DsdlProperty containerProperty, BitStreamReader reader, object target, DsdlType scheme, bool tailArrayOptimization) { if (property.Ignored) { return(true); } if (property.PropertyContract == null) { property.PropertyContract = GetContractSafe(property.PropertyType); } bool useExistingValue = false; object currentValue = null; if (property.Readable) { currentValue = property.ValueProvider.GetValue(target); } IContract propertyContract; if (currentValue == null) { propertyContract = property.PropertyContract; } else { propertyContract = GetContractSafe(currentValue.GetType()); useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType()); } var value = CreateValueInternal( reader, propertyContract, property, containerContract, containerProperty, (useExistingValue) ? currentValue : null, scheme, property.PropertyType, tailArrayOptimization); // always set the value if useExistingValue is false, // otherwise also set it if CreateValue returns a new value compared to the currentValue // this could happen because of a JsonConverter against the type if ((!useExistingValue || value != currentValue) && ShouldSetPropertyValue(property, containerContract as ObjectContract, value)) { property.ValueProvider.SetValue(target, value); return(true); } // the value wasn't set be JSON was populated onto the existing value return(useExistingValue); }
void SerializeList( BitStreamWriter writer, IEnumerable values, IContract contract, IContract finalItemContract, DsdlType derivedDsdlType, bool tailArrayOptimization) { if (!(derivedDsdlType is ArrayDsdlType arrayDsdlType)) { throw new InvalidOperationException($"Array DSDL type expected for type '{contract.UnderlyingType.FullName}'."); } object underlyingList = values is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : values; _serializeStack.Push(underlyingList); var arrayCount = values.Count(); switch (arrayDsdlType.Mode) { case ArrayDsdlTypeMode.Dynamic: { if (arrayCount > arrayDsdlType.MaxSize) { throw new SerializationException($"'{contract.UnderlyingType.FullName}' is too big. MaxSize is {arrayDsdlType.MaxSize}."); } if (!tailArrayOptimization || arrayDsdlType.ElementType.MinBitlen < 8) { WriteDynamicArraySize(writer, arrayCount, arrayDsdlType); } else { tailArrayOptimization = false; } break; } case ArrayDsdlTypeMode.Static: { if (arrayCount != arrayDsdlType.MaxSize) { throw new SerializationException($"'{contract.UnderlyingType.FullName}' expected size is {arrayDsdlType.MaxSize}."); } break; } } // Note: an exception from the IEnumerable won't be caught. int i = 0; foreach (object value in values) { i++; var valueContract = finalItemContract ?? (value == null ? null : _serializer.ContractResolver.ResolveContract(value.GetType())); if (!CheckForCircularReference(value, null, valueContract)) { continue; } if (!CheckDsdlTypeCompatibility(arrayDsdlType.ElementType, valueContract)) { throw new InvalidOperationException( $"DSDL type mismatch for enumerated item '{contract.UnderlyingType.FullName}.{valueContract.UnderlyingType}'."); } var tao = i == arrayCount ? tailArrayOptimization : false; SerializeValue(writer, value, valueContract, arrayDsdlType.ElementType, tao); } //writer.WriteEndArray(); _serializeStack.Pop(); }
static bool IsString(string name, DsdlType type) { return(type is ArrayDsdlType adt && adt.IsStringLike && name.StartsWith("t_string_")); }
public void Serialize(BitStreamWriter stream, object value, DsdlType dsdlScheme) { var contract = _serializer.ContractResolver.ResolveContract(value.GetType()); SerializeValue(stream, value, contract, dsdlScheme, true); }
static bool IsEnum(string name, DsdlType type) { return((type is IntDsdlType || type is UIntDsdlType) && name.StartsWith("t_enum_")); }