Esempio n. 1
0
        public void Serialize(ref byte[] buffer, ref int offset, T value)
        {
            if (EqualityComparer <T> .Default.Equals(value, default))
            {
                SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias);
                return;
            }

            if (value is Type type)
            {
                SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, InlineType, Bias);
                _typeFormatter.Serialize(ref buffer, ref offset, type);
                return;
            }

            if (value is IExternalRootObject externalObj)
            {
                if (!object.ReferenceEquals(_serializer.InstanceData.CurrentRoot, value))
                {
                    SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, ExternalObject, Bias);

                    var refId = externalObj.GetReferenceId();
                    SerializerBinary.WriteInt32(ref buffer, ref offset, refId);

                    _serializer.Config.OnExternalObject?.Invoke(externalObj);

                    return;
                }
            }

            if (_serializer.InstanceData.ObjectCache.TryGetExistingObjectId(value, out int id))
            {
                // Existing value
                SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias);
            }
            else
            {
                // Important: Insert the ID for this value into our dictionary BEFORE calling SerializeFirstTime, as that might recursively call us again (maybe with the same value!)
                _serializer.InstanceData.ObjectCache.RegisterObject(value);

                var specificType = value.GetType();
                if (typeof(T) == specificType)
                {
                    // New value (same type)
                    SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValueSameType, Bias);
                }
                else
                {
                    // New value (type included)
                    SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValue, Bias);
                    _typeFormatter.Serialize(ref buffer, ref offset, specificType);
                }

                // Write the object normally
                GetSpecificSerializerDispatcher(specificType)(ref buffer, ref offset, value);
            }
        }
Esempio n. 2
0
        public void Serialize(ref byte[] buffer, ref int offset, Person value)
        {
            SerializerBinary.WriteString(ref buffer, ref offset, value.Name);
            SerializerBinary.WriteInt32(ref buffer, ref offset, value.Health);
            PersonFormatter.Serialize(ref buffer, ref offset, value.BestFriend);

            // Important:
            // You might be tempted to just recursively call Serialize again for 'BestFriend', but that won't work!
            // Do not think you can manually serialize other instances.
            // It may look like that the object injected into "PersonFormatter" is just 'MyCustomPersonFormatter' itself again,
            // but that's not the case!
            // In fact, what you get is a lot of magic behind the scenes that deals with a ton of edge cases (object references, and reference loop handling, and more)
        }
Esempio n. 3
0
        public void Serialize(ref byte[] buffer, ref int offset, T member)
        {
            // Declaring type
            _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType);

            SerializerBinary.WriteInt32(ref buffer, ref offset, (int)member.MemberType);

            switch (member.MemberType)
            {
            // Write all the data we need to resolve overloads
            case MemberTypes.Constructor:
            case MemberTypes.Method:
                var method = (MethodBase)(MemberInfo)member;

                _stringFormatter.Serialize(ref buffer, ref offset, method.Name);

                var args = method.GetParameters();
                SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length);
                for (int i = 0; i < args.Length; i++)
                {
                    _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType);
                }

                break;

            case MemberTypes.Property:
                PropertyInfo prop = (PropertyInfo)(MemberInfo)member;
                _stringFormatter.Serialize(ref buffer, ref offset, prop.Name);
                _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType);
                break;

            case MemberTypes.Field:
                FieldInfo field = (FieldInfo)(MemberInfo)member;
                _stringFormatter.Serialize(ref buffer, ref offset, field.Name);
                _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType);

                break;

            default:
                throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'");
            }
        }
Esempio n. 4
0
            public Ceras.Formatters.IFormatter <IEqualityComparer <byte?[]> > _comparerFormatter; // auto-implemented by Ceras using DynamicObjectFormatter

            public void Serialize(ref byte[] buffer, ref int offset, HashSet <byte?[]> set)
            {
                // What do we need?
                // - The comparer
                // - Number of entries
                // - Actual content

                // Comparer
                _comparerFormatter.Serialize(ref buffer, ref offset, set.Comparer);

                // Count
                // We could use a 'IFormatter<int>' field, but Ceras will resolve it to this method anyway...
                SerializerBinary.WriteInt32(ref buffer, ref offset, set.Count);

                // Actual content
                foreach (var array in set)
                {
                    _byteArrayFormatter.Serialize(ref buffer, ref offset, array);
                }
            }
