예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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
            });
        }