예제 #1
0
        public void Step7_GameDatabase()
        {
            /*
             * Scenario:
             * We have "MyMonster" and "MyAbility" for a game.
             * We want to be able to easily serialize the whole graph, but we also
             * want MyMonster and MyAbility instances to be saved in their own files!
             *
             * Lets first take a look at the classes we're working with:
             */

            MyMonster monster = new MyMonster();

            monster.Name   = "Skeleton Mage";
            monster.Health = 250;
            monster.Mana   = 100;

            monster.Abilities.Add(new MyAbility
            {
                Name     = "Fireball",
                ManaCost = 12,
                Cooldown = 0.5f,
            });

            monster.Abilities.Add(new MyAbility
            {
                Name     = "Ice Lance",
                ManaCost = 14,
                Cooldown = 6,
            });

            // We want to save monsters and abilities in their their own files.
            // Using other serializers this would be a terribly time-consuming task.
            // We would have to add attributes or maybe even write custom serializers so the "root objects"
            // can be when they are referenced in another object..
            // Then we'd need a separate field maybe where we'd save a list of IDs or something....
            // And then at load(deserialization)-time we would have to manually load that list, and resolve the
            // objects they stand for...
            //
            // And all that for literally every "foreign key" (as it is called in database terms). :puke: !
            //
            //
            // Ceras offers a much better approach.
            // You can implement IExternalRootObject, telling Ceras the "Id" of your object.
            // You can generate that Id however you want, most people would proably opt to use some kind of auto-increment counter
            // from their SQLite/SQL/MongoDB/LiteDB/...
            //
            // At load time Ceras will ask you to load the object again given its Id.
            //

            SerializerConfig config   = new SerializerConfig();
            var myGameObjectsResolver = new MyGameObjectsResolver();

            config.ExternalObjectResolver = myGameObjectsResolver;
            config.KnownTypes.Add(typeof(MyAbility));
            config.KnownTypes.Add(typeof(MyMonster));
            config.KnownTypes.Add(typeof(List <>));


            // Ceras will call "OnExternalObject" (if you provide a function).
            // It can be used to find all the IExternalRootObject's that Ceras encounters while
            // serializing your object.
            //
            // In this example we just collect them in a list and then serialize them as well
            List <IExternalRootObject> externalObjects = new List <IExternalRootObject>();

            config.OnExternalObject = obj => { externalObjects.Add(obj); };

            var serializer = new CerasSerializer(config);

            myGameObjectsResolver.Serializer = serializer;

            var monsterData = serializer.Serialize(monster);

            // we can write this monster to the "monsters" sql-table now
            monsterData.VisualizePrint("Monster data");
            MyGameDatabase.Monsters[monster.Id] = monsterData;

            // While serializing the monster we found some other external objects as well (the abilities)
            // Since we have collected them into a list we can serialize them as well.
            // Note: while in this example the abilities themselves don't reference any other external objects,
            // it is quite common in a real-world scenario that every object has tons of references, so keep in mind that
            // the following serializations would keep adding objects to our 'externalObjects' list.
            for (var i = 0; i < externalObjects.Count; i++)
            {
                var obj = externalObjects[i];

                var abilityData = serializer.Serialize(obj);

                var id = obj.GetReferenceId();
                MyGameDatabase.Abilities[id] = abilityData;

                abilityData.VisualizePrint($"Ability {id} data:");
            }

            // Problems:

            /*
             * 1.)
             * Cannot deserialize recursively
             * we'd overwrite our object cache, Ids would go out of order, ...
             * Example: A nested object tells us "yea, this is object ID 5 again", while 5 is already some other object (because its the wrong context!)
             *
             * -> Need to make it so the serializer has Stack<>s of object- and type-caches.
             *
             *
             * 2.)
             * Keep in mind that we can NOT share a deserialization buffer!!
             * If we load from Monster1.bin, and then require Spell5.bin, that'd overwrite our shared buffer,
             * and then when the spell is done and we want to continue with the monster, the data will have changed!
             *
             * -> debug helper: "The data has changed while deserializing, this must be a bug on your end!"
             *
             * 3.)
             * while deserializing objects, we need to create them, add to cache, then populate.
             * otherwise we might get into a situation where we want to load an ability that points to a monster (the one we're already loading)
             * and then we end up with two monsters (and if they code continues to run, infinite, and we get a stackoverflow)
             * In other words: Objects that are still being deserialized, need to already be in the cache, so they can be used by other stuff!
             *
             * -> create helper class that deals with deserializing object graphs?
             *
             */

            // Load the data again:
            var loadedMonster = serializer.Deserialize <MyMonster>(MyGameDatabase.Monsters[1]);

            var ability1 = serializer.Deserialize <MyAbility>(MyGameDatabase.Abilities[1]);
            var ability2 = serializer.Deserialize <MyAbility>(MyGameDatabase.Abilities[2]);
        }
예제 #2
0
        public void Step3_Recycling()
        {
            /*
             * Scenario:
             *		- You might be developing a game or other timing-sensitive application
             *		  where performance is extremely important and where small stutters by the GC have to be avoided
             *		- You have your own object-pool and want Ceras to obtain instances from it and return them to it.
             *
             * What you want:
             *		- You want more performance
             *		- You want to decrease GC pauses and GC pressure
             *
             * What can we do:
             *		- Recycle objects, reducing GC pressure
             *		- Take objects from a pool instead of doing "new MyThing()" to improve cache-coherence.
             */



            // Assuming we're receiving "network packets" over the internet, we'd instantiate a new object every time we call Deserialize
            // That is pretty wasteful. We receive one object, deserialize it, use it, then discard it, ...
            //
            // What we can do is have one instance that we can just overwrite all the time!
            //
            // Ceras will use the provided object and overwrite the fields; instead of creating a new object instance.
            // If no instance is provided, Ceras will just instantiate one.
            //
            // Hint: This can also be used to quickly set or reset an object to some predefined values in other scenarios.

            var serializer = new CerasSerializer();

            Person recycledPerson = new Person {
                Health = 35, Name = "test"
            };

            byte[] buffer = serializer.Serialize(recycledPerson);             // Lets assume we already got a network buffer and now we just have to read it.

            for (int i = 0; i < 100; i++)
            {
                // No person object will be allocated, the fields
                // of 'recycledPerson' will just be overwritten
                serializer.Deserialize <Person>(ref recycledPerson, buffer);
            }



            //
            // Now we'll use some extremely simple object-pooling solution to reduce GC pressure.
            // The 'MyVerySimplePool' is obviously just for illustration, in something like Unity3D you would
            // of course make something much more elaborate...
            //
            // If the data in the buffer tells us "it's a 'null' object" then Ceras will of course set 'recycledPerson' to null.
            // But now you might wonder what happens to the instance that was previously inside 'recycledPerson'.
            // Normally the answer would be that the object would be simply lost (and eventually its space would be reclaimed by the .NET "garbage-collector").
            //
            // In some scenarios (games) we don't want this because garbage-collections often cause stutters.
            // A common solution to this is object-pooling.
            // Ceras supports that by allowing you to "catch" unused objects, so you can return them to your object-pool.

            MyVerySimplePool <Person> pool = new MyVerySimplePool <Person>();

            SerializerConfig config = new SerializerConfig();

            config.ObjectFactoryMethod = type =>
            {
                if (type != typeof(Person))
                {
                    return(null);
                }

                return(pool.GetFromPool());
            };
            config.DiscardObjectMethod = obj =>
            {
                pool.ReturnToPool((Person)obj);
            };


            serializer = new CerasSerializer(config);

            // todo: the example is not fully done yet

            /*
             * var personA = new Person { Name = "a", Health = 1 };
             * var personB = new Person { Name = "b", Health = 2 };
             * var personC = new Person { Name = "c", Health = 3 };
             *
             * personA.BestFriend = personB;
             * personB.BestFriend = personC;
             * personC.BestFriend = personA;
             *
             * serializer.Serialize();
             */
        }
 protected internal virtual void FillSerializers(XmlNode node, SerializationConfig serializationConfig)
 {
     foreach (XmlNode child in node.ChildNodes)
     {
         string name = CleanNodeName(child);
         string value = GetTextContent(child);
         if ("serializer".Equals(name))
         {
             var serializerConfig = new SerializerConfig();
             serializerConfig.SetClassName(value);
             string typeClassName = GetAttribute(child, "type-class");
             serializerConfig.SetTypeClassName(typeClassName);
             serializationConfig.AddSerializerConfig(serializerConfig);
         }
         else
         {
             if ("global-serializer".Equals(name))
             {
                 var globalSerializerConfig = new GlobalSerializerConfig();
                 globalSerializerConfig.SetClassName(value);
                 serializationConfig.SetGlobalSerializerConfig(globalSerializerConfig);
             }
         }
     }
 }
