private void SerializeReferenceType(PowerSerializationContext context, BinaryWriter writer, object obj, Type type)
 {
     foreach (FieldInfo info in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
     {
         if (info.FieldType.IsPrimitive)
         {
             CheckTypeAllowance(info.FieldType);
             WritePrimitiveObject(writer, info.GetValue(obj));
         }
         else if (info.FieldType.IsValueType)
         {
             CheckTypeAllowance(info.FieldType);
             SerializeReferenceType(context, writer, info.GetValue(obj), info.FieldType);
         }
         else
         {
             object value = info.GetValue(obj);
             if (value is null)
             {
                 writer.Write((ushort)0);
             }
             else
             {
                 CheckTypeAllowance(value.GetType());
                 WriteObjectReference(context, writer, value);
             }
         }
     }
 }
 /// <summary>
 /// Serializes the given object, writing its object references and primitive data to the given binary writer. Referenced objects are not serialized, but are added to the object graph.
 /// </summary>
 /// <param name="context">The current serialization context, with data about the current object graph and known types.</param>
 /// <param name="writer">The binary writer to utilize.</param>
 /// <param name="obj">The object that should be serialized.</param>
 /// <param name="type">The type of the current object.</param>
 protected virtual void SerializeObject(PowerSerializationContext context, BinaryWriter writer, object obj, Type type)
 {
     if (type.IsArray)
     {
         Array array = (Array)obj;
         int[] ranks = new int[array.Rank];
         for (int i = 0; i < array.Rank; i++)
         {
             ranks[i] = array.GetLength(i);
         }
         Type elementType = type.GetElementType();
         CheckTypeAllowance(type);
         if (elementType.IsPrimitive)
         {
             WriteFlattenedPrimitiveArray(context, writer, array, 0, ranks, new int[array.Rank]);
         }
         else if (elementType.IsValueType)
         {
             WriteFlattenedValueTypeArray(context, writer, array, 0, ranks, new int[array.Rank], elementType);
         }
         else
         {
             WriteFlattenedArray(context, writer, array, 0, ranks, new int[array.Rank]);
         }
     }
     else if (type.IsPrimitive)
     {
     }
     else
     {
         SerializeReferenceType(context, writer, obj, type);
     }
 }
 private void WriteFlattenedPrimitiveArray(PowerSerializationContext context, BinaryWriter writer, Array array, int index, int[] ranks, int[] currentRanks)
 {
     if (index < ranks.Length)
     {
         for (int i = 0; i < ranks[index]; i++)
         {
             WriteFlattenedPrimitiveArray(context, writer, array, index + 1, ranks, currentRanks);
             currentRanks[index]++;
         }
     }
     else
     {
         WritePrimitiveObject(writer, array.GetValue(currentRanks));
     }
 }
 private void WriteFlattenedValueTypeArray(PowerSerializationContext context, BinaryWriter writer, Array array, int index, int[] ranks, int[] currentRanks, Type type)
 {
     if (index < ranks.Length)
     {
         for (int i = 0; i < ranks[index]; i++)
         {
             WriteFlattenedValueTypeArray(context, writer, array, index + 1, ranks, currentRanks, type);
             currentRanks[index]++;
         }
     }
     else
     {
         SerializeReferenceType(context, writer, array.GetValue(currentRanks), type);
     }
 }
 /// <summary>
 /// Writes an object reference to the given binary writer. If the object has not been referenced before, its type is also stored, along with any immutable type data (like the contents of a string).
 /// </summary>
 /// <param name="context">The current serialization context, with data about the current object graph and known types.</param>
 /// <param name="writer">The binary writer to utilize.</param>
 /// <param name="obj">The object being referenced.</param>
 protected virtual void WriteObjectReference(PowerSerializationContext context, BinaryWriter writer, object obj)
 {
     if (obj is null)
     {
         writer.Write((ushort)0);
     }
     else if (context.HasObject(obj))
     {
         writer.Write(context.GetObjectID(obj));
     }
     else if (obj is Type typeRepresentation)
     {
         (ushort, Type)objectData = context.RegisterObject(obj);
         writer.Write(objectData.Item1);
         writer.Write(context.GetTypeID(typeof(Type)));
         TypeResolver.WriteTypeID(writer, typeRepresentation);
     }
     else
     {
         (ushort, Type)objectData = context.RegisterObject(obj);
         writer.Write(objectData.Item1);
         writer.Write(context.GetTypeID(objectData.Item2));
         if (obj is string oString)
         {
             writer.Write(oString);
         }
         else if (objectData.Item2.IsPrimitive)
         {
             WritePrimitiveObject(writer, obj);
         }
         else if (obj is Array array)
         {
             byte rankSize = (byte)array.Rank;
             writer.Write(rankSize);
             for (int i = 0; i < array.Rank; i++)
             {
                 writer.Write(array.GetLength(i));
             }
         }
     }
 }
        /// <summary>
        /// Serializes an object to a byte array.
        /// </summary>
        /// <param name="obj">The object to serialize.</param>
        /// <returns>A byte-based representation of the object.</returns>
        public virtual byte[] Serialize(object obj)
        {
            if (obj is null)
            {
                obj = new NullRepresentative();
            }

            using (MemoryStream stream = new MemoryStream())
            {
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    PowerSerializationContext context = CreateSerializationContext();
                    Type objType = context.RegisterObject(obj).Item2;
                    CheckTypeAllowance(objType);
                    if (objType == typeof(string))
                    {
                        writer.Write((string)obj);
                        long pos = writer.BaseStream.Position;
                        TypeResolver.WriteTypeID(writer, objType);
                        writer.Write((int)(writer.BaseStream.Position - pos));
                    }
                    else if (obj is Type typeRepresentation)
                    {
                        TypeResolver.WriteTypeID(writer, typeRepresentation);
                        long pos = writer.BaseStream.Position;
                        TypeResolver.WriteTypeID(writer, typeof(Type));
                        writer.Write((int)(writer.BaseStream.Position - pos));
                    }
                    else if (objType.IsPrimitive)
                    {
                        WritePrimitiveObject(writer, obj);
                        long pos = writer.BaseStream.Position;
                        TypeResolver.WriteTypeID(writer, objType);
                        writer.Write((int)(writer.BaseStream.Position - pos));
                    }
                    else
                    {
                        if (obj is Array array)
                        {
                            byte rankSize = (byte)array.Rank;
                            writer.Write(rankSize);
                            for (int i = 0; i < array.Rank; i++)
                            {
                                writer.Write(array.GetLength(i));
                            }
                        }
                        for (int i = 1; i < context.ObjectGraph.Count; i++)
                        {
                            SerializeObject(context, writer, context.ObjectGraph[i], context.ObjectGraph[i].GetType());
                        }
                        ImmutableList <Type> types = context.IncludedTypes;
                        long pos = writer.BaseStream.Position;
                        foreach (Type type in types)
                        {
                            TypeResolver.WriteTypeID(writer, type);
                        }
                        writer.Write((int)(writer.BaseStream.Position - pos));
                    }
                    return(stream.ToArray());
                }
            }
        }