Esempio n. 5
0
        public void Serialize(ref byte[] buffer, ref int offset, Person value)
        {
            SerializerBinary.WriteString(ref buffer, ref offset, value.Name);
            SerializerBinary.WriteInt32(ref buffer, ref offset, value.Health);

            // !! Important - Read below!
            PersonFormatter.Serialize(ref buffer, ref offset, value.BestFriend);

            // You might be tempted to just recursively call your own Serialize method (this method) again for 'BestFriend', but that won't work!
            // That won't work because Ceras does many things behind the scenes to make reference-loops work.
            //
            // Think about it like this:
            // When we want to serialize '.BestFriend' and someone is their own best friend (silly, i know :P) then we'd want the serialized data to
            // say "this object was already written, look it up here..."
            // Otherwise we'd get into an infinite loop, which is exactly what is happening if we'd just write "this.Serialize(ref buffer, ref offset, value.BestFriend);" here.
            //
            // Now, as for the 'PersonFormatter' field in this class.
            // Ceras can inject fields of type 'IFormatter' and 'CerasSerializer' into all its formatters.
            // So, even though it may look like that the object injected into "PersonFormatter" is just 'MyCustomPersonFormatter' itself again, that's not the case!
            //
            // In case you are interested in what's going on behind the scenes:
            // Ceras actually injects a 'ReferenceFormatter<Person>' into our 'PersonFormatter' field, which deals with reference loops.
        }
Esempio n. 6
0
        public void Serialize(ref byte[] buffer, ref int offset, T value)
        {
            if (ReferenceEquals(value, null))
            {
                SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias);
                return;
            }

            var specificType = value.GetType();
            var entry        = GetOrCreateEntry(specificType);

            if (entry.IsType)             // This is very rare, so we cache the check itself, and do the cast below
            {
                SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, InlineType, Bias);
                _typeFormatter.Serialize(ref buffer, ref offset, (Type)(object)value);
                return;
            }

            if (entry.IsExternalRootObject)
            {
                var externalObj = (IExternalRootObject)value;

                if (!ReferenceEquals(_ceras.InstanceData.CurrentRoot, value))
                {
                    SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, ExternalObject, Bias);

                    var refId = externalObj.GetReferenceId();
                    SerializerBinary.WriteInt32(ref buffer, ref offset, refId);

                    _ceras.Config.OnExternalObject?.Invoke(externalObj);

                    return;
                }
            }

            if (_allowReferences)
            {
                if (_ceras.InstanceData.ObjectCache.TryGetExistingObjectId(value, out int id))
                {
                    // Existing value
                    SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias);
                }
                else
                {
                    // Register new object
                    _ceras.InstanceData.ObjectCache.RegisterObject(value);

                    // Embedd type (if needed)
                    if (ReferenceEquals(typeof(T), specificType))
                    {
                        // New value (same type)
                        SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValueSameType, Bias);
                    }
                    else
                    {
                        // New value (type included)
                        SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValue, Bias);
                        _typeFormatter.Serialize(ref buffer, ref offset, specificType);
                    }

                    // Write object
                    entry.CurrentSerializeDispatcher(ref buffer, ref offset, value);
                }
            }
            else
            {
                // Embedd type (if needed)
                if (ReferenceEquals(typeof(T), specificType))
                {
                    // New value (same type)
                    SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValueSameType, Bias);
                }
                else
                {
                    // New value (type included)
                    SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValue, Bias);
                    _typeFormatter.Serialize(ref buffer, ref offset, specificType);
                }

                // Write object
                entry.CurrentSerializeDispatcher(ref buffer, ref offset, value);
            }
        }