예제 #4
0
 public XmlRpcResponseDeserializer(SerializerConfig config) : base(config)
 {
 }
예제 #5
0
        public void ComplexPersonSerializing()
        {
            using (var config = new SerializerConfig())
            {
                config.Match <ComplexPerson>();

                using (var serializer = config.Create())
                {
                    IList <ComplexPerson> input = new List <ComplexPerson>
                    {
                        new ComplexPerson
                        {
                            Name     = "Sarah",
                            Age      = 37,
                            Children = new List <ComplexPerson>
                            {
                                new ComplexPerson
                                {
                                    Name     = "John",
                                    Age      = 14,
                                    Children = new List <ComplexPerson>()
                                }
                            }
                        },
                        new ComplexPerson
                        {
                            Name     = "Julia",
                            Age      = 42,
                            Children = new List <ComplexPerson>
                            {
                                new ComplexPerson
                                {
                                    Name     = "Sandra",
                                    Age      = 20,
                                    Children = null
                                }
                            }
                        },
                        new ComplexPerson
                        {
                            Name     = "Sam",
                            Age      = 14,
                            Children = null
                        }
                    };

                    using (var stream = CreateStream())
                    {
                        serializer.Serialize(stream, input);
                        stream.Seek(0);
                        var result = serializer.Deserialize <IList <ComplexPerson> >(stream);

                        Assert.Equal(3, result.Count);

                        var sarah = result[0];
                        Assert.Equal("Sarah", sarah.Name);
                        Assert.Equal(37, sarah.Age);
                        Assert.Single(sarah.Children);

                        var john = sarah.Children[0];
                        Assert.Equal("John", john.Name);
                        Assert.Equal(14, john.Age);
                        Assert.Empty(john.Children);

                        var julia = result[1];
                        Assert.Equal("Julia", julia.Name);
                        Assert.Equal(42, julia.Age);
                        Assert.Single(julia.Children);

                        var sandra = julia.Children[0];
                        Assert.Equal("Sandra", sandra.Name);
                        Assert.Equal(20, sandra.Age);
                        Assert.Null(sandra.Children);

                        var sam = result[2];
                        Assert.Equal("Sam", sam.Name);
                        Assert.Equal(14, sam.Age);
                        Assert.Null(sam.Children);
                    }
                }
            }
        }
예제 #6
0
파일: TCPLink.cs 프로젝트: magicono43/RTCV
        private void StoreMessages(NetworkStream providedStream)
        {
            var config = new SerializerConfig();

            config.Advanced.PersistTypeCache = true;
            config.OnResolveFormatter.Add((c, t) =>
            {
                if (t == typeof(HashSet <byte[]>))
                {
                    return(new NetCore.NetCore_Extensions.HashSetFormatterThatKeepsItsComparer());
                }
                return(null);                // continue searching
            });
            var serializer = new CerasSerializer(config);

            TcpListener   server        = null;
            Socket        socket        = null;
            NetworkStream networkStream = null;

            if (providedStream != null)
            {
                networkStream = providedStream;
            }

            try
            {
                if (networkStream == null)
                {
                    server = new TcpListener((IP == "127.0.0.1" ? IPAddress.Loopback : IPAddress.Any), Port);
                    server.Start();
                    socket        = KillableAcceptSocket(server);
                    networkStream = new NetworkStream(socket);

                    server.Stop();
                }

                networkStream.ReadTimeout  = 20;
                networkStream.WriteTimeout = int.MaxValue;  //Using {BOOP} commands routed through UDP/TCP

                if (spec.Side == NetworkSide.CLIENT)
                {
                    SendMessage(new NetCoreAdvancedMessage("{HI}"));    //The exchange of {HI} command confirms that link is established on Receiving
                }
                while (true)
                {
                    if (networkStream != null && networkStream.DataAvailable)
                    {
                        if (spec.Side == NetworkSide.SERVER && (!socket?.Connected ?? true))
                        {
                            return;
                        }

                        NetCoreAdvancedMessage message = null;

                        try
                        {
                            using (MemoryStream ms = new MemoryStream())
                            {
                                Stopwatch sw = new Stopwatch();
                                sw.Start();

                                //Read the size
                                int    lengthToReceive  = 0;
                                byte[] _lengthToReceive = new byte[4];
                                networkStream.Read(_lengthToReceive, 0, _lengthToReceive.Length);
                                lengthToReceive = BitConverter.ToInt32(_lengthToReceive, 0);

                                //Console.WriteLine("I want this many bytes: " + lengthToReceive);
                                //Now read until we have that many bytes
                                long bytesRead = CopyBytes(lengthToReceive, networkStream, ms);
                                //Console.WriteLine("I got this many bytes: " + bytesRead);

                                //Deserialize it
                                ms.Position = 0;

                                //cmd = (RTC_Command)binaryFormatter.Deserialize(ms);
                                var temp = ms.ToArray();
                                message = serializer.Deserialize <NetCoreAdvancedMessage>(temp);

                                sw.Stop();
                                if (message.Type != "{BOOP}" && sw.ElapsedMilliseconds > 50)
                                {
                                    Console.WriteLine("It took " + sw.ElapsedMilliseconds + " ms to deserialize cmd " + message.Type + " of " + temp.Length + " bytes");
                                }
                            }
                        }
                        catch { throw; }

                        if (message != null)
                        {
                            if (message.Type == "{RETURNVALUE}")
                            {
                                spec.Connector.watch.AddReturn(message);
                            }
                            else
                            {
                                spec.Connector.hub.QueueMessage(message);
                            }
                        }
                    }

                    while (PeerMessageQueue.Count > 0)
                    {
                        NetCoreMessage pendingMessage;

                        lock (PeerMessageQueueLock)
                        {
                            pendingMessage = PeerMessageQueue.First.Value;
                            PeerMessageQueue.RemoveFirst();
                        }

                        try
                        {
                            Stopwatch sw = new Stopwatch();
                            sw.Start();
                            //Write the length of the command to the first four bytes
                            byte[] buf = serializer.Serialize(pendingMessage);

                            //Write the length of the incoming object to the NetworkStream
                            byte[] length = BitConverter.GetBytes(buf.Length);
                            networkStream.Write(length, 0, length.Length);

                            networkStream.Write(buf, 0, buf.Length);
                            sw.Stop();
                            if (pendingMessage.Type != "{BOOP}" && sw.ElapsedMilliseconds > 50)
                            {
                                Console.WriteLine("It took " + sw.ElapsedMilliseconds + " ms to serialize backCmd " + pendingMessage.Type + " of " + buf.Length + " bytes");
                            }
                        }
                        catch
                        {
                            throw;
                        }

                        if (pendingMessage.Type == "{BYE}")
                        {
                            lock (PeerMessageQueueLock) //Since we're shutting down, let's clear the message queue
                                PeerMessageQueue?.Clear();
                        }

                        if (status == NetworkStatus.DISCONNECTED || status == NetworkStatus.CONNECTIONLOST)
                        {
                            //If the link's status changed from an outside factor, we want to stop the thread.

                            lock (PeerMessageQueueLock)
                                PeerMessageQueue?.Clear();

                            return;
                        }
                    }

                    Thread.Sleep(spec.messageReadTimerDelay);
                }
            }
            catch (Exception ex)
            {
                if (ex is ThreadAbortException)
                {
                    ConsoleEx.WriteLine("Ongoing TCPLink Thread Killed");
                }
                else if (ex.InnerException != null && ex.InnerException is SocketException)
                {
                    ConsoleEx.WriteLine("Ongoing TCPLink Socket Closed during use");
                }
                else if (ex is SerializationException)
                {
                    ConsoleEx.WriteLine("Ongoing TCPLink Closed during Serialization operation");
                }
                else if (ex is ObjectDisposedException)
                {
                    ConsoleEx.WriteLine("Ongoing TCPLink Closed during Socket acceptance");
                }
                else
                {
                    DiscardException(ex);
                }
            }
            finally
            {
                //Let's force close everything JUST IN CASE

                try
                {
                    networkStream?.Close();
                    networkStream?.Dispose();
                }
                catch { } //nobody cares why this failed


                try
                {
                    socket?.Shutdown(SocketShutdown.Both);
                    socket?.Dispose();
                }
                catch { } //nobody cares why this failed


                try
                {
                    server?.Stop();
                }
                catch (Exception ex)
                {
                    DiscardException(ex);
                }

                if (status == NetworkStatus.CONNECTED)
                {
                    status = (expectingSomeone ? NetworkStatus.CONNECTIONLOST : NetworkStatus.DISCONNECTED);
                }
                else if (status != NetworkStatus.CONNECTIONLOST)
                {
                    status = NetworkStatus.DISCONNECTED;
                }

                //Kill synced query if happenning
                spec.Connector.watch.Kill();
            }
        }
