private static bool TypeIsValidSerializer(Type t) { if (t.IsValueType) { SerializationLogger.LogError($"(De)serializer {t.PrettyName()} is a value type, which is not allowed"); return(false); } var constructor = t.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (constructor == null) { SerializationLogger.LogError($"(De)serializer {t.PrettyName()} doesn't have a parameterless constructor"); return(false); } return(true); }
public override AContainer <BinaryStream> LoadContainer(string name, bool writable, bool errorIfNotExist = true) { // all saved in memory containers are considered as writable AContainer <BinaryStream> container = null; if (_containerPositions.TryGetValue(name, out PosLen containerPosLen)) { _storage.Seek(containerPosLen.Position, SeekOrigin.Begin); var data = new byte[containerPosLen.Length]; _storage.Read(data, 0, data.Length); var memStream = CreateMemoryStream(data, writable); var binStream = new BinaryStream(memStream, writable); container = new BinaryContainer(binStream, _serializers); } else if (errorIfNotExist) { SerializationLogger.LogError($"Container '{name}' does not exist in {this.PrettyTypeName()}"); } return(container); }
public override AContainer <BinaryStream> LoadContainer(string name, bool writable = false, bool errorIfNotExist = true) { // all files are considered as writable string filePath = GetFilePath(name); if (!File.Exists(filePath)) { if (errorIfNotExist) { SerializationLogger.LogError($"File '{filePath}' does not exist"); } return(null); } var data = File.ReadAllBytes(filePath); var memStream = CreateMemoryStream(data, writable); var binStream = new BinaryStream(memStream, writable); var container = new BinaryContainer(binStream, _serializers); return(container); }
public static bool CreateFile(string filePath) { var directory = Directory.GetParent(filePath).FullName; if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } if (!Directory.Exists(directory)) { SerializationLogger.LogError($"Unable to create directory '{directory}'"); return(false); } File.WriteAllText(filePath, ""); if (!File.Exists(filePath)) { SerializationLogger.LogError($"Unable to create file '{filePath}'"); return(false); } return(true); }
private void Init(List <TypeIdAttribute> typeIds, List <ISerializer> serializers, List <IDeserializer> deserializers) { _typeInfos = new List <SerializationTypeInfo>(typeIds.Count); _typeToIndex = new Dictionary <Type, ushort>(typeIds.Count); _idToIndex = new Dictionary <int, ushort>(typeIds.Count); foreach (var typeId in typeIds) { var t = typeId.Type; // duplicate checks if (_typeToIndex.TryGetValue(t, out var conflictIndex)) { var conflictId = _typeInfos[conflictIndex].Id; throw new Exception($"Type {t.PrettyName()} was marked by {typeof(TypeIdAttribute).PrettyName()} multiple times: id {conflictId} and id {typeId.Id} on type {typeId.AttributeOnType.PrettyName()}"); } if (_idToIndex.TryGetValue(typeId.Id, out conflictIndex)) { var conflictType = _typeInfos[conflictIndex].Type; throw new Exception($"Types {t.PrettyName()} and {conflictType.PrettyName()} have the same {typeof(TypeIdAttribute).PrettyName()} id value {typeId.Id}"); } ushort index = _typeInfos.Count.ToUInt16(); _typeInfos.Add(new SerializationTypeInfo(typeId)); _typeToIndex.Add(t, index); _idToIndex.Add(typeId.Id, index); } _serializerInfos = new List <SerializerInfo>(serializers.Count + 1); foreach (var s in serializers) { var sGenericDefinition = typeof(ISerializer <,>); var sInterface = s.GetType().ImplementsGenericInterfaceDefinition(sGenericDefinition); if (sInterface == null) { throw new Exception($"Serializer {s.GetType().PrettyName()} does not implement interface {sGenericDefinition.PrettyName()}"); } var arguments = sInterface.GetGenericArguments(); Type oType = arguments[0]; if (oType.IsAbstract | oType.IsInterface) { continue; } if (!typeof(TStream).IsAssignableFrom(arguments[1])) { continue; } if (!_typeToIndex.TryGetValue(oType, out var sTypeIndex)) { throw new Exception($"Serializer {s.PrettyTypeName()} works with type {oType.PrettyName()} which is not marked with {typeof(TypeIdAttribute).PrettyName()}"); } if (s.Version <= 0 | s.Version > MAX_VERSION) { throw new Exception($"Serializer {s.PrettyTypeName()} has invalid version {s.Version}, should be in range 1..{MAX_VERSION}"); } _serializerInfos.Add(new SerializerInfo() { TypeId = _typeInfos[sTypeIndex].Id, Version = s.Version, Serializer = s as ISerializer <TStream> }); } _serializerInfos.Sort((x, y) => { var comp = x.TypeId.CompareTo(y.TypeId); if (comp == 0) { comp = y.Version.CompareTo(x.Version); } return(comp); }); for (int i = _serializerInfos.Count - 1; i >= 0; i--) { var sInfo = _serializerInfos[i]; bool highestVersion = i == 0 || _serializerInfos[i - 1].TypeId != sInfo.TypeId; if (highestVersion) { var index = _idToIndex[sInfo.TypeId]; var tInfo = _typeInfos[index]; tInfo.InitSerializers(i, sInfo.Serializer); _typeInfos[index] = tInfo; } else { var nextInfo = _serializerInfos[i - 1]; if (nextInfo.Version == sInfo.Version) { throw new Exception($"Serializers {sInfo.Serializer.PrettyTypeName()} and {nextInfo.Serializer.PrettyTypeName()} have the same version {sInfo.Version}"); } } } _deserializerInfos = new List <DeserializerInfo>(deserializers.Count + 1); foreach (var d in deserializers) { var dGenericDefinition = typeof(IDeserializer <,>); var dInterface = d.GetType().ImplementsGenericInterfaceDefinition(dGenericDefinition); if (dInterface == null) { throw new Exception($"Deserializer {d.PrettyTypeName()} does not implement interface {dGenericDefinition.PrettyName()}"); } var arguments = dInterface.GetGenericArguments(); Type oType = arguments[0]; if (oType.IsAbstract | oType.IsInterface) { continue; } if (!typeof(TStream).IsAssignableFrom(arguments[1])) { continue; } if (!_typeToIndex.TryGetValue(oType, out var dTypeIndex)) { throw new Exception($"Deserializer {d.PrettyTypeName()} works with type {oType.PrettyName()} which is not marked with {typeof(TypeIdAttribute).PrettyName()}"); } if (d.Version <= 0 | d.Version > MAX_VERSION) { throw new Exception($"Deserializer {d.PrettyTypeName()} has invalid version {d.Version}, should be in range 1..{MAX_VERSION}"); } _deserializerInfos.Add(new DeserializerInfo() { TypeId = _typeInfos[dTypeIndex].Id, Version = d.Version, Deserializer = d as IDeserializer <TStream> }); } _deserializerInfos.Sort((x, y) => { var comp = x.TypeId.CompareTo(y.TypeId); if (comp == 0) { comp = y.Version.CompareTo(x.Version); } return(comp); }); for (int i = _deserializerInfos.Count - 1; i >= 0; i--) { var dInfo = _deserializerInfos[i]; if (i > 0) { var nextInfo = _deserializerInfos[i - 1]; if (nextInfo.TypeId == dInfo.TypeId & nextInfo.Version == dInfo.Version) { throw new Exception($"Deserializers {dInfo.Deserializer.PrettyTypeName()} and {nextInfo.Deserializer.PrettyTypeName()} have the same version {dInfo.Version}"); } } var index = _idToIndex[dInfo.TypeId]; var tInfo = _typeInfos[index]; tInfo.InitDeserializers(i); _typeInfos[index] = tInfo; } var report = $"{this.PrettyTypeName()} initialized with {_serializerInfos.Count} serializers, {_deserializerInfos.Count} deserializers and {_typeInfos.Count} types"; SerializationLogger.Log(report); // to reduce conditions in some inner loops in search of required (de)serializers _serializerInfos.Add(new SerializerInfo() { TypeId = -1 }); _deserializerInfos.Add(new DeserializerInfo() { TypeId = -1 }); }