Esempio n. 7
0
        public void Serialize(ref byte[] buffer, ref int offset, T member)
        {
            // Declaring type
            _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType);

            byte bindingData = 0;

            switch (member.MemberType)
            {
            // Write all the data we need to resolve overloads
            case MemberTypes.Constructor:
            case MemberTypes.Method:
                var method = (MethodBase)(MemberInfo)member;

                if (method.ContainsGenericParameters)
                {
                    throw new ArgumentException($"The method or constructor '{method.DeclaringType?.FullName}.{method.Name}' can not be serialized because it is not closed. If you need this functionality (or don't know what this means) please report an issue on GitHub.");
                }

                bindingData = PackBindingData(method.IsStatic, ReflectionTypeToCeras(member.MemberType));

                // 1. Binding data
                SerializerBinary.WriteByte(ref buffer, ref offset, bindingData);

                // 2. Method Name
                _stringFormatter.Serialize(ref buffer, ref offset, method.Name);

                // 3. Parameters
                var args = method.GetParameters();
                SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length);
                for (int i = 0; i < args.Length; i++)
                {
                    _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType);
                }

                break;

            case MemberTypes.Property:
                PropertyInfo prop = (PropertyInfo)(MemberInfo)member;

                bindingData = PackBindingData(prop.GetAccessors(true)[0].IsStatic, ReflectionTypeToCeras(member.MemberType));

                // 1. Binding data
                SerializerBinary.WriteByte(ref buffer, ref offset, bindingData);

                // 2. Property Name
                _stringFormatter.Serialize(ref buffer, ref offset, prop.Name);

                // 3. Property Type
                _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType);
                break;

            case MemberTypes.Field:
                FieldInfo field = (FieldInfo)(MemberInfo)member;

                bindingData = PackBindingData(field.IsStatic, ReflectionTypeToCeras(member.MemberType));

                // 1. Binding data
                SerializerBinary.WriteByte(ref buffer, ref offset, bindingData);

                // 2. Field Name
                _stringFormatter.Serialize(ref buffer, ref offset, field.Name);

                // 3. Field Type
                _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType);

                break;

            case MemberTypes.TypeInfo:
            case MemberTypes.NestedType:
                // This should never happen, because root types as well as nested types are simply "Type",
                // so they should be handled by the TypeFormatter!
                goto default;

            default:
                throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'");
            }
        }
Esempio n. 8
0
        public void Serialize(ref byte[] buffer, ref int offset, T member)
        {
            // Declaring type
            _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType);

            byte bindingData = 0;

            switch (member.MemberType)
            {
            // Write all the data we need to resolve overloads
            case MemberTypes.Constructor:
            case MemberTypes.Method:
                var method = (MethodBase)(MemberInfo)member;

                bindingData = PackBindingData(method.IsStatic, ReflectionTypeToCeras(member.MemberType));

                // 1. Binding data
                SerializerBinary.WriteByte(ref buffer, ref offset, bindingData);

                // 2. Method Name
                _stringFormatter.Serialize(ref buffer, ref offset, method.Name);

                // todo: parameter count can be merged into the unused bits of bindingData, but so much bit-packing makes things more complicated than they need to be;
                // it's extremely unlikely that anyone would notice the savings, even if they'd serialize tons of MemberInfos

                // 3. Parameters
                var args = method.GetParameters();
                SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length);
                for (int i = 0; i < args.Length; i++)
                {
                    _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType);
                }

                break;

            case MemberTypes.Property:
                PropertyInfo prop = (PropertyInfo)(MemberInfo)member;

                bindingData = PackBindingData(prop.GetAccessors(true)[0].IsStatic, ReflectionTypeToCeras(member.MemberType));

                // 1. Binding data
                SerializerBinary.WriteByte(ref buffer, ref offset, bindingData);

                // 2. Property Name
                _stringFormatter.Serialize(ref buffer, ref offset, prop.Name);

                // 3. Property Type
                _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType);
                break;

            case MemberTypes.Field:
                FieldInfo field = (FieldInfo)(MemberInfo)member;

                bindingData = PackBindingData(field.IsStatic, ReflectionTypeToCeras(member.MemberType));

                // 1. Binding data
                SerializerBinary.WriteByte(ref buffer, ref offset, bindingData);

                // 2. Field Name
                _stringFormatter.Serialize(ref buffer, ref offset, field.Name);

                // 3. Field Type
                _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType);

                break;

            case MemberTypes.TypeInfo:
            case MemberTypes.NestedType:
                // This should never happen, because root types as well as nested types are simply "Type",
                // so they should be handled by the TypeFormatter!
                goto default;

            default:
                throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'");
            }
        }
Esempio n. 9
0
 public void Serialize(ref byte[] buffer, ref int offset, bool value)
 {
     SerializerBinary.WriteInt32(ref buffer, ref offset, value ? 1 : 0);
 }