예제 #7
0
파일: Generator.cs 프로젝트: zvinless/Ceras
        static (CerasSerializer, List <Type>) CreateSerializerAndTargets(IEnumerable <Assembly> asms)
        {
            // Find config method and create a SerializerConfig
            SerializerConfig config = new SerializerConfig();
            var configMethods       = asms.SelectMany(a => a.GetTypes())
                                      .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
                                      .Where(m => m.GetCustomAttribute <CerasAutoGenConfigAttribute>() != null)
                                      .ToArray();

            if (configMethods.Length > 1)
            {
                throw new Exception("Found more than one method with the CerasAutoGenConfig attribute!");
            }
            if (configMethods.Length == 1)
            {
                config = (SerializerConfig)configMethods[0].Invoke(null, null);
            }

            config.VersionTolerance.Mode = VersionToleranceMode.Disabled;             // ensure VersionTolerance is off so we don't accidentally get 'SchemaDynamicFormatter'
            var ceras = new CerasSerializer(config);


            // Start with KnownTypes...
            HashSet <Type> newTypes = new HashSet <Type>();

            newTypes.AddRange(config.KnownTypes);

            // And also include all marked types
            var marker = typeof(CerasAutoGenFormatterAttribute);

            bool HasMarker(Type t) => t.GetCustomAttributes(true)
            .Any(a => a.GetType().FullName == marker.FullName);

            var markedTargets = asms.SelectMany(a => a.GetTypes())
                                .Where(t => !t.IsAbstract && HasMarker(t));

            newTypes.AddRange(markedTargets);


            // Go through each type, add all the member-types it wants to serialize as well
            HashSet <Type> allTypes = new HashSet <Type>();

            while (newTypes.Any())
            {
                // Get first, remove from "to explore" list, and add it to the "done" list.
                var t = newTypes.First();
                newTypes.Remove(t);
                allTypes.Add(t);


                if (CerasSerializer.IsPrimitiveType(t))
                {
                    // Skip int, string, Type, ...
                    continue;
                }

                if (t.IsAbstract || t.ContainsGenericParameters)
                {
                    // Can't explore abstract or open generics
                    continue;
                }

                // Explore the type, add all member types
                var schema = ceras.GetTypeMetaData(t).PrimarySchema;

                foreach (var member in schema.Members)
                {
                    if (!allTypes.Contains(member.MemberType))
                    {
                        newTypes.Add(member.MemberType);
                    }
                }
            }


            // Only leave things that use DynamicFormatter, or have the marker attribute
            List <Type> targets = new List <Type>();

            foreach (var t in allTypes)
            {
                var f     = ceras.GetSpecificFormatter(t);
                var fType = f.GetType();

                if (fType.IsGenericType && fType.GetGenericTypeDefinition().Name == typeof(DynamicFormatter <int>).GetGenericTypeDefinition().Name)
                {
                    targets.Add(t);
                }
                else if (HasMarker(t))
                {
                    targets.Add(t);
                }
            }

            return(ceras, targets);
        }
예제 #8
0
 public XmlParser(SerializerConfig serializerConfig)
 {
     _config = serializerConfig;
 }
예제 #9
0
        static void EnsureSealedTypesThrowsException()
        {
            //
            // 1. Check while serializing
            //
            var obj = new List <object>();

            obj.Add(5);
            obj.Add(DateTime.Now);
            obj.Add("asdasdas");
            obj.Add(new Person()
            {
                Name = "abc"
            });

            var config = new SerializerConfig();

            config.KnownTypes.Add(typeof(List <>));
            config.KnownTypes.Add(typeof(int));
            // Some types not added on purpose

            // Should be true by default!
            Debug.Assert(config.Advanced.SealTypesWhenUsingKnownTypes);

            var ceras = new CerasSerializer(config);

            try
            {
                ceras.Serialize(obj);

                Debug.Assert(false, "this line should not be reached, we want an exception here!");
            }
            catch (Exception e)
            {
                // all good
            }

            //
            // 2. Check while deserializing
            //
            config = new SerializerConfig();
            config.KnownTypes.Add(typeof(List <>));
            config.KnownTypes.Add(typeof(int));
            config.Advanced.SealTypesWhenUsingKnownTypes = false;
            ceras = new CerasSerializer(config);

            var data = ceras.Serialize(obj);

            config = new SerializerConfig();
            config.KnownTypes.Add(typeof(List <>));
            config.KnownTypes.Add(typeof(int));
            config.Advanced.SealTypesWhenUsingKnownTypes = true;
            ceras = new CerasSerializer(config);

            try
            {
                ceras.Deserialize <List <object> >(data);

                Debug.Assert(false, "this line should not be reached, we want an exception here!");
            }
            catch (Exception e)
            {
                // all good
            }
        }
예제 #10
0
        static void ReadonlyTest()
        {
            // Test #1:
            // By default the setting is off. Fields are ignored.
            {
                SerializerConfig config = new SerializerConfig();
                CerasSerializer  ceras  = new CerasSerializer(config);

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "xyz", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 10, Setting2 = "asdasdas"
                });

                var data = ceras.Serialize(obj);

                var cloneNew = ceras.Deserialize <ReadonlyFieldsTest>(data);

                Debug.Assert(cloneNew.Int == 1);
                Debug.Assert(cloneNew.String == "a");
                Debug.Assert(cloneNew.Container == null);
            }

            // Test #2A:
            // In the 'Members' mode we expect an exception for readonly value-typed fields.
            {
                SerializerConfig config = new SerializerConfig();
                config.Advanced.ReadonlyFieldHandling = ReadonlyFieldHandling.Members;

                config.ConfigType <ReadonlyFieldsTest>()
                .ConfigMember(f => f.Int).Include()
                .ConfigMember(f => f.String).Include();


                CerasSerializer ceras = new CerasSerializer(config);

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "55555", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 555555, Setting2 = "555555555"
                });

                var data = ceras.Serialize(obj);

                ReadonlyFieldsTest existingTarget = new ReadonlyFieldsTest(6, "66666", null);

                bool gotException = false;
                try
                {
                    var cloneNew = ceras.Deserialize <ReadonlyFieldsTest>(data);
                }
                catch (Exception ex)
                {
                    gotException = true;
                }

                Debug.Assert(gotException);                 // We want an exception
            }

            // Test #2B:
            // In the 'Members' mode (when not dealing with value-types)
            // we want Ceras to re-use the already existing object
            {
                SerializerConfig config = new SerializerConfig();
                config.Advanced.ReadonlyFieldHandling = ReadonlyFieldHandling.Members;

                config.ConfigType <ReadonlyFieldsTest>()
                .ConfigMember(f => f.Int).Exclude()
                .ConfigMember(f => f.String).Exclude()
                .ConfigMember(f => f.Container).Include(ReadonlyFieldHandling.Members);

                CerasSerializer ceras = new CerasSerializer(config);

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "55555", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 555555, Setting2 = "555555555"
                });

                var data = ceras.Serialize(obj);

                var newContainer = new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = -1, Setting2 = "this should get overwritten"
                };
                ReadonlyFieldsTest existingTarget = new ReadonlyFieldsTest(6, "66666", newContainer);

                // populate existing data
                ceras.Deserialize <ReadonlyFieldsTest>(ref existingTarget, data);

                // The simple fields should have been ignored
                Debug.Assert(existingTarget.Int == 6);
                Debug.Assert(existingTarget.String == "66666");

                // The reference itself should not have changed
                Debug.Assert(existingTarget.Container == newContainer);

                // The content of the container should be changed now
                Debug.Assert(newContainer.Setting1 == 555555);
                Debug.Assert(newContainer.Setting2 == "555555555");
            }


            // Test #3
            // In 'ForcedOverwrite' mode Ceras should fix all possible mismatches by force (reflection),
            // which means that it should work exactly like as if the field were not readonly.
            {
                SerializerConfig config = new SerializerConfig();
                config.Advanced.ReadonlyFieldHandling = ReadonlyFieldHandling.ForcedOverwrite;
                CerasSerializer ceras = new CerasSerializer(config);

                // This time we want Ceras to fix everything, reference mismatches and value mismatches alike.

                ReadonlyFieldsTest obj = new ReadonlyFieldsTest(5, "55555", new ReadonlyFieldsTest.ContainerThingA {
                    Setting1 = 324, Setting2 = "1134"
                });

                var data = ceras.Serialize(obj);

                ReadonlyFieldsTest existingTarget = new ReadonlyFieldsTest(123, null, new ReadonlyFieldsTest.ContainerThingB());

                // populate existing object
                ceras.Deserialize <ReadonlyFieldsTest>(ref existingTarget, data);


                // Now we really check for everything...

                // Sanity check, no way this could happen, but lets make sure.
                Debug.Assert(ReferenceEquals(obj, existingTarget) == false);

                // Fields should be like in the original
                Debug.Assert(existingTarget.Int == 5);
                Debug.Assert(existingTarget.String == "55555");

                // The container type was wrong, Ceras should have fixed that by instantiating a different object
                // and writing that into the readonly field.
                var container = existingTarget.Container as ReadonlyFieldsTest.ContainerThingA;
                Debug.Assert(container != null);

                // Contents of the container should be correct as well
                Debug.Assert(container.Setting1 == 324);
                Debug.Assert(container.Setting2 == "1134");
            }

            // Test #4:
            // Everything should work fine when using the MemberConfig attribute as well
            {
                var ceras = new CerasSerializer();

                var obj = new ReadonlyFieldsTest2();
                obj.Numbers.Clear();
                obj.Numbers.Add(234);

                var data = ceras.Serialize(obj);

                var clone        = new ReadonlyFieldsTest2();
                var originalList = clone.Numbers;
                ceras.Deserialize(ref clone, data);

                Debug.Assert(originalList == clone.Numbers);           // actual reference should not have changed
                Debug.Assert(clone.Numbers.Count == 1);                // amount of entries should have changed
                Debug.Assert(clone.Numbers[0] == 234);                 // entry itself should be right
            }

            // todo: also test the case where the existing object does not match the expected type
        }
예제 #11
0
        static void ExpressionTreesTest()
        {
            // Primitive test (private readonly in a base type)
            {
                SerializerConfig config = new SerializerConfig();
                config.ConfigType <ReadonlyTestClass>()
                .ConstructByUninitialized()
                .SetReadonlyHandling(ReadonlyFieldHandling.ForcedOverwrite)
                .SetTargetMembers(TargetMember.PrivateFields);

                var ceras = new CerasSerializer(config);

                var obj  = new ReadonlyTestClass("a");
                var data = ceras.Serialize(obj);

                var clone = ceras.Deserialize <ReadonlyTestClass>(data);

                Debug.Assert(obj.GetName() == clone.GetName());
                Debug.Assert(obj.GetBaseName() == clone.GetBaseName());

                Console.WriteLine();
            }

            // Small test 1
            {
                Expression <Func <string, int, char> > getCharAtIndex = (text, index) => text.ElementAt(index);
                MethodCallExpression body = (MethodCallExpression)getCharAtIndex.Body;

                // Serialize and deserialize delegate
                SerializerConfig config = new SerializerConfig();
                var ceras = new CerasSerializer(config);

                var data      = ceras.Serialize <object>(body);
                var dataAsStr = Encoding.ASCII.GetString(data).Replace('\0', ' ');

                var clonedExp = (MethodCallExpression)ceras.Deserialize <object>(data);

                Debug.Assert(clonedExp.Method == body.Method);
                Debug.Assert(clonedExp.Arguments.Count == body.Arguments.Count);
            }

            // Small test 2
            {
                // Test data
                string inputString = "abcdefgh";


                Expression <Func <string, int, char> > getCharAtIndex = (text, index) => (text.ElementAt(index).ToString() + text[index])[0];
                var  del1 = getCharAtIndex.Compile();
                char c1   = del1(inputString, 2);


                // Serialize and deserialize expression
                SerializerConfig config = new SerializerConfig();
                var ceras = new CerasSerializer(config);

                var data      = ceras.Serialize(getCharAtIndex);
                var dataAsStr = Encoding.ASCII.GetString(data).Replace('\0', ' ');

                var clonedExp = ceras.Deserialize <Expression <Func <string, int, char> > >(data);


                // Compile the restored expression, check if it works and returns the same result
                var del2 = clonedExp.Compile();

                // Check single case
                var c2 = del2(inputString, 2);
                Debug.Assert(c1 == c2);

                // Check all cases
                for (int i = 0; i < inputString.Length; i++)
                {
                    Debug.Assert(del1(inputString, i) == del2(inputString, i));
                }
            }
        }
예제 #12
0
        /*
         #if NETFRAMEWORK
         * static void TestDynamic()
         * {
         *      dynamic dyn = new ExpandoObject();
         *      dyn.number = 5;
         *      dyn.list = new List<string> { "a", "b"};
         *      dyn.c = "c";
         *      dyn.func = new Func<string>(((object)dyn).ToString);
         *
         *      var ceras = new CerasSerializer();
         *      var data = ceras.Serialize(dyn);
         *      var dyn2 = ceras.Deserialize<dynamic>(data);
         * }
         #endif
         */

        static void TestBitmapFormatter()
        {
            var config = new SerializerConfig();

            config.Advanced.BitmapMode = BitmapMode.SaveAsBmp;
            var ceras = new CerasSerializer(config);

            var home      = Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
            var downloads = Path.Combine(home, "Downloads");

            var images = new Image[]
            {
                // todo: add test images
                Image.FromFile(Path.Combine(downloads, @".png")),
            };

            for (int iteration = 0; iteration < 5; iteration++)
            {
                var imgData1 = ceras.Serialize(images);
                var clones   = ceras.Deserialize <Image[]>(imgData1);

                for (var cloneIndex = 0; cloneIndex < clones.Length; cloneIndex++)
                {
                    var c = clones[cloneIndex];
                    c.Dispose();
                    clones[cloneIndex] = null;
                }
            }


            byte[] sharedBuffer = new byte[100];
            int    offset       = 0;

            foreach (var sourceImage in images)
            {
                offset += ceras.Serialize(sourceImage, ref sharedBuffer, offset);
            }
            offset += ceras.Serialize(images, ref sharedBuffer, offset);

            int writtenLength = offset;

            List <Image> clonedImages = new List <Image>();

            offset = 0;

            for (var i = 0; i < images.Length; i++)
            {
                Image img = null;
                ceras.Deserialize(ref img, sharedBuffer, ref offset);
                clonedImages.Add(img);
            }
            Image[] imageArrayClone = null;
            ceras.Deserialize(ref imageArrayClone, sharedBuffer, ref offset);

            // Ensure all bytes consumed again
            Debug.Assert(offset == writtenLength);

            foreach (var img in clonedImages)
            {
                img.Dispose();
            }
            foreach (var img in imageArrayClone)
            {
                img.Dispose();
            }
        }
예제 #13
0
 public UserModel(SerializerConfig serializerConfig, DeserializerConfig deserializerConfig) : base(serializerConfig, deserializerConfig, "users")
 {
 }
예제 #14
0
        public void Step1_SimpleUsage()
        {
            //
            // 1.) Simple usage
            // aka. "I'm here for the cool features! I want to optimize for max-performance later"
            var person = new Person {
                Name = "riki", Health = 100
            };

            var serializer = new CerasSerializer();

            var data = serializer.Serialize(person);

            data.VisualizePrint("Simple Person");

            var clone1 = serializer.Deserialize <Person>(data);

            Console.WriteLine($"Clone: Name={clone1.Name}, Health={clone1.Health}");



            // 2.) Types
            // You can also serialize as <object>.
            // In that case the type information will be included.
            // If a type is written it will only be written ONCE, so a List<Person> will not suddenly waste a
            // ton of space by continously writing the type-names
            var objectData = serializer.Serialize <object>(person);

            objectData.VisualizePrint("Person as <object>");
            var objectClone = serializer.Deserialize <object>(objectData);



            //
            // 3.) Improvement:
            // Recycle the serialization buffer by keeping the reference to it around.
            // Optionally we can even let Ceras create (or resize) the buffer for us.
            byte[] buffer       = null;
            int    writtenBytes = serializer.Serialize(person, ref buffer);

            // Now we could send this over the network, for example:
            //   socket.Send(buffer, writtenBytes, SocketFlags.None);
            var clone2 = serializer.Deserialize <Person>(buffer);



            //
            // 4.)
            // Deciding what gets serialized
            // There are multiple ways to configure what members to serialize
            // Ceras determines member inclusion in this order:
            //
            //  - a. Using the result of "ShouldSerializeMember".
            //       This method can always override everything else.
            //       If it returns "NoOverride" or the method is not set
            //       the search for a decision continues.
            //
            //  - b. [Ignore] and [Include] attributes on individual members
            //
            //  - c. [MemberConfig] attribute
            //
            //  - d. "DefaultTargets" setting in the SerializerConfig
            //       which defaults to 'TargetMember.PublicFields'
            //

            SerializerConfig config = new SerializerConfig();

            config.DefaultTargets = TargetMember.PublicProperties | TargetMember.PrivateFields;

            config.ShouldSerializeMember = m => SerializationOverride.NoOverride;



            //
            // 5.) Circular references
            // Serializers commonly have trouble serializing circular references.
            // Ceras supports every possible object-graph, and there's literally
            // nothing to do or configure, it just works out of the box.
            // Lets make an example anyway...

            var personA = new Person {
                Name = "alice"
            };
            var personB = new Person {
                Name = "bob"
            };

            personA.BestFriend = personB;
            personB.BestFriend = personA;

            var dataWithCircularReferences = serializer.Serialize(personA);

            dataWithCircularReferences.VisualizePrint("Circular references data");

            var cloneA = serializer.Deserialize <Person>(dataWithCircularReferences);

            if (cloneA.BestFriend.BestFriend.BestFriend.BestFriend.BestFriend.BestFriend == cloneA)
            {
                Console.WriteLine("Circular reference serialization working as intended!");
            }
            else
            {
                throw new Exception("There was some problem!");
            }
        }
예제 #15
0
        public XmlRpcClient(HttpClient client)
        {
            Configuration = new SerializerConfig();

            _client = client;
        }
예제 #16
0
        public void Step7_GameDatabase()
        {
            /*
             * Scenario:
             * We have "MyMonster" and "MyAbility" for a game.
             * We want to be able to easily serialize the whole graph, but we also
             * want MyMonster and MyAbility instances to be saved in their own files!
             *
             * Lets first take a look at the classes we're working with:
             */

            MyMonster monster = new MyMonster();

            monster.Name   = "Skeleton Mage";
            monster.Health = 250;
            monster.Mana   = 100;

            monster.Abilities.Add(new MyAbility
            {
                Name     = "Fireball",
                ManaCost = 12,
                Cooldown = 0.5f,
            });

            monster.Abilities.Add(new MyAbility
            {
                Name     = "Ice Lance",
                ManaCost = 14,
                Cooldown = 6,
            });

            // We want to save monsters and abilities in their their own files.
            //
            // Using other serializers this would be a terribly time-consuming task.
            // How would a classic solution for that look like? (without Ceras)
            // We would have to add attributes or maybe even write custom serializers so the "root objects"
            // can be when they are referenced in another object..
            // Then we'd need a separate field maybe where we'd save a list of IDs or something....
            // And then at load(deserialization)-time we would have to manually load that list, and resolve the
            // objects they stand for...
            // And all that for literally every "foreign key" (as it is called in database terms). :puke: !
            //
            // Ceras offers a much better approach.
            // Just implement the 'IExternalRootObject' interface so Ceras can obtain an "ID" of your objects.
            // So whenever Ceras sees one of your objects implementing that interface, it will just write the ID of the object instead.
            // You can generate that ID however you want, most people would proably use some sort of counter.
            //
            // When loading/deserializing an object again Ceras will ask you for the external objects (giving you the ID).
            //


            SerializerConfig config = new SerializerConfig();
            // 1. Create a config with a (pretty simple) custom external-object-resolver.
            var myGameObjectsResolver = new MyGameObjectsResolver();

            config.ExternalObjectResolver = myGameObjectsResolver;
            // 2. Using KnownTypes is not neccesary at all, it just makes the serialized data a bit smaller.
            config.KnownTypes.Add(typeof(MyAbility));
            config.KnownTypes.Add(typeof(MyMonster));
            config.KnownTypes.Add(typeof(List <>));


            // Ceras will call "OnExternalObject" (if you provide a function) when it encounters one of your IExternalRootObjects.
            //
            // So what would you use that for?
            // Pretty often when serializing one object, you probably also want to know about all the other IExternalRootObjects that
            // part of the "object graph" in some way (referenced by the original object) so you can save them as well.
            //
            // Maybe it would be a good idea to also include the last time an object has changed.
            // Like, you could have an OnPropertyChanged and whenever something changes you'd set something like a 'LastModified' date.
            // Then later you have the list of all the IExternalRootObjects and you can check LastModified to see if you have
            // to serialize and save it into a file again, or if the object is still up to date.
            //
            // In our example that means when serializing our Monster, the OnExternalObject function would
            // get called for the two abilities; that way we can save them as well.

            List <IExternalRootObject> externalObjects = new List <IExternalRootObject>();

            config.OnExternalObject = obj => { externalObjects.Add(obj); };

            var serializer = new CerasSerializer(config);

            myGameObjectsResolver.Serializer = serializer;

            var monsterData = serializer.Serialize(monster);

            // we can write this monster to the "monsters" sql-table now
            monsterData.VisualizePrint("Monster data");
            MyGameDatabase.Monsters[monster.Id] = monsterData;

            // While serializing the monster we found some other external objects as well (the abilities)
            // Since we have collected them into a list we can serialize them as well.
            // Note: while in this example the abilities themselves don't reference any other external objects,
            // it is quite common in a real-world scenario that every object has tons of references, so keep in mind that
            // the following serializations would keep adding objects to our 'externalObjects' list.
            for (var i = 0; i < externalObjects.Count; i++)
            {
                var obj = externalObjects[i];

                var abilityData = serializer.Serialize(obj);

                var id = obj.GetReferenceId();
                MyGameDatabase.Abilities[id] = abilityData;

                abilityData.VisualizePrint($"Ability {id} data:");
            }

            /*
             * Note:
             *
             * 1.)
             * Keep in mind that we can not share a deserialization buffer!
             * That means overwriting the buffer you passed to Deserialize while the deserialization is still in progress will cause problems.
             * "But why, when would I even attempt that??"
             * -> If you remember Step1 there's a part about re-using buffers. Well, in some cases you might be tempted to share a deserialization buffer as well.
             *    For example you might think "if I use File.ReadAllBytes() for every object, that'd be wasteful, better use one big buffer and populate it from the file!"
             *    The idea is nice and would work to avoid creating a large buffer each time you want to read an object; but when combining it with this IExternalObject idea,
             *    things begin to break down because:
             *
             *    Lets say you have a Monster1.bin file, and load it into the shared buffer. Now while deserializing Ceras realizes that the monster also has a reference to Spell3.bin.
             *    It will send a request to your OnExternalObject function, asking for Type=Spell ID=3.
             *    That's when you'd load the Spell3.bin data into the shared buffer, OVERWRITING THE DATA of the monster that is still being deserialized.
             *
             * In other words: Just make sure to not overwrite a buffer before the library is done with it (which should be common sense for any programmer tbh :P)
             *
             * 2.)
             * Consider a situation where we have 2 Person objects, both refering to each other (like the BestFriend example in Step1)
             * And now we'd like to load one person again.
             * Obviously Ceras has to also load the second person, so it will request it from you
             * Of course you again load the file (this time the requested person2.bin) and deserialize it.
             * Now! While deserializing person2 Ceras sees that it needs Person1!
             * And it calls your OnExternalObject again...
             *
             * > "Oh no, its an infinite loop, how to deal with this?"
             *
             * No problem. What you do is:
             * At the very start before deserializing, you first create an empty object:
             *    var p = new Person();
             * and then you add it to a dictionary!
             *    myDictionary.Add(id, p);
             *
             * And then you call Ceras in "populate" mode, passing the object you created.
             *    ceras.Deserialize(ref p, data);
             *
             * And you do it that way evertime something gets deserialized.
             * Now the problem is solved: While deserializing Person2 ceras calls your load function, and this time you already have an object!
             * Yes, it is not yet fully populated, but that doesn't matter at all. What matters is that the reference matches.
             *
             *
             * If this was confusing to you wait until I wrote another, even more detailed guide or something (or just open an issue on github!)
             *
             *
             * (todo: write better guide; maybe even write some kind of "helper" class that deals with all of this maybe?)
             */

            // Load the data again:
            var loadedMonster = serializer.Deserialize <MyMonster>(MyGameDatabase.Monsters[1]);

            var ability1 = serializer.Deserialize <MyAbility>(MyGameDatabase.Abilities[1]);
            var ability2 = serializer.Deserialize <MyAbility>(MyGameDatabase.Abilities[2]);
        }
예제 #17
0
파일: Tutorial.cs 프로젝트: zvinless/Ceras
        public void Step1_SimpleUsage()
        {
            //
            // 1.) Simple usage
            // aka. "I'm here for the cool features! I want to optimize for max-performance later"
            var person = new Person {
                Name = "riki", Health = 100
            };

            var ceras = new CerasSerializer();

            var data = ceras.Serialize(person);

            data.VisualizePrint("Simple Person");

            var clone1 = ceras.Deserialize <Person>(data);

            Console.WriteLine($"Clone: Name={clone1.Name}, Health={clone1.Health}");



            // 2.) Types
            // You can also serialize as <object>.
            // In that case the type information will be included.
            // If a type is written it will only be written ONCE, so a List<Person> will not suddenly waste a
            // ton of space by continously writing the type-names
            var objectData = ceras.Serialize <object>(person);

            objectData.VisualizePrint("Person as <object>");
            var objectClone = ceras.Deserialize <object>(objectData);



            //
            // 3.) Improvement:
            // Recycle the serialization buffer by keeping the reference to it around.
            // Optionally we can even let Ceras create (or resize) the buffer for us.
            byte[] buffer       = null;
            int    writtenBytes = ceras.Serialize(person, ref buffer);

            // Now we could send this over the network, for example:
            //   socket.Send(buffer, writtenBytes, SocketFlags.None);
            var clone2 = ceras.Deserialize <Person>(buffer);



            //
            // 4.)
            // Deciding what gets serialized
            // There are multiple ways to configure what members to serialize
            // Ceras determines member inclusion in this order:
            //
            //  - a. Any custom configuration using ConfigType<T> or ConfigType(type)
            //
            //  - b. [Include] and [Exclude] attributes on individual members
            //
            //  - c. [MemberConfig] attribute
            //
            //  - d. "DefaultTargets" setting in the SerializerConfig
            //       which defaults to 'TargetMember.PublicFields'
            //

            SerializerConfig config = new SerializerConfig();

            config.DefaultTargets = TargetMember.PublicProperties | TargetMember.PrivateFields;

            config.ConfigType <Person>()
            .ConfigMember(p => p.Name).Include()
            .ConfigMember(p => p.BestFriend).Include();



            //
            // 5.) Circular references
            // Serializers commonly have trouble serializing circular references.
            // Ceras supports every possible object-graph, and there's literally
            // nothing to do or configure, it just works out of the box.
            // Lets make an example anyway...

            var personA = new Person {
                Name = "alice"
            };
            var personB = new Person {
                Name = "bob"
            };

            personA.BestFriend = personB;
            personB.BestFriend = personA;

            var dataWithCircularReferences = ceras.Serialize(personA);

            dataWithCircularReferences.VisualizePrint("Circular references data");

            var cloneA = ceras.Deserialize <Person>(dataWithCircularReferences);

            if (cloneA.BestFriend.BestFriend.BestFriend.BestFriend.BestFriend.BestFriend == cloneA)
            {
                Console.WriteLine("Circular reference serialization working as intended!");
            }
            else
            {
                throw new Exception("There was some problem!");
            }


            // Works with self-references!
            // Ceras maintains object references while deserializing, even if the object a field/prop points to doesn't exist yet
            var personC = new Person {
                Name = "abc"
            };

            personC.BestFriend = personC;
            var cloneC = ceras.Deserialize <Person>(ceras.Serialize(personC));

            Debug.Assert(cloneC.BestFriend.BestFriend.BestFriend.BestFriend == cloneC);


            // Fully maintains identity of objects!
            // There is only one actual object instance here (personC). The array refers to the same object two times.
            // While Ceras deserializes the array it only creates a single instance of 'Person', exactly as intended.
            Person[] personArray = new Person[2];
            personArray[0] = personC;
            personArray[1] = personC;
            var personArrayClone = ceras.Deserialize <Person[]>(ceras.Serialize(personArray));

            Debug.Assert(personArray[0] == personArray[1]);
            Debug.Assert(ReferenceEquals(personArray[0], personArray[1]));
            Debug.Assert(personArray[0].BestFriend == personArray[1].BestFriend);
            Debug.Assert(personArray[0].BestFriend.BestFriend == personArray[1]);
        }
예제 #18
0
        public void Setup()
        {
            //
            // Create example data
            var parent1 = new Person
            {
                Age       = -901,
                FirstName = "Parent 1",
                LastName  = "abc",
                Sex       = Sex.Male,
            };
            var parent2 = new Person
            {
                Age       = 7881964,
                FirstName = "Parent 2",
                LastName  = "xyz",
                Sex       = Sex.Female,
            };

            _person = new Person
            {
                Age       = 5,
                FirstName = "Riki",
                LastName  = "Example Person Object",
                Sex       = Sex.Unknown,
                Parent1   = parent1,
                Parent2   = parent2,
            };

            _list = Enumerable.Range(25000, 100).Select(x => new Person {
                Age = x, FirstName = "a", LastName = "b", Sex = Sex.Female
            }).ToArray();

            //
            // Config Serializers
            _wire = new Wire.Serializer(new Wire.SerializerOptions(knownTypes: new Type[] { typeof(Person), typeof(Person[]) }));

            _netSerializer = new NetSerializer.Serializer(rootTypes: new Type[] { typeof(Person), typeof(Person[]) });

            var config = new SerializerConfig();

            config.DefaultTargets = TargetMember.AllPublic;
            var knownTypes = new[] { typeof(Person), typeof(List <>), typeof(Person[]) };

            config.KnownTypes.AddRange(knownTypes);
            config.PreserveReferences = false;
            _ceras = new CerasSerializer(config);

            //
            // Run each serializer once to verify they work correctly!
            if (!Equals(RunCeras(_person), _person))
            {
                ThrowError();
            }
            if (!Equals(RunJson(_person), _person))
            {
                ThrowError();
            }
            if (!Equals(RunMessagePackCSharp(_person), _person))
            {
                ThrowError();
            }
            if (!Equals(RunProtobuf(_person), _person))
            {
                ThrowError();
            }
            if (!Equals(RunWire(_person), _person))
            {
                ThrowError();
            }
            if (!Equals(RunNetSerializer(_person), _person))
            {
                ThrowError();
            }

            void ThrowError() => throw new InvalidOperationException("Cannot continue with the benchmark because a serializer does not round-trip an object correctly. (Benchmark results will be wrong)");
        }
예제 #19
0
파일: Blitting.cs 프로젝트: zvinless/Ceras
        public void BlittingEnums()
        {
            // Usually we don't use the reinterpret-formatter for enum members so we can minimize the size (varint encoding)

            var stressTestValues = new[]
            {
                long.MinValue, long.MaxValue, -1, 0, 1, 5, 1000, 255, 256,
                rngByte, rngByte, rngByte,
                rngLong, rngLong, rngLong, rngLong, rngLong, rngLong,
            };


            var config = new SerializerConfig();

            config.OnConfigNewType = t => t.CustomResolver = (c, t2) => c.Advanced.GetFormatterResolver <ReinterpretFormatterResolver>().GetFormatter(t2);
            //config.OnConfigNewType = t => t.CustomFormatter = (IFormatter)Activator.CreateInstance(typeof(EnumFormatterUnsafe<>).MakeGenericType(t.Type));
            var ceras = new CerasSerializer(config);

            var typesToTest = new[]
            {
                typeof(TestEnumInt8),
                typeof(TestEnumUInt8),
                typeof(TestEnumInt16),
                typeof(TestEnumUInt16),
                typeof(TestEnumInt64),
                typeof(TestEnumUInt64),
            };

            var serializeMethod   = typeof(CerasSerializer).GetMethods().First(m => m.Name == nameof(CerasSerializer.Serialize) && m.GetParameters().Length == 1);
            var deserializeMethod = typeof(CerasSerializer).GetMethods().First(m => m.Name == nameof(CerasSerializer.Deserialize) && m.GetParameters().Length == 1);


            foreach (var t in typesToTest)
            {
                Type baseType     = t.GetEnumUnderlyingType();
                int  expectedSize = Marshal.SizeOf(baseType);

                var values = Enum.GetValues(t).Cast <object>().Concat(stressTestValues.Cast <object>());

                foreach (var v in values)
                {
                    var obj = Enum.ToObject(t, v);

                    // We must call Serialize<T>, and we can't use <object> because that would embed the type information
                    var data = (byte[])serializeMethod.MakeGenericMethod(t).Invoke(ceras, new object[] { obj });

                    Assert.True(data.Length == expectedSize);

                    var cloneObj = deserializeMethod.MakeGenericMethod(t).Invoke(ceras, new object[] { data });

                    Assert.True(obj.Equals(cloneObj));
                }
            }


            Assert.True(ceras.Serialize(TestEnumInt8.a).Length == 1);
            Assert.True(ceras.Serialize(TestEnumUInt8.a).Length == 1);

            Assert.True(ceras.Serialize(TestEnumInt16.a).Length == 2);
            Assert.True(ceras.Serialize(TestEnumUInt16.a).Length == 2);

            Assert.True(ceras.Serialize(TestEnumInt64.a).Length == 8);
            Assert.True(ceras.Serialize(TestEnumUInt64.a).Length == 8);
        }
예제 #20
0
        static (CerasSerializer, List <Type>, Dictionary <Type, Type>) CreateSerializerAndTargets(IEnumerable <Assembly> asms)
        {
            // Find config method and create a SerializerConfig
            SerializerConfig config = new SerializerConfig();
            var configMethods       = asms.SelectMany(a => a.GetTypes())
                                      .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
                                      .Where(m => m.GetCustomAttribute <AotSerializerConfigAttribute>() != null)
                                      .ToArray();

            if (configMethods.Length > 1)
            {
                throw new Exception("Found more than one method with the CerasAutoGenConfig attribute!");
            }
            if (configMethods.Length == 1)
            {
                config = (SerializerConfig)configMethods[0].Invoke(null, null);
            }

            var ceras = new CerasSerializer(config);


            // Start with KnownTypes and user-marked types...
            HashSet <Type> newTypes = new HashSet <Type>();

            newTypes.AddRange(config.KnownTypes);
            newTypes.AddRange(asms.SelectMany(a => a.GetTypes()).Where(t => !t.IsAbstract && IsMarkedForAot(t)));


            // Go through each type, add all the member-types it wants to serialize as well
            HashSet <Type>          processedTypes = new HashSet <Type>();
            Dictionary <Type, Type> aotHint        = new Dictionary <Type, Type>();

            while (newTypes.Any())
            {
                // Get first, remove from "to explore" list, and add it to the "done" list.
                var t = newTypes.First();

                if (t.IsArray)
                {
                    t = t.GetElementType();
                }

                newTypes.Remove(t);
                processedTypes.Add(t);

                if (CerasSerializer.IsPrimitiveType(t))
                {
                    // Skip int, string, Type, ...
                    continue;
                }

                if (t.IsAbstract || t.ContainsGenericParameters)
                {
                    // Can't explore abstract or open generics
                    continue;
                }

                // Explore the type, add all member types
                var schema = ceras.GetTypeMetaData(t).PrimarySchema;

                foreach (var member in schema.Members)
                {
                    if (!processedTypes.Contains(member.MemberType))
                    {
                        newTypes.Add(member.MemberType);
                    }
                }

                var formatter     = ceras.GetSpecificFormatter(t);
                var formatterType = formatter.GetType();
                var needAot       =
                    CerasHelpers.IsDynamicFormatter(formatterType) ||
                    CerasHelpers.IsSchemaDynamicFormatter(formatterType) ||
                    IsMarkedForAot(t);

                if (needAot)
                {
                    continue;
                }

                aotHint[t] = formatterType;

                foreach (var type in formatterType.GenericTypeArguments)
                {
                    if (!processedTypes.Contains(type))
                    {
                        newTypes.Add(type);
                    }
                }
            }

            // Only leave things that use DynamicFormatter, or have the marker attribute
            List <Type> targets = new List <Type>();

            foreach (var t in processedTypes)
            {
                if (CerasSerializer.IsPrimitiveType(t))
                {
                    continue;                     // Skip int, string, Type, ...
                }
                if (t.IsAbstract || t.ContainsGenericParameters)
                {
                    continue;                     // Abstract or open generics can't have instances...
                }
                if (aotHint.ContainsKey(t))
                {
                    continue;
                }

                targets.Add(t);
            }

            return(ceras, targets, aotHint);

            bool IsMarkedForAot(Type t)
            {
                if (t.GetCustomAttributes(true).Any(a => a.GetType().FullName == Marker.FullName))
                {
                    return(true);                    // has 'Generate Formatter' attribute
                }
                return(false);
            }
        }
예제 #21
0
        static void Main(string[] args)
        {
#if NET45
            global::System.Console.WriteLine("Running on NET4.5");
#elif NET451
            global::System.Console.WriteLine("Running on NET4.5.1");
#elif NET452
            global::System.Console.WriteLine("Running on NET4.5.2");
#elif NET47
            global::System.Console.WriteLine("Running on NET4.7");
#elif NET47
            global::System.Console.WriteLine("Running on NET4.7");
#elif NET471
            global::System.Console.WriteLine("Running on NET4.7.1");
#elif NET472
            global::System.Console.WriteLine("Running on NET4.7.2");
#elif NETSTANDARD2_0
            global::System.Console.WriteLine("Running on NET STANDARD 2.0");
#else
#error Unhandled framework version!
#endif



            new Internals().FastCopy();

            new BuiltInTypes().Bitmap();

            var config = new SerializerConfig();
            config.Advanced.BitmapMode = BitmapMode.SaveAsBmp;
            var ceras = new CerasSerializer(config);

            var home      = System.Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
            var downloads = Path.Combine(home, "Downloads");

            var images = new Image[]
            {
                Image.FromFile(Path.Combine(downloads, @"68747470733a2f2f692e696d6775722e636f6d2f513839365567562e706e67.png")),
                Image.FromFile(Path.Combine(downloads, @"7plX.gif")),
                Image.FromFile(Path.Combine(downloads, @"TexturesCom_BrickOldMixedSize0012_1_seamless_S.jpg")),
                Image.FromFile(Path.Combine(downloads, @"New Drawing.png")),
                Image.FromFile(Path.Combine(downloads, @"smoke_1_40_128_corrected.png")),
                Image.FromFile(Path.Combine(downloads, @"Spheres_thumb9.png")),
            };

            for (int iteration = 0; iteration < 5; iteration++)
            {
                var imgData1 = ceras.Serialize(images);
                var clones   = ceras.Deserialize <Image[]>(imgData1);

                for (var cloneIndex = 0; cloneIndex < clones.Length; cloneIndex++)
                {
                    var c = clones[cloneIndex];
                    c.Dispose();
                    clones[cloneIndex] = null;
                }
            }


            byte[] sharedBuffer = new byte[100];
            int    offset       = 0;
            foreach (var sourceImage in images)
            {
                offset += ceras.Serialize(sourceImage, ref sharedBuffer, offset);
            }
            offset += ceras.Serialize(images, ref sharedBuffer, offset);

            int writtenLength = offset;

            List <Image> clonedImages = new List <Image>();
            offset = 0;

            for (var i = 0; i < images.Length; i++)
            {
                Image img = null;
                ceras.Deserialize(ref img, sharedBuffer, ref offset);
                clonedImages.Add(img);
            }
            Image[] imageArrayClone = null;
            ceras.Deserialize(ref imageArrayClone, sharedBuffer, ref offset);

            // Ensure all bytes consumed again
            Debug.Assert(offset == writtenLength);

            foreach (var img in clonedImages)
            {
                img.Dispose();
            }
            foreach (var img in imageArrayClone)
            {
                img.Dispose();
            }
        }
        public void TestWriteObjectWithCustomSerializable()
        {
            var config = new SerializationConfig();
            var sc = new SerializerConfig()
                .SetImplementation(new CustomSerializer())
                .SetTypeClass(typeof (CustomSerializableType));
            config.AddSerializerConfig(sc);
            var serializationService =
                new SerializationServiceBuilder().SetPortableVersion(1)
                    .AddPortableFactory(TestSerializationConstants.PORTABLE_FACTORY_ID, new TestPortableFactory())
                    .SetConfig(config).Build();

            var foo = new CustomSerializableType {Value = "foo"};

            var objectCarryingPortable1 = new ObjectCarryingPortable(foo);
            var data = serializationService.ToData(objectCarryingPortable1);
            var objectCarryingPortable2 = serializationService.ToObject<ObjectCarryingPortable>(data);
            Assert.AreEqual(objectCarryingPortable1, objectCarryingPortable2);
        }
예제 #23
0
파일: Program.cs 프로젝트: aspark/Ceras
        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                var error = "Not enough arguments. The last argument is always the .cs file output path, all arguments before that are the input assemblies (.dll files) of your unity project. Example: \"C:\\MyUnityProject\\Temp\\bin\\Debug\\Assembly-CSharp.dll C:\\MyUnityProject\\Assets\\Scripts\\GeneratedFormatters.cs\"";

                Console.WriteLine(error);
                throw new ArgumentException(error);
            }

            inputAssemblies  = args.Reverse().Skip(1).Reverse().ToArray();
            outputCsFileName = args.Reverse().First();

            var marker = typeof(CerasAutoGenFormatterAttribute);

            AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
            var asms = inputAssemblies.Select(Assembly.LoadFrom);

            var targets = asms.SelectMany(a => a.GetTypes())
                          .Where(t => t.GetCustomAttributes(true)
                                 .Any(a => a.GetType().FullName == marker.FullName))
                          .Where(t => !t.IsAbstract)
                          .ToList();

            Console.WriteLine($"Found: {targets.Count} targets");

            // Find config method and create a SerializerConfig
            SerializerConfig config = new SerializerConfig();
            var configMethods       = asms.SelectMany(a => a.GetTypes())
                                      .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
                                      .Where(m => m.GetCustomAttribute <CerasAutoGenConfigAttribute>() != null)
                                      .ToArray();

            if (configMethods.Length > 1)
            {
                throw new Exception("Found more than one config method!");
            }
            if (configMethods.Length == 1)
            {
                config = (SerializerConfig)configMethods[0].Invoke(null, null);
            }

            targets.AddRange(config.KnownTypes);

            var ceras = new CerasSerializer(config);

            StringBuilder fullCode = new StringBuilder(25 * 1000);

            fullCode.AppendLine("using Ceras;");
            fullCode.AppendLine("using Ceras.Formatters;");
            fullCode.AppendLine("namespace Ceras.GeneratedFormatters");
            fullCode.AppendLine("{");

            var setCustomFormatters = targets.Select(t => $"config.ConfigType<{t.FullName}>().CustomFormatter = new {t.Name}Formatter();");

            fullCode.AppendLine($@"
static class GeneratedFormatters
{{
	internal static void UseFormatters(SerializerConfig config)
	{{
		{string.Join("\n", setCustomFormatters)}
	}}
}}
");

            foreach (var t in targets)
            {
                SourceFormatterGenerator.Generate(t, ceras, fullCode);
            }
            fullCode.AppendLine("}");

            Console.WriteLine($"Parsing...");

            var syntaxTree = CSharpSyntaxTree.ParseText(fullCode.ToString());

            Console.WriteLine($"Formatting...");

            var workspace = new AdhocWorkspace();
            var options   = workspace.Options
                            .WithChangedOption(CSharpFormattingOptions.IndentBlock, true)
                            .WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInAccessors, true)
                            .WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInControlBlocks, true)
                            .WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInTypes, true)
                            .WithChangedOption(CSharpFormattingOptions.IndentBraces, false);

            syntaxTree = Formatter.Format(syntaxTree.GetRoot(), workspace, options).SyntaxTree;

            Console.WriteLine($"Saving...");

            using (var fs = File.OpenWrite(outputCsFileName))
                using (var w = new StreamWriter(fs))
                {
                    fs.SetLength(0);
                    w.WriteLine(syntaxTree.ToString());
                }



            // todo: maybe we'll generate an assembly instead of source code at some pointlater...
            //GenerateFormattersAssembly(targets);

            Thread.Sleep(300);
            Console.WriteLine($"> Done!");
        }
 public virtual SerializationConfig AddSerializerConfig(SerializerConfig serializerConfig)
 {
     GetSerializerConfigs().Add(serializerConfig);
     return this;
 }
예제 #25
0
 public static void ToCERAS <T>(this T obj, string filename, SerializerConfig config)
 {
     byte[] final;
     final = ToCERAS(obj, config);
     File.WriteAllBytes(filename, final);
 }