├── .gitignore ├── LICENSE ├── appveyor.yml ├── build └── pack.bat ├── docs ├── danger-danger.md ├── dynamic-types.md ├── example-outputs.md ├── faqs.md ├── flow.md ├── getting-started.md ├── serializers.md ├── type-handlers.md └── type-mappers.md ├── readme.md └── src ├── LazyData.Binary ├── BinaryDeserializer.cs ├── BinarySerializer.cs ├── Handlers │ ├── BasicBinaryPrimitiveHandler.cs │ └── IBinaryPrimitiveHandler.cs ├── IBinaryDeserializer.cs ├── IBinarySerializer.cs └── LazyData.Binary.csproj ├── LazyData.Bson ├── BsonDeserializer.cs ├── BsonSerializer.cs ├── IBsonDeserializer.cs ├── IBsonSerializer.cs └── LazyData.Bson.csproj ├── LazyData.Json ├── Handlers │ ├── BasicJsonPrimitiveHandler.cs │ └── IJsonPrimitiveHandler.cs ├── IJsonDeserializer.cs ├── IJsonSerializer.cs ├── JsonDeserializer.cs ├── JsonSerializer.cs └── LazyData.Json.csproj ├── LazyData.Numerics ├── Checkers │ └── NumericsPrimitiveChecker.cs ├── Handlers │ ├── NumericsBinaryPrimitiveHandler.cs │ ├── NumericsJsonPrimitiveHandler.cs │ └── NumericsXmlPrimitiveHandler.cs └── LazyData.Numerics.csproj ├── LazyData.PerformanceTests ├── LazyData.PerformanceTests.csproj ├── Models │ ├── DynamicTypesModel.cs │ ├── Gender.cs │ ├── Person.cs │ └── PersonList.cs ├── PerformanceConfig.cs ├── PerformanceScenario.cs └── Program.cs ├── LazyData.SuperLazy ├── LazyData.SuperLazy.csproj └── Transformer.cs ├── LazyData.Tests ├── Extensions │ └── AssertExtensions.cs ├── Helpers │ ├── SerializationTestHelper.cs │ └── TypeAssertionHelper.cs ├── LazyData.Tests.csproj ├── Models │ ├── B.cs │ ├── C.cs │ ├── CommonTypesModel.cs │ ├── ComplexModel.cs │ ├── CyclicModels.cs │ ├── DynamicTypesModel.cs │ ├── E.cs │ ├── NullableTypesModel.cs │ ├── NumericsTypesModel.cs │ └── SomeTypes.cs ├── SanityTests │ ├── BsonSanityTests.cs │ ├── GeneralTests.cs │ ├── ModelInterchangableTests.cs │ ├── SuperLazyTransformerTests.cs │ └── YamlSanityTests.cs ├── Serialization │ ├── CyclicSerializationTests.cs │ ├── DynamicModelSerializationTests.cs │ ├── NullableModelSerializationTests.cs │ ├── NulledModelSerializationTests.cs │ ├── NumericsModelSerializationTests.cs │ └── PopulatedModelSerializationTests.cs └── TypeMapper │ ├── DefaultTypeMapperTests.cs │ └── TypeAnalyzerTests.cs ├── LazyData.Xml ├── Handlers │ ├── BasicXmlPrimitiveHandler.cs │ └── IXmlPrimitiveHandler.cs ├── IXmlDeserializer.cs ├── IXmlSerializer.cs ├── LazyData.Xml.csproj ├── XmlDeserializer.cs └── XmlSerializer.cs ├── LazyData.Yaml ├── IYamlDeserializer.cs ├── IYamlSerializer.cs ├── LazyData.Yaml.csproj ├── YamlDeserializer.cs └── YamlSerializer.cs ├── LazyData.sln └── LazyData ├── Attributes ├── DynamicTypeAttribute.cs ├── PersistAttribute.cs └── PersistDataAttribute.cs ├── DataObject.cs ├── DefaultEncoding.cs ├── Exceptions ├── NoKnownTypeException.cs └── TypeNotPersistableException.cs ├── Extensions ├── IListExtensions.cs ├── ReflectionExtensions.cs └── TypeExtensions.cs ├── LazyData.csproj ├── Mappings ├── CollectionMapping.cs ├── DictionaryMapping.cs ├── Mappers │ ├── DefaultTypeMapper.cs │ ├── EverythingTypeMapper.cs │ ├── ITypeMapper.cs │ ├── MappingConfiguration.cs │ └── TypeMapper.cs ├── Mapping.cs ├── NestedMapping.cs ├── PropertyMapping.cs ├── TypeMapping.cs └── Types │ ├── ITypeAnalyzer.cs │ ├── ITypeCreator.cs │ ├── Primitives │ ├── Checkers │ │ ├── BasicPrimitiveChecker.cs │ │ ├── IPrimitiveChecker.cs │ │ └── PredicatePrimitiveChecker.cs │ ├── IPrimitiveRegistry.cs │ └── PrimitiveRegistry.cs │ ├── TypeAnalyzer.cs │ ├── TypeAnalyzerConfiguration.cs │ └── TypeCreator.cs ├── Registries ├── IMappingRegistry.cs └── MappingRegistry.cs └── Serialization ├── Debug └── DebugSerializer.cs ├── GenericDeserializer.cs ├── GenericSerializer.cs ├── IDeserializer.cs ├── IPrimitiveHandler.cs └── ISerializer.cs /.gitignore: -------------------------------------------------------------------------------- 1 | /src/.vs 2 | obj 3 | bin 4 | packages/ 5 | *.user 6 | *.suo 7 | .idea 8 | 9 | *.nupkg 10 | /src/LazyData.PerformanceTests/BenchmarkDotNet.Artifacts 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 LP 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 3.0.{build} 2 | branches: 3 | only: 4 | - master 5 | - build-test 6 | image: Visual Studio 2019 7 | configuration: Release 8 | dotnet_csproj: 9 | patch: true 10 | file: '**\*.csproj' 11 | version: '{version}' 12 | package_version: '{version}' 13 | assembly_version: '{version}' 14 | file_version: '{version}' 15 | informational_version: '{version}' 16 | before_build: 17 | - cmd: nuget restore src/LazyData.sln 18 | build: 19 | project: src/LazyData.sln 20 | publish_nuget: true 21 | verbosity: minimal 22 | artifacts: 23 | - path: '**\*.nupkg' 24 | deploy: 25 | provider: NuGet 26 | on: 27 | APPVEYOR_REPO_TAG: true 28 | server: 29 | api_key: 30 | secure: MR+iI5Hg7CeJK1+4Tb0jY5usaROJRWBgPnlksWZ8d/LSC2/sEfOeIpLvFmX1eOLW 31 | skip_symbols: true 32 | symbol_server: 33 | artifact: /.*\.nupkg/ 34 | -------------------------------------------------------------------------------- /build/pack.bat: -------------------------------------------------------------------------------- 1 | set version=0.3.0 2 | dotnet pack ../src/LazyData -c Release -o ../../_dist /p:version=%version% 3 | dotnet pack ../src/LazyData.Xml -c Release -o ../../_dist /p:version=%version% 4 | dotnet pack ../src/LazyData.Binary -c Release -o ../../_dist /p:version=%version% 5 | dotnet pack ../src/LazyData.Json -c Release -o ../../_dist /p:version=%version% 6 | dotnet pack ../src/LazyData.Bson -c Release -o ../../_dist /p:version=%version% 7 | dotnet pack ../src/LazyData.Yaml -c Release -o ../../_dist /p:version=%version% 8 | dotnet pack ../src/LazyData.Numerics -c Release -o ../../_dist /p:version=%version% 9 | dotnet pack ../src/LazyData.SuperLazy -c Release -o ../../_dist /p:version=%version% -------------------------------------------------------------------------------- /docs/danger-danger.md: -------------------------------------------------------------------------------- 1 | # Gotchas 2 | 3 | ## 3rd Party Objects 4 | 5 | The main gotcha is around the way the types are mapped for transforming, so if you are using the `DefaultTypeMapper` types need to have the `[PersistData]` attribute, which you cannot really insert into 3rd party classes. 6 | 7 | So it is recommended for this that you make your own models which contain the bits you care about for these scenarios and just copy the data into these transient models before you serialize, if that is not possible then you can use the `EverythingTypeMapper`. 8 | 9 | ## Ducktyped style data 10 | ~~So if you were to have something like a `List` which may contain many different types of object, this would not work without a custom serializer and type mapper, as it would not be able to statically analyse the type and possible types that would be contained.~~ 11 | 12 | ~~As when it came to deserialize it would be unsure as to what type of object each instance would be, so although this library supports lists, dictionaries, arrays etc it is recommended that you make sure your generics are not of a base type wherever possible.~~ 13 | 14 | ~~A possible workaround here is to make a custom class which derives from object and making it a known primitive, so you decide how to serialize this object a single unified way.~~ 15 | 16 | This is all supported now as `DynamicTypes` 17 | 18 | ## Cyclic Data 19 | 20 | If you have circular references it will blow up. It is advised to not have circular references... it is something that will be looked at, but its trying to do it in a way that will not deteriorate performance too much. 21 | 22 | ## Data Types 23 | 24 | Also there is only support for basic types, so if you end up having complex structs that need transforming in a specific way there will hopefully be a notion of `KnownTypes` where you can provide the transformers some information on how to serialize/deserialize types, but currently it will throw an exception if it doesnt know how to handle a type and cannot nest the object. 25 | 26 | ## Public Properties 27 | 28 | Currently it only supports persisting of public properties, so make sure you factor this into your POCOs. 29 | 30 | This was done as in certain frameworks like Unity, they expect certain fields to be public members rathe than properties so this was used to differentiate the expected sort of data. 31 | 32 | ## Migrations 33 | 34 | So one discussed point previously has been data migrations, long story short its not a solved problem at the moment, there are a few different ways to solve the problem but this is a problem for another day if people need it. 35 | 36 | If you don't know what I am on about here is an example: 37 | 38 | So you save your `game-1.sav` file which is using version 1 of the model, but now you have an update and have changed the model and its version 2, and has different fields and a data type has changed. So how do you get the old data into the new model format? 39 | 40 | ... well right now you don't, you have to manually map between them yourself, but in the future there may be some way to automagically work with the data in some tertiary format before it becomes a statically typed .net object. 41 | 42 | -------------------------------------------------------------------------------- /docs/dynamic-types.md: -------------------------------------------------------------------------------- 1 | # Dynamic Types 2 | 3 | One of the recent changes is to support the notion of dynamic types automatically. This will occur if the type mapper runs into any types which are interfaces, `object` or some type which is abstract or ambiguous. 4 | 5 | When it finds a dynamic type it flags it and the serialization layer will output type information so the deserializer can create the right type without needing to be told what it is. 6 | 7 | ## How to apply it 8 | 9 | As mentioned above it will automatically apply to any type which can not be automatically resolved at deserialization time. However in some cases you may be using inheritance and have a base class which all other classes inherit from, this will not be picked up automatically so in this case you would need to apply the `DynamicTypeAttribute` to the property in question. 10 | 11 | ## Overhead 12 | 13 | When this dynamic typing occurs it will output the type information with the serialized data, which will be output as a string, so here is an example: 14 | 15 | ```csharp 16 | // The model being used 17 | [Persist] 18 | public class DynamicTypesModel 19 | { 20 | [PersistData] 21 | public object DynamicNestedProperty { get; set; } 22 | 23 | [PersistData] 24 | public object DynamicPrimitiveProperty { get; set; } 25 | 26 | [PersistData] 27 | public IList DynamicList { get; set; } 28 | 29 | [PersistData] 30 | public IDictionary DynamicDictionary { get; set; } 31 | } 32 | ``` 33 | So the class above uses `object` type which is too ambiguous for deserialization, so the json serializer would output the below content: 34 | 35 | ```json 36 | { 37 | "DynamicNestedProperty":{ 38 | "Type":"Tests.Editor.Models.E", 39 | "Data":{ 40 | "IntValue":10 41 | } 42 | }, 43 | "DynamicPrimitiveProperty":{ 44 | "Type":"System.Int32", 45 | "Data":12 46 | }, 47 | "DynamicList":[ 48 | { 49 | "Type":"Tests.Editor.Models.E", 50 | "Data":{ 51 | "IntValue":22 52 | } 53 | }, 54 | { 55 | "Type":"Tests.Editor.Models.C", 56 | "Data":{ 57 | "FloatValue":25.0 58 | } 59 | }, 60 | { 61 | "Type":"System.Int32", 62 | "Data":20 63 | } 64 | ], 65 | "DynamicDictionary":[ 66 | { 67 | "Key":{ 68 | "Type":"System.String", 69 | "Data":"key1" 70 | }, 71 | "Value":{ 72 | "Type":"System.Int32", 73 | "Data":62 74 | } 75 | }, 76 | { 77 | "Key":{ 78 | "Type":"Tests.Editor.Models.E", 79 | "Data":{ 80 | "IntValue":99 81 | } 82 | }, 83 | "Value":{ 84 | "Type":"System.Int32", 85 | "Data":54 86 | } 87 | }, 88 | { 89 | "Key":{ 90 | "Type":"System.Int32", 91 | "Data":1 92 | }, 93 | "Value":{ 94 | "Type":"Tests.Editor.Models.C", 95 | "Data":{ 96 | "FloatValue":51.0 97 | } 98 | } 99 | } 100 | ], 101 | "Type":"Tests.Editor.Models.DynamicTypesModel" 102 | } 103 | ``` 104 | 105 | So as you can see because it cannot infer the type correctly it needs to analyze it and output the type with the data, which will increase the file size, however it will at least ensure your types are correctly mapped. -------------------------------------------------------------------------------- /docs/faqs.md: -------------------------------------------------------------------------------- 1 | # Faqs etc 2 | 3 | ## How performant is it? 4 | 5 | Well its pretty fast, there is a basic performance test for you to run yourself if you are interested within the unit test project, but for example: 6 | 7 | ``` 8 | Binary Serializing 9 | Serialized 10000 Entities in 00:00:00.4638837 10 | with 0.04638837ms average 11 | Serialized Large Entity with 10000 elements in 00:00:00.3841531 12 | large Entity Size 2000052bytes 13 | Deserialized Large Entity with 10000 elements in 00:00:00.8442814 14 | 15 | 16 | Json Serializing 17 | Serialized 10000 Entities in 00:00:01.1072485 18 | with 0.11072485 average 19 | Serialized Large Entity with 10000 elements in 00:00:02.0896456 20 | large Entity Size 14860085bytes 21 | Deserialized Large Entity with 10000 elements in 00:00:02.3295665 22 | 23 | 24 | Xml Serializing 25 | Serialized 10000 Entities in 00:00:01.0868938 26 | with 0.10868938 average 27 | Serialized Large Entity with 10000 elements in 00:00:01.5478223 28 | large Entity Size 22680128bytes 29 | Deserialized Large Entity with 10000 elements in 00:00:07.6778448 30 | ``` 31 | 32 | It also does not generate too much GC allocations, for binary serialization it is generally a couple of kb GC allocations, deserialization is usually about twice the size due to instantiations. 33 | 34 | Generally its fast enough for most use cases, and as it doesn't *require* you to alter your classes in any way, just write your Pocos in a sensible way and dump them out as data. 35 | 36 | ## Why does it not just do one data format? 37 | 38 | It was designed as a part of a bigger library to abstract away data formats, if you want to do JUST Json serialization then just use JSON.Net directly, or one of the other myriad of purely single format focused serializers. 39 | 40 | The benefit of this approach is that you can choose how to handle your data, if you want it in JSON to send to a web service, but binary to store as a cache on the file system, no problem just call the appropriate serializer. 41 | 42 | Take for example a typical game dev scenario where you have some simple objects representing items, quests, characters etc and you have custom tools that let you alter all these types. Now when you are developing you would probably want to work in a human readable format like Json or Xml, so just use this and output your data as whatever format and load it back in as the same format... but then what about when you go to release... chances are you would want to optimize your files and make them non human readable, so in that case just have a step to output the files as binary. 43 | 44 | You can now abstract away the underlying data format, and dont need to do any fancy manual serialization logic, you just pass in your objects and tell them what format they should be saved/loaded as, and as the formats are all using the same underlying mapping they will all work with the same type without you having to do anything. 45 | 46 | ## Is this just for Unity? 47 | 48 | No no, it was originally created as part of a unity framework but has been split out to be used in any .net platform that supports .net standard 2.0. 49 | 50 | ## Why is the setup so complicated? 51 | 52 | If you cba setting up the depdencies and dont need anything fancy, just include the `SuperLazy` assembly which has a preconfigured static class (yuck) that will just work for you out of the box. 53 | 54 | If you do want more control over how things are getting mapped and serialized etc, then you will have to manually set stuff up as explained in the getting started document. 55 | 56 | For larger projects its expected that there will be some form of dependency injection system in place or some other mechanism to create objects up front and pass them via IoC into whatever needs them, so the setup may look scary if you were to be doing it every time you want to serialize something, but its assumed you will just set it up once and share the instance everywhere (or if you are too lazy just use the pre made transformer). 57 | 58 | ## You keep mentioning ETL, what is it and how does it effect me? 59 | 60 | ETL stands for `Extract -> Transform -> Load` which is a common term when developing large data reliant applications, the notion is that you take data from somewhere (web service, xml file, database etc) in some various format, then transform the data to some other structure, then load it into somewhere else (database, json file, web service etc). 61 | 62 | This was the original reason this library was created, to allow people to create data pipelines with [Persistity](https://github.com/grofit/persistity), you can read more on it all there, but for example if you wanted to save your game data, or upload data to a high score board api, you would probably do the following: 63 | 64 | - Get model which contains all needed data 65 | - Convert it to some format required for persistance 66 | - Send payload to some end point 67 | 68 | So this could be: 69 | 70 | - Take your model -> convert it to JSON -> transform the json slightly -> send to a web service 71 | - Take your model -> convert it to binary -> save on the file system 72 | - Take your model -> convert it to binary -> encrypt it -> save on the file system 73 | - Take your model -> convert it to JSON -> send it to mongodb 74 | 75 | I mean the possibilities are endless, but ultimately you can wrap the above logic up in a singular pipeline for a given task, and then share this notion throughout your game, so rather than having to keep hand writing all these various bits all over the place you could do something like: 76 | 77 | ```csharp 78 | // Same setup as before but we add an encryption processor 79 | var encryptor = new AesEncryptor("some-pass-phrase"); 80 | var encryptionProcessor = new EncryptDataProcessor(encryptor); 81 | var writeFileEndpoint = new WriteFileEndpoint("savegame.sav"); 82 | 83 | // Same as before but we now add the processor into the mix 84 | var saveToBinaryFilePipeline = new PipelineBuilder() 85 | .SerializeWith(binarySerializer) // <-- That binary serializer would be from this lib 86 | .ProcessWith(encryptionProcessor) 87 | .SendTo(writeFileEndpoint) 88 | .Build(); 89 | 90 | // Execute the pipeline with your game data 91 | saveToBinaryFilePipeline.Execute(myGameData, SuccessCallback, ErrorCallback); 92 | ``` 93 | So again pairing this with dependency injection makes an easy way for you to just configure your data persistence needs ahead of time, then inject it into anything that needs it, and lets say you are releasing for a mobile device. 94 | 95 | If this stuff sounds cool and you want to learn more then take a look at persistity, which is built to do all of the above. -------------------------------------------------------------------------------- /docs/flow.md: -------------------------------------------------------------------------------- 1 | # Flow 2 | 3 | There are a few varying bits which do stuff on the process from taking a model and spitting it out in a format. 4 | 5 | From the users perspective the flow would start at a serializer but then its just magic from there on, so here is what happens under the hood: 6 | 7 | ``` 8 | ISerializer <- This takes the object and gets a mapping from the registry 9 | | for the type and then runs through the mapping serializing 10 | | and then outputting the data object in the given format. 11 | | 12 | | 13 | IMappingRegistry <- This contains all mappings for types, if a type has already 14 | | been mapped before then it will not analyze it again, if it 15 | | has not been mapped it will get it mapped and cache it. 16 | | 17 | | 18 | ITypeMapper <- This acts as an entry point to generate a mapping for a given 19 | | type, it will analyze the objects properties and then build 20 | | a mapping tree that represents all the things that need serializing 21 | | 22 | | 23 | ITypeAnalyzer <- This provides a way for the mapper to analyze the underlying types 24 | in a generic way, it provides information such as if something is 25 | a generic, if its a list, what the underlying type is etc. 26 | ``` 27 | 28 | As you can see its not actually that complicated, the main flow is primarily getting a type mapping, then visiting every mapped property and outputting its data in the required format. 29 | 30 | Deserializing is the same but it also has an `ITypeCreator` which is tasked with instantiating a type at runtime. 31 | 32 | ## Type Caching 33 | 34 | Because the mappings for each type are cached, it will have to generate the mapping for a type the first time it is required, which can cause an overhead if happening during a game loop or other critical time. 35 | 36 | If you want to side step this overhead of generating type mappings at runtime it is recommended you manually call the `mappingRegistry.GetMappingFor()` method before you start your game/app, this way it will build the type mappings ahead of time so when you go to call them at runtime they will already be known about and in memory. -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | If you just want to covnert your models to a given format and read it back in with no need for custom types etc you can just include the `LazyData.SuperLazy` assembly and use the `Transformer` which is a static class which contains methods which expose simple things like `ToJson`, `ToBinary`, `FromXml` etc as well as letting you convert between formats. 4 | 5 | However under the hood this helper is just abstracting the composition and initilization of the required components needed for the de/serializers to run. 6 | 7 | For example under the hood here is what normal setup would look like: 8 | 9 | ```csharp 10 | var typeCreator = new TypeCreator(); 11 | var typeAnalyzer = new TypeAnalyzer(); 12 | var typeMapper = new EverythingTypeMapper(typeAnalyzer); 13 | var mappingRegistry = new MappingRegistry(typeMapper); 14 | 15 | var jsonSerializer = new JsonSerializer(_mappingRegistry); 16 | var jsonDeserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 17 | ``` 18 | 19 | That would setup a JSON serializer and deserializer, and you can setup other de/serializers the same way. 20 | 21 | In most cases it is advised you use dependency injection and inject in the serializers however you need. 22 | 23 | ## Convoluted? 24 | 25 | On face value the above may seem convoluted, and you would probably be right, compared to most serialization frameworks you have to setup a load of stuff before you can get on and start serializing stuff. 26 | 27 | This is completely true, but the focus of this library is less day to day serialization and more higher level ETL related tasks, it *can* be used as a serialization framework, and if you want to just get up and running just use the `Transformer`, but as part of a bigger process this approach provides a more extensible and configurable way to manage your serialization pipelines. -------------------------------------------------------------------------------- /docs/serializers.md: -------------------------------------------------------------------------------- 1 | # Serializers 2 | 3 | Serializers offer a way to convert a statically typed model into a homogonised data object for use on other parts of the pipeline. They also wrap up the concept of type mapping, which is the way it knows how to extract and process your models. 4 | 5 | ## Serialization 6 | 7 | Currently there are 3 serializers which will let you convert any objets with correct attribute `[PersistData]` to and from: 8 | 9 | - Json 10 | - Binary 11 | - Xml 12 | 13 | You can easily add your own serializers, which implement `ISerializer` and `IDeserializer`. 14 | 15 | ## Type Mappings 16 | 17 | Type mappings are visitor tree style objects which express the underlying type as a tree, so for example when you pass in a class like: 18 | 19 | ```csharp 20 | [Persist] 21 | public class SomeClass 22 | { 23 | [PersistData] 24 | public float SomeValue { get; set; } 25 | } 26 | ``` 27 | 28 | It will behind the scenes analyse your type and work out what properties need to be bound, by default the `DefaultTypeMapper` should be used, but there is an interface for you to make your own, or an alternative `EverythingTypeMapper` which will just auto map every public property which has a get/set. 29 | 30 | ## Known Types 31 | 32 | The serializers know of most basic unity and .net types and how to handle them, however there will be scenarios where things like `ReactiveProperty` from unirx or other frameworks appear, that need to be mapped in a certain way, (i.e extract the value and bin the rest of it). This needs 2 things to be setup for these types to be processed correctly. 33 | 34 | 1. You need to make sure your `TypeMapper` (the interface of `ITypeMapper` does not know about this notion) is provided a list of known primitives upon creation 35 | 36 | 2. You need to provide your serializer with an implementation of `ITypeHandler` to tell it how to serialize the value. 37 | 38 | So for example if I wanted to support the unirx `ReactiveProperty` in binary I would do something like: 39 | 40 | ```csharp 41 | // TypeMapper setup 42 | var typeMapper = new DefaultTypeMapper(new []{ typeof(ReactiveProperty)}); 43 | 44 | // Class to handle known type 45 | public class ReactiveIntHandler : ITypeHandler 46 | { 47 | public bool MatchesType(Type type) 48 | { return type == typeof(ReactiveProperty); } 49 | 50 | public void HandleTypeIn(BinaryWriter writer, object data) 51 | { 52 | var typedObject = (ReactiveProperty)object; 53 | writer.Write((int)typedObject.Value); 54 | } 55 | 56 | public object HandleTypeOut(BinaryReader reader) 57 | { 58 | var value = reader.ReadInt32(); 59 | return new ReactiveProperty(value); 60 | } 61 | } 62 | 63 | // Pass known type handler to the Serializer and Deserializer 64 | var binaryConfig = new BinaryConfiguration { 65 | TypeHandlers = new []{ new ReactiveIntHandler() } 66 | } 67 | var serializer = new BinarySerializer(binaryConfig); 68 | var deserializer = new BinaryDeserializer(binaryConfig); 69 | 70 | // I can now use models with this property 71 | [Persist] 72 | public class SomeClass 73 | { 74 | [PersistData] 75 | public ReactiveProperty MyProperty {get;set;} 76 | } 77 | ``` 78 | 79 | It is a bit long winded and each serializer would need its own type handler but once it is setup you will be able to serialize any type you want in a given way, even the dreaded built in unity types if you wanted to strip certain data from a `GameObject` or whatever. 80 | 81 | ## Creating A Serializer 82 | 83 | This will hopefully become simpler in the future but the main idea is that you will be passed the type and need to get a mapping for the type which represents the structure of the data, and you iterate over that drilling down into the tree and converting each step into a piece of data. 84 | 85 | So for example if you were to want to create a CSV serializer you would probably create a string builder and look at something like the `BinarySerializer` and `BinaryDeserializer` to see how it writes out each value in a flat manner and just put a comma after it (well its obviously a bit more complex but thats the basics). 86 | 87 | Ultimately almost all De/serializers will take some configuration and an `IMappingRegistry` which will handle the type mapping for the types. -------------------------------------------------------------------------------- /docs/type-mappers.md: -------------------------------------------------------------------------------- 1 | # Type Mappers 2 | 3 | This is generally not that important for most users but there is the notion of a type mapper (`ITypeMapper`) which handles the visiting of the object tree and returning back a list of mappings that it runs through to extract and populate data on the underlying object. 4 | 5 | ## DefaultTypeMapper 6 | 7 | So in most cases you will want to use the `DefaultTypeMapper` which will automatically look at the types attributes and pull out the relevant properties for the objects. In most use cases you will probably want to provide this to the `IMappingRegistry`, however there are other mappers available. 8 | 9 | ## EverythingTypeMapper & TypeMapper 10 | 11 | There is an `EverythingTypeMapper` which doesnt bother checking for attributes and will just pump out EVERY public property that has a get/set available. 12 | 13 | This is primarily useful in scenarios where you are wanting to use 3rd party classes which are POCOs but you cannot decorate or if you are just using the serializers explicitly and want to just dump everything public out. 14 | 15 | There is also the `TypeMapper` which is the underlying abstract class which has most of the implementation data for `ITypeMapper`, but this is ultimately seen as a basis class for you to derive your own if needed, if you want to analyze your classes in a completely different way you can completely bypass this `TypeMapper` route and just implement your own `ITypeMapper`. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # LazyData 2 | 3 | A quick data (de)serialization framework for varying data formats in .net with a focus on clean and minimal serialized output for each format, mainly for game development scenarios such as in Unity, MonoGame etc. 4 | 5 | [![Build Status][build-status-image]][build-status-url] 6 | [![Nuget Package][nuget-image]][nuget-url] 7 | [![Join Discord Chat][discord-image]][discord-url] 8 | 9 | Formats supported 10 | 11 | - Xml 12 | - Binary 13 | - Json (via some JSON.Net implementation) 14 | - Bson (built on top of the Json Serializer, *Experimental*) 15 | - Yaml (built on top of the Json Serializer, *Experimental*) 16 | 17 | If you are interested in how the outputs would look take a look [here](docs/example-outputs.md) 18 | 19 | ## Examples 20 | 21 | If you are SUPER lazy you can use the `SuperLazy.Transformer` to get stuff done like a typical serialization framework: 22 | 23 | ```csharp 24 | var modelIn = new SomeModel(); 25 | var data = Transformer.ToJson(modelIn); 26 | var modelOut = Transformer.FromJson(data); 27 | ``` 28 | 29 | You can even lazily transform your data between formats on the fly, which is helpful if you debug in JSON but want to use Binary for production, here is an example of one of the tests: 30 | 31 | ```csharp 32 | var model = SerializationTestHelper.GeneratePopulatedModel(); 33 | 34 | var expectdString = Transformer.ToJson(model); 35 | var xml = Transformer.FromJsonToXml(expectdString); 36 | var binary = Transformer.FromXmlToBinary(xml); 37 | var json = Transformer.FromBinaryToJson(binary); 38 | 39 | Assert.AreEqual(expectdString, json); 40 | ``` 41 | 42 | ## Non Lazy Approach 43 | 44 | The static transformer is there for people who dont care about customizing the library and just want to (de)serialize everything however the library was built to be configurable so you can skip the helper `Transformer` class and make the serializers yourself like so: 45 | 46 | ```csharp 47 | public class SomeClass 48 | { 49 | public float SomeValue { get; set; } 50 | } 51 | 52 | var mappingRegistry = new MappingRegistry(new EverythingTypeMapper()); 53 | var serializer = new JsonSerializer(_mappingRegistry); 54 | var output = serializer.Serialize(model); 55 | Console.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 56 | Console.WriteLine(output.AsString); 57 | ``` 58 | 59 | ### Deserialize stuff 60 | ```csharp 61 | var someDataFromAFile = getData(); 62 | var dataObject = new DataObject(someDataFromAFile); 63 | 64 | var mappingRegistry = new MappingRegistry(new EverythingTypeMapper()); 65 | var deserializer = new JsonSerializer(_mappingRegistry); 66 | var model = deserializer.Deserialize(dataObject); 67 | ``` 68 | 69 | You can alternatively use an `DefaultTypeMapper` instead of the `EverythingTypeMapper` which will only attempt to serialize things with attributes on. The allowing you to not need any custom attributes. This is handy for scenarios where you just treat your models as pure data classes. 70 | 71 | 72 | ### Only serialize certain properties 73 | ```csharp 74 | [Persist] 75 | public class SomeClass 76 | { 77 | [PersistData] 78 | public float SomeValue { get; set; } 79 | 80 | public string NotPersisted { get; set; } 81 | } 82 | 83 | var mappingRegistry = new MappingRegistry(new DefaultTypeMapper()); 84 | var serializer = new JsonSerializer(_mappingRegistry); 85 | var output = serializer.Serialize(model); 86 | 87 | Console.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 88 | Console.WriteLine(output.AsString); 89 | ``` 90 | 91 | The `[Persist]` attribute indicates that this should be output in the serialized data, on a class it indicates it is a root object that contains serialized data, on a property it indicates the property should be mapped. 92 | 93 | This attribute is used rather than `[Serialize]` because it is due to it being originally meant for ETL processes, if you want to just treat it like a serialization framework you can bypass the need for attributes entirely. 94 | 95 | ## Docs 96 | 97 | Check out the docs directory for docs which go into more detail. 98 | 99 | ## Tests 100 | 101 | There are a suite of unit tests which verify most scenarios, as well as output some performance related stats, it is recommended you take a peek at them if you want to see more advanced scenarios. 102 | 103 | ## Blurb 104 | 105 | This was originally part of the [Persistity library](https://github.com/grofit/persistity) for unity *(which was originally part of [EcsRx library](https://github.com/grofit/ecsrx))*, however was separated out to make more generic and reuseable and although its still meant to be used as a smaller part of a larger process, it has some helpers to allow it to be used just like a basic serializer without much effort. 106 | 107 | The original focus of this library was to provide a consistent way to pass data around and convert/transform it between formats and types easily however as the serialization pieces can be used in isolation purely for serialization 108 | 109 | 110 | [build-status-image]: https://ci.appveyor.com/api/projects/status/sn2vsn0vfib14emg?svg=true 111 | [build-status-url]: https://ci.appveyor.com/project/grofit/lazydata/branch/master 112 | [nuget-image]: https://img.shields.io/nuget/v/LazyData.svg?style=flat-square 113 | [nuget-url]: https://www.nuget.org/packages/LazyData/ 114 | [discord-image]: https://img.shields.io/discord/488609938399297536.svg 115 | [discord-url]: https://discord.gg/bS2rnGz 116 | -------------------------------------------------------------------------------- /src/LazyData.Binary/BinaryDeserializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using LazyData.Binary.Handlers; 5 | using LazyData.Mappings.Types; 6 | using LazyData.Registries; 7 | using LazyData.Serialization; 8 | 9 | namespace LazyData.Binary 10 | { 11 | public class BinaryDeserializer : GenericDeserializer, IBinaryDeserializer 12 | { 13 | public override IPrimitiveHandler DefaultPrimitiveHandler { get; } = new BasicBinaryPrimitiveHandler(); 14 | 15 | public BinaryDeserializer(IMappingRegistry mappingRegistry, ITypeCreator typeCreator, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, typeCreator, customPrimitiveHandlers) 16 | {} 17 | 18 | protected override bool IsDataNull(BinaryReader reader) 19 | { 20 | var currentPosition = reader.BaseStream.Position; 21 | 22 | foreach (var nullByte in BinarySerializer.NullDataSig) 23 | { 24 | var readByte = reader.ReadByte(); 25 | if (nullByte != readByte) 26 | { 27 | reader.BaseStream.Position = currentPosition; 28 | return false; 29 | } 30 | } 31 | return true; 32 | } 33 | 34 | protected override bool IsObjectNull(BinaryReader reader) 35 | { 36 | var currentPosition = reader.BaseStream.Position; 37 | 38 | foreach (var nullByte in BinarySerializer.NullObjectSig) 39 | { 40 | var readByte = reader.ReadByte(); 41 | if (nullByte != readByte) 42 | { 43 | reader.BaseStream.Position = currentPosition; 44 | return false; 45 | } 46 | } 47 | return true; 48 | } 49 | 50 | protected override int GetCountFromState(BinaryReader state) 51 | { return state.ReadInt32(); } 52 | 53 | public override object Deserialize(DataObject data, Type type = null) 54 | { 55 | using (var memoryStream = new MemoryStream(data.AsBytes)) 56 | using (var reader = new BinaryReader(memoryStream)) 57 | { 58 | var containsType = reader.ReadBoolean(); 59 | if (containsType) 60 | { 61 | var typeName = reader.ReadString(); 62 | if(type == null) 63 | { type = TypeCreator.LoadType(typeName); } 64 | } 65 | 66 | var typeMapping = MappingRegistry.GetMappingFor(type); 67 | var instance = Activator.CreateInstance(type); 68 | Deserialize(typeMapping.InternalMappings, instance, reader); 69 | return instance; 70 | } 71 | } 72 | 73 | public override void DeserializeInto(DataObject data, object existingInstance) 74 | { 75 | using (var memoryStream = new MemoryStream(data.AsBytes)) 76 | using (var reader = new BinaryReader(memoryStream)) 77 | { 78 | var containsType = reader.ReadBoolean(); 79 | if (containsType) { reader.ReadString(); } 80 | 81 | var typeMapping = MappingRegistry.GetMappingFor(existingInstance.GetType()); 82 | Deserialize(typeMapping.InternalMappings, existingInstance, reader); 83 | } 84 | } 85 | 86 | protected override string GetDynamicTypeNameFromState(BinaryReader state) 87 | { return state.ReadString(); } 88 | 89 | protected override BinaryReader GetDynamicTypeDataFromState(BinaryReader state) 90 | { return state; } 91 | } 92 | } -------------------------------------------------------------------------------- /src/LazyData.Binary/BinarySerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using LazyData.Binary.Handlers; 5 | using LazyData.Extensions; 6 | using LazyData.Registries; 7 | using LazyData.Serialization; 8 | 9 | namespace LazyData.Binary 10 | { 11 | public class BinarySerializer : GenericSerializer, IBinarySerializer 12 | { 13 | public static readonly byte[] NullDataSig = { 141, 141 }; 14 | public static readonly byte[] NullObjectSig = { 141, 229, 141 }; 15 | 16 | public override IPrimitiveHandler DefaultPrimitiveHandler { get; } = new BasicBinaryPrimitiveHandler(); 17 | 18 | public BinarySerializer(IMappingRegistry mappingRegistry, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, customPrimitiveHandlers) 19 | {} 20 | 21 | protected override void HandleNullData(BinaryWriter state) 22 | { state.Write(NullDataSig); } 23 | 24 | protected override void HandleNullObject(BinaryWriter state) 25 | { state.Write(NullObjectSig); } 26 | 27 | protected override void AddCountToState(BinaryWriter state, int count) 28 | { state.Write(count); } 29 | 30 | protected override BinaryWriter GetDynamicTypeState(BinaryWriter state, Type type) 31 | { 32 | state.Write(type.GetPersistableName()); 33 | return state; 34 | } 35 | 36 | public override DataObject Serialize(object data, bool persistType = false) 37 | { 38 | var typeMapping = MappingRegistry.GetMappingFor(data.GetType()); 39 | using (var memoryStream = new MemoryStream()) 40 | using (var binaryWriter = new BinaryWriter(memoryStream)) 41 | { 42 | binaryWriter.Write(persistType); 43 | 44 | if(persistType) 45 | { binaryWriter.Write(typeMapping.Type.GetPersistableName()); } 46 | 47 | Serialize(typeMapping.InternalMappings, data, binaryWriter); 48 | binaryWriter.Flush(); 49 | memoryStream.Seek(0, SeekOrigin.Begin); 50 | 51 | return new DataObject(memoryStream.ToArray()); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/LazyData.Binary/Handlers/BasicBinaryPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using LazyData.Mappings.Types.Primitives.Checkers; 4 | 5 | namespace LazyData.Binary.Handlers 6 | { 7 | public class BasicBinaryPrimitiveHandler : IBinaryPrimitiveHandler 8 | { 9 | public IPrimitiveChecker PrimitiveChecker { get; } = new BasicPrimitiveChecker(); 10 | 11 | public void Serialize(BinaryWriter state, object data, Type type) 12 | { 13 | if (type == typeof(byte)) { state.Write((byte)data); } 14 | else if (type == typeof(short)) { state.Write((short)data); } 15 | else if (type == typeof(int)) { state.Write((int)data); } 16 | else if (type == typeof(long)) { state.Write((long)data); } 17 | else if (type == typeof(bool)) { state.Write((bool)data); } 18 | else if (type == typeof(float)) { state.Write((float)data); } 19 | else if (type == typeof(double)) { state.Write((double)data); } 20 | else if (type == typeof(decimal)) { state.Write((decimal)data); } 21 | else if (type.IsEnum) { state.Write((int)data); } 22 | else if (type == typeof(TimeSpan)) { state.Write(((TimeSpan)data).TotalMilliseconds); } 23 | else if (type == typeof(DateTime)) { state.Write(((DateTime)data).ToBinary()); } 24 | else if (type == typeof(Guid)) { state.Write(((Guid)data).ToString()); } 25 | else if (type == typeof(string)) { state.Write(data.ToString()); } 26 | } 27 | 28 | public object Deserialize(BinaryReader state, Type type) 29 | { 30 | if (type == typeof(byte)) { return state.ReadByte(); } 31 | if (type == typeof(short)) { return state.ReadInt16(); } 32 | if (type == typeof(int)) { return state.ReadInt32(); } 33 | if (type == typeof(long)) { return state.ReadInt64(); } 34 | if (type == typeof(bool)) { return state.ReadBoolean(); } 35 | if (type == typeof(float)) { return state.ReadSingle(); } 36 | if (type == typeof(double)) { return state.ReadDouble(); } 37 | if (type == typeof(decimal)) { return state.ReadDecimal(); } 38 | if (type.IsEnum) 39 | { 40 | var value = state.ReadInt32(); 41 | return Enum.ToObject(type, value); 42 | } 43 | if (type == typeof(Guid)) 44 | { 45 | return new Guid(state.ReadString()); 46 | } 47 | if (type == typeof(DateTime)) 48 | { 49 | var binaryTime = state.ReadInt64(); 50 | return DateTime.FromBinary(binaryTime); 51 | } 52 | if (type == typeof(TimeSpan)) 53 | { 54 | var totalMilliseconds = state.ReadDouble(); 55 | return TimeSpan.FromMilliseconds(totalMilliseconds); 56 | } 57 | 58 | return state.ReadString(); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/LazyData.Binary/Handlers/IBinaryPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using LazyData.Serialization; 3 | 4 | namespace LazyData.Binary.Handlers 5 | { 6 | public interface IBinaryPrimitiveHandler : IPrimitiveHandler 7 | {} 8 | } -------------------------------------------------------------------------------- /src/LazyData.Binary/IBinaryDeserializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Serialization; 2 | 3 | namespace LazyData.Binary 4 | { 5 | public interface IBinaryDeserializer : IDeserializer { } 6 | } -------------------------------------------------------------------------------- /src/LazyData.Binary/IBinarySerializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Serialization; 2 | 3 | namespace LazyData.Binary 4 | { 5 | public interface IBinarySerializer : ISerializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Binary/LazyData.Binary.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.0;net46 6 | LazyData.Binary 7 | Grofit (LP) 8 | https://github.com/grofit/lazydata/blob/master/LICENSE 9 | https://github.com/grofit/lazydata 10 | false 11 | Binary serializer for use with LazyData 12 | serialization game-development binary 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/LazyData.Bson/BsonDeserializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using LazyData.Json; 5 | using LazyData.Json.Handlers; 6 | using LazyData.Mappings.Types; 7 | using LazyData.Registries; 8 | using Newtonsoft.Json.Bson; 9 | using Newtonsoft.Json.Linq; 10 | 11 | namespace LazyData.Bson 12 | { 13 | public class BsonDeserializer : JsonDeserializer, IBsonDeserializer 14 | { 15 | public BsonDeserializer(IMappingRegistry mappingRegistry, ITypeCreator typeCreator, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, typeCreator, customPrimitiveHandlers) 16 | {} 17 | 18 | public override object Deserialize(DataObject data, Type type = null) 19 | { 20 | JObject jsonData; 21 | using(var memoryStream = new MemoryStream(data.AsBytes)) 22 | using(var bsonReader = new BsonReader(memoryStream)) 23 | { 24 | jsonData = (JObject)JToken.ReadFrom(bsonReader); 25 | } 26 | 27 | if (type == null) 28 | { 29 | var typeName = jsonData[JsonSerializer.TypeField].ToString(); 30 | type = TypeCreator.LoadType(typeName); 31 | } 32 | 33 | var typeMapping = MappingRegistry.GetMappingFor(type); 34 | var instance = Activator.CreateInstance(type); 35 | 36 | Deserialize(typeMapping.InternalMappings, instance, jsonData); 37 | return instance; 38 | } 39 | 40 | public override void DeserializeInto(DataObject data, object existingInstance) 41 | { 42 | JObject jsonData; 43 | using(var memoryStream = new MemoryStream(data.AsBytes)) 44 | using(var bsonReader = new BsonReader(memoryStream)) 45 | { 46 | jsonData = (JObject)JToken.ReadFrom(bsonReader); 47 | } 48 | 49 | var typeName = jsonData[JsonSerializer.TypeField].ToString(); 50 | var type = TypeCreator.LoadType(typeName); 51 | var typeMapping = MappingRegistry.GetMappingFor(type); 52 | 53 | Deserialize(typeMapping.InternalMappings, existingInstance, jsonData); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/LazyData.Bson/BsonSerializer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using LazyData.Extensions; 4 | using LazyData.Json; 5 | using LazyData.Json.Handlers; 6 | using LazyData.Registries; 7 | using Newtonsoft.Json.Bson; 8 | using Newtonsoft.Json.Linq; 9 | 10 | namespace LazyData.Bson 11 | { 12 | public class BsonSerializer : JsonSerializer, IBsonSerializer 13 | { 14 | public BsonSerializer(IMappingRegistry mappingRegistry, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, customPrimitiveHandlers) 15 | {} 16 | 17 | public override DataObject Serialize(object data, bool persistType = false) 18 | { 19 | var node = new JObject(); 20 | var dataType = data.GetType(); 21 | var typeMapping = MappingRegistry.GetMappingFor(dataType); 22 | Serialize(typeMapping.InternalMappings, data, node); 23 | 24 | if (persistType) 25 | { 26 | var typeElement = new JProperty(TypeField, dataType.GetPersistableName()); 27 | node.Add(typeElement); 28 | } 29 | 30 | using(var memoryStream = new MemoryStream()) 31 | using (var bsonWriter = new BsonWriter(memoryStream)) 32 | { 33 | node.WriteTo(bsonWriter); 34 | return new DataObject(memoryStream.ToArray()); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/LazyData.Bson/IBsonDeserializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Json; 2 | 3 | namespace LazyData.Bson 4 | { 5 | public interface IBsonDeserializer : IJsonDeserializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Bson/IBsonSerializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Json; 2 | 3 | namespace LazyData.Bson 4 | { 5 | public interface IBsonSerializer : IJsonSerializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Bson/LazyData.Bson.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.0;net46 6 | LazyData.Bson 7 | Grofit (LP) 8 | https://github.com/grofit/lazydata/blob/master/LICENSE 9 | https://github.com/grofit/lazydata 10 | false 11 | Bson serializer for use with LazyData 12 | serialization game-development bson 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/LazyData.Json/Handlers/BasicJsonPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Extensions; 3 | using LazyData.Mappings.Types.Primitives.Checkers; 4 | using Newtonsoft.Json.Linq; 5 | 6 | namespace LazyData.Json.Handlers 7 | { 8 | public class BasicJsonPrimitiveHandler : IJsonPrimitiveHandler 9 | { 10 | private readonly Type[] StringCompatibleTypes = 11 | { 12 | typeof(string), typeof(bool), typeof(byte), typeof(short), typeof(int), 13 | typeof(long), typeof(Guid), typeof(float), typeof(double), typeof(decimal) 14 | }; 15 | 16 | public IPrimitiveChecker PrimitiveChecker { get; } = new BasicPrimitiveChecker(); 17 | 18 | public void Serialize(JToken state, object data, Type type) 19 | { 20 | if (type == typeof(DateTime)) 21 | { 22 | var typedValue = (DateTime)data; 23 | var stringValue = typedValue.ToBinary().ToString(); 24 | state.Replace(new JValue(stringValue)); 25 | return; 26 | } 27 | 28 | if (type == typeof(TimeSpan)) 29 | { 30 | var typedValue = (TimeSpan)data; 31 | var stringValue = typedValue.TotalMilliseconds.ToString(); 32 | state.Replace(new JValue(stringValue)); 33 | return; 34 | } 35 | 36 | if (type.IsTypeOf(StringCompatibleTypes) || type.IsEnum) 37 | { 38 | state.Replace(new JValue(data)); 39 | } 40 | } 41 | 42 | public object Deserialize(JToken state, Type type) 43 | { 44 | if (type == typeof(DateTime)) 45 | { 46 | var binaryDate = state.ToObject(); 47 | return DateTime.FromBinary(binaryDate); 48 | } 49 | 50 | if (type == typeof(TimeSpan)) 51 | { 52 | var binaryDate = state.ToObject(); 53 | return TimeSpan.FromMilliseconds(binaryDate); 54 | } 55 | 56 | if (type.IsEnum) 57 | { return Enum.Parse(type, state.ToString()); } 58 | 59 | return state.ToObject(type); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/LazyData.Json/Handlers/IJsonPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Serialization; 2 | using Newtonsoft.Json.Linq; 3 | 4 | namespace LazyData.Json.Handlers 5 | { 6 | public interface IJsonPrimitiveHandler : IPrimitiveHandler 7 | {} 8 | } -------------------------------------------------------------------------------- /src/LazyData.Json/IJsonDeserializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Serialization; 2 | 3 | namespace LazyData.Json 4 | { 5 | public interface IJsonDeserializer : IDeserializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Json/IJsonSerializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Serialization; 2 | 3 | namespace LazyData.Json 4 | { 5 | public interface IJsonSerializer : ISerializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Json/JsonDeserializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using LazyData.Json.Handlers; 6 | using LazyData.Mappings; 7 | using LazyData.Mappings.Types; 8 | using LazyData.Registries; 9 | using LazyData.Serialization; 10 | using Newtonsoft.Json.Linq; 11 | 12 | namespace LazyData.Json 13 | { 14 | public class JsonDeserializer : GenericDeserializer, IJsonDeserializer 15 | { 16 | public override IPrimitiveHandler DefaultPrimitiveHandler { get; } = new BasicJsonPrimitiveHandler(); 17 | 18 | public JsonDeserializer(IMappingRegistry mappingRegistry, ITypeCreator typeCreator, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, typeCreator, customPrimitiveHandlers) 19 | {} 20 | 21 | protected override bool IsDataNull(JToken state) 22 | { 23 | if(state == null) { return true; } 24 | if (state.Type == JTokenType.Null || state.Type == JTokenType.None) 25 | { return true; } 26 | 27 | return false; 28 | } 29 | 30 | protected override bool IsObjectNull(JToken state) 31 | { return IsDataNull(state); } 32 | 33 | protected override string GetDynamicTypeNameFromState(JToken state) 34 | { return state[JsonSerializer.TypeField].ToString(); } 35 | 36 | protected override JToken GetDynamicTypeDataFromState(JToken state) 37 | { return state[JsonSerializer.DataField]; } 38 | 39 | public override object Deserialize(DataObject data, Type type = null) 40 | { 41 | var jsonData = JObject.Parse(data.AsString); 42 | if(type == null) 43 | { 44 | var typeName = jsonData[JsonSerializer.TypeField].ToString(); 45 | type = TypeCreator.LoadType(typeName); 46 | } 47 | 48 | var typeMapping = MappingRegistry.GetMappingFor(type); 49 | var instance = Activator.CreateInstance(type); 50 | 51 | Deserialize(typeMapping.InternalMappings, instance, jsonData); 52 | return instance; 53 | } 54 | 55 | public override void DeserializeInto(DataObject data, object existingInstance) 56 | { 57 | var jsonData = JObject.Parse(data.AsString); 58 | var typeMapping = MappingRegistry.GetMappingFor(existingInstance.GetType()); 59 | 60 | Deserialize(typeMapping.InternalMappings, existingInstance, jsonData); 61 | } 62 | 63 | protected override int GetCountFromState(JToken state) 64 | { return state.Children().Count(); } 65 | 66 | protected override void Deserialize(IEnumerable mappings, T instance, JToken state) 67 | { 68 | foreach (var mapping in mappings) 69 | { 70 | var childNode = state.HasValues ? state[mapping.LocalName] : null; 71 | DelegateMappingType(mapping, instance, childNode); 72 | } 73 | } 74 | 75 | protected override void DeserializeCollection(CollectionMapping mapping, T instance, JToken state) 76 | { 77 | if (IsObjectNull(state)) 78 | { 79 | mapping.SetValue(instance, null); 80 | return; 81 | } 82 | 83 | var count = GetCountFromState(state); 84 | var collectionInstance = CreateCollectionFromMapping(mapping, count); 85 | mapping.SetValue(instance, collectionInstance); 86 | 87 | for (var i = 0; i < count; i++) 88 | { 89 | var collectionElement = state[i]; 90 | var elementInstance = DeserializeCollectionElement(mapping, collectionElement); 91 | 92 | if (collectionInstance.IsFixedSize) 93 | { collectionInstance[i] = elementInstance; } 94 | else 95 | { collectionInstance.Insert(i, elementInstance); } 96 | } 97 | } 98 | 99 | protected override void DeserializeDictionary(DictionaryMapping mapping, T instance, JToken state) 100 | { 101 | if (IsObjectNull(state)) 102 | { 103 | mapping.SetValue(instance, null); 104 | return; 105 | } 106 | 107 | var count = GetCountFromState(state); 108 | 109 | var dictionary = CreateDictionaryFromMapping(mapping); 110 | mapping.SetValue(instance, dictionary); 111 | 112 | for (var i = 0; i < count; i++) 113 | { 114 | var keyValuePairElement = state[i]; 115 | DeserializeDictionaryKeyValuePair(mapping, dictionary, keyValuePairElement); 116 | } 117 | } 118 | 119 | protected override void DeserializeDictionaryKeyValuePair(DictionaryMapping mapping, IDictionary dictionary, JToken state) 120 | { 121 | var keyElement = state[JsonSerializer.KeyField]; 122 | var keyInstance = DeserializeDictionaryKey(mapping, keyElement); 123 | var valueElement = state[JsonSerializer.ValueField]; 124 | var valueInstance = DeserializeDictionaryValue(mapping, valueElement); 125 | dictionary.Add(keyInstance, valueInstance); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /src/LazyData.Json/JsonSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using LazyData.Extensions; 5 | using LazyData.Json.Handlers; 6 | using LazyData.Mappings; 7 | using LazyData.Registries; 8 | using LazyData.Serialization; 9 | using Newtonsoft.Json.Linq; 10 | 11 | namespace LazyData.Json 12 | { 13 | public class JsonSerializer : GenericSerializer, IJsonSerializer 14 | { 15 | public const string TypeField = "@Type"; 16 | public const string DataField = "@Data"; 17 | public const string KeyField = "Key"; 18 | public const string ValueField = "Value"; 19 | 20 | public override IPrimitiveHandler DefaultPrimitiveHandler { get; } = new BasicJsonPrimitiveHandler(); 21 | 22 | public JsonSerializer(IMappingRegistry mappingRegistry, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, customPrimitiveHandlers) 23 | {} 24 | 25 | protected override void HandleNullData(JToken state) 26 | { state.Replace(JValue.CreateNull()); } 27 | 28 | protected override void HandleNullObject(JToken state) 29 | { HandleNullData(state); } 30 | 31 | protected override void AddCountToState(JToken state, int count) 32 | { } 33 | 34 | protected override JToken GetDynamicTypeState(JToken state, Type type) 35 | { 36 | state[TypeField] = type.GetPersistableName(); 37 | return state[DataField] = new JObject(); 38 | } 39 | 40 | public override DataObject Serialize(object data, bool persistType = false) 41 | { 42 | var node = new JObject(); 43 | var dataType = data.GetType(); 44 | var typeMapping = MappingRegistry.GetMappingFor(dataType); 45 | Serialize(typeMapping.InternalMappings, data, node); 46 | 47 | if (persistType) 48 | { 49 | var typeElement = new JProperty(TypeField, dataType.GetPersistableName()); 50 | node.Add(typeElement); 51 | } 52 | 53 | var xmlString = node.ToString(); 54 | return new DataObject(xmlString); 55 | } 56 | 57 | protected override void Serialize(IEnumerable mappings, T data, JToken state) 58 | { 59 | foreach (var mapping in mappings) 60 | { 61 | var newElement = new JObject(); 62 | state[mapping.LocalName] = newElement; 63 | 64 | DelegateMappingType(mapping, data, newElement); 65 | } 66 | } 67 | 68 | protected override void SerializeCollection(CollectionMapping collectionMapping, T data, JToken state) 69 | { 70 | var objectValue = AttemptGetValue(collectionMapping, data, state); 71 | if (objectValue == null) { return; } 72 | var collectionValue = (objectValue as IList); 73 | 74 | var jsonArray = new JArray(); 75 | state.Replace(jsonArray); 76 | for (var i = 0; i < collectionValue.Count; i++) 77 | { 78 | var element = collectionValue[i]; 79 | var jsonObject = new JObject(); 80 | jsonArray.Add(jsonObject); 81 | SerializeCollectionElement(collectionMapping, element, jsonObject); 82 | } 83 | } 84 | 85 | protected override void SerializeDictionary(DictionaryMapping dictionaryMapping, T data, JToken state) 86 | { 87 | var objectValue = AttemptGetValue(dictionaryMapping, data, state); 88 | if (objectValue == null) { return; } 89 | var dictionaryValue = (objectValue as IDictionary); 90 | 91 | var jsonArray = new JArray(); 92 | state.Replace(jsonArray); 93 | foreach (var key in dictionaryValue.Keys) 94 | { 95 | var jsonObject = new JObject(); 96 | jsonArray.Add(jsonObject); 97 | SerializeDictionaryKeyValuePair(dictionaryMapping, dictionaryValue, key, jsonObject); 98 | } 99 | } 100 | 101 | protected override void SerializeDictionaryKeyValuePair(DictionaryMapping dictionaryMapping, IDictionary dictionary, object key, JToken state) 102 | { 103 | var keyElement = new JObject(); 104 | var valueElement = new JObject(); 105 | state[KeyField] = keyElement; 106 | state[ValueField] = valueElement; 107 | 108 | SerializeDictionaryKey(dictionaryMapping, key, keyElement); 109 | SerializeDictionaryValue(dictionaryMapping, dictionary[key], valueElement); 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/LazyData.Json/LazyData.Json.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.0;net46 6 | LazyData.Json 7 | Grofit (LP) 8 | https://github.com/grofit/lazydata/blob/master/LICENSE 9 | https://github.com/grofit/lazydata 10 | false 11 | Json serializer for use with LazyData 12 | serialization game-development json 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/LazyData.Numerics/Checkers/NumericsPrimitiveChecker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using LazyData.Mappings.Types.Primitives.Checkers; 4 | 5 | namespace LazyData.Numerics.Checkers 6 | { 7 | public class NumericsPrimitiveChecker : IPrimitiveChecker 8 | { 9 | public bool IsPrimitive(Type type) 10 | { 11 | return type == typeof(Vector2) || 12 | type == typeof(Vector3) || 13 | type == typeof(Vector4) || 14 | type == typeof(Quaternion); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/LazyData.Numerics/Handlers/NumericsBinaryPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Numerics; 4 | using LazyData.Binary.Handlers; 5 | using LazyData.Mappings.Types.Primitives.Checkers; 6 | using LazyData.Numerics.Checkers; 7 | 8 | namespace LazyData.Numerics.Handlers 9 | { 10 | public class NumericsBinaryPrimitiveHandler : IBinaryPrimitiveHandler 11 | { 12 | public IPrimitiveChecker PrimitiveChecker { get; } = new NumericsPrimitiveChecker(); 13 | 14 | public void Serialize(BinaryWriter state, object data, Type type) 15 | { 16 | if (type == typeof(Vector2)) 17 | { 18 | var vector = (Vector2)data; 19 | state.Write(vector.X); 20 | state.Write(vector.Y); 21 | } 22 | else if (type == typeof(Vector3)) 23 | { 24 | var vector = (Vector3)data; 25 | state.Write(vector.X); 26 | state.Write(vector.Y); 27 | state.Write(vector.Z); 28 | } 29 | else if (type == typeof(Vector4)) 30 | { 31 | var vector = (Vector4)data; 32 | state.Write(vector.X); 33 | state.Write(vector.Y); 34 | state.Write(vector.Z); 35 | state.Write(vector.W); 36 | } 37 | else if (type == typeof(Quaternion)) 38 | { 39 | var quaternion = (Quaternion)data; 40 | state.Write(quaternion.X); 41 | state.Write(quaternion.Y); 42 | state.Write(quaternion.Z); 43 | state.Write(quaternion.W); 44 | } 45 | } 46 | 47 | public object Deserialize(BinaryReader state, Type type) 48 | { 49 | if (type == typeof(Vector2)) 50 | { 51 | var x = state.ReadSingle(); 52 | var y = state.ReadSingle(); 53 | return new Vector2(x, y); 54 | } 55 | if (type == typeof(Vector3)) 56 | { 57 | var x = state.ReadSingle(); 58 | var y = state.ReadSingle(); 59 | var z = state.ReadSingle(); 60 | return new Vector3(x, y, z); 61 | } 62 | if (type == typeof(Vector4)) 63 | { 64 | var x = state.ReadSingle(); 65 | var y = state.ReadSingle(); 66 | var z = state.ReadSingle(); 67 | var w = state.ReadSingle(); 68 | return new Vector4(x, y, z, w); 69 | } 70 | if (type == typeof(Quaternion)) 71 | { 72 | var x = state.ReadSingle(); 73 | var y = state.ReadSingle(); 74 | var z = state.ReadSingle(); 75 | var w = state.ReadSingle(); 76 | return new Quaternion(x, y, z, w); 77 | } 78 | 79 | return null; 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/LazyData.Numerics/Handlers/NumericsJsonPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using LazyData.Json.Handlers; 4 | using LazyData.Mappings.Types.Primitives.Checkers; 5 | using LazyData.Numerics.Checkers; 6 | using Newtonsoft.Json.Linq; 7 | 8 | namespace LazyData.Numerics.Handlers 9 | { 10 | public class NumericsJsonPrimitiveHandler : IJsonPrimitiveHandler 11 | { 12 | public IPrimitiveChecker PrimitiveChecker { get; } = new NumericsPrimitiveChecker(); 13 | 14 | public void Serialize(JToken state, object data, Type type) 15 | { 16 | if (type == typeof(Vector2)) 17 | { 18 | var typedObject = (Vector2)data; 19 | state["x"] = typedObject.X; 20 | state["y"] = typedObject.Y; 21 | return; 22 | } 23 | if (type == typeof(Vector3)) 24 | { 25 | var typedObject = (Vector3)data; 26 | state["x"] = typedObject.X; 27 | state["y"] = typedObject.Y; 28 | state["z"] = typedObject.Z; 29 | return; 30 | } 31 | if (type == typeof(Vector4)) 32 | { 33 | var typedObject = (Vector4)data; 34 | state["x"] = typedObject.X; 35 | state["y"] = typedObject.Y; 36 | state["z"] = typedObject.Z; 37 | state["w"] = typedObject.W; 38 | return; 39 | } 40 | if (type == typeof(Quaternion)) 41 | { 42 | var typedObject = (Quaternion)data; 43 | state["x"] = typedObject.X; 44 | state["y"] = typedObject.Y; 45 | state["z"] = typedObject.Z; 46 | state["w"] = typedObject.W; 47 | return; 48 | } 49 | } 50 | 51 | public object Deserialize(JToken state, Type type) 52 | { 53 | if (type == typeof(Vector2)) 54 | { return new Vector2(state["x"].ToObject(), state["y"].ToObject()); } 55 | if (type == typeof(Vector3)) 56 | { return new Vector3(state["x"].ToObject(), state["y"].ToObject(), state["z"].ToObject()); } 57 | if (type == typeof(Vector4)) 58 | { return new Vector4(state["x"].ToObject(), state["y"].ToObject(), state["z"].ToObject(), state["w"].ToObject()); } 59 | if (type == typeof(Quaternion)) 60 | { return new Quaternion(state["x"].ToObject(), state["y"].ToObject(), state["z"].ToObject(), state["w"].ToObject()); } 61 | 62 | return null; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/LazyData.Numerics/Handlers/NumericsXmlPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using System.Xml.Linq; 4 | using LazyData.Mappings.Types.Primitives.Checkers; 5 | using LazyData.Numerics.Checkers; 6 | using LazyData.Xml.Handlers; 7 | 8 | namespace LazyData.Numerics.Handlers 9 | { 10 | public class NumericsXmlPrimitiveHandler : IXmlPrimitiveHandler 11 | { 12 | public IPrimitiveChecker PrimitiveChecker { get; } = new NumericsPrimitiveChecker(); 13 | 14 | public void Serialize(XElement state, object data, Type type) 15 | { 16 | if (type == typeof(Vector2)) 17 | { 18 | var typedObject = (Vector2)data; 19 | state.Add(new XElement("x", typedObject.X)); 20 | state.Add(new XElement("y", typedObject.Y)); 21 | return; 22 | } 23 | if (type == typeof(Vector3)) 24 | { 25 | var typedObject = (Vector3)data; 26 | state.Add(new XElement("x", typedObject.X)); 27 | state.Add(new XElement("y", typedObject.Y)); 28 | state.Add(new XElement("z", typedObject.Z)); 29 | return; 30 | } 31 | if (type == typeof(Vector4)) 32 | { 33 | var typedObject = (Vector4)data; 34 | state.Add(new XElement("x", typedObject.X)); 35 | state.Add(new XElement("y", typedObject.Y)); 36 | state.Add(new XElement("z", typedObject.Z)); 37 | state.Add(new XElement("w", typedObject.W)); 38 | return; 39 | } 40 | if (type == typeof(Quaternion)) 41 | { 42 | var typedObject = (Quaternion)data; 43 | state.Add(new XElement("x", typedObject.X)); 44 | state.Add(new XElement("y", typedObject.Y)); 45 | state.Add(new XElement("z", typedObject.Z)); 46 | state.Add(new XElement("w", typedObject.W)); 47 | return; 48 | } 49 | } 50 | 51 | public object Deserialize(XElement state, Type type) 52 | { 53 | if (type == typeof(Vector2)) 54 | { 55 | var x = float.Parse(state.Element("x").Value); 56 | var y = float.Parse(state.Element("y").Value); 57 | return new Vector2(x, y); 58 | } 59 | if (type == typeof(Vector3)) 60 | { 61 | var x = float.Parse(state.Element("x").Value); 62 | var y = float.Parse(state.Element("y").Value); 63 | var z = float.Parse(state.Element("z").Value); 64 | return new Vector3(x, y, z); 65 | } 66 | if (type == typeof(Vector4)) 67 | { 68 | var x = float.Parse(state.Element("x").Value); 69 | var y = float.Parse(state.Element("y").Value); 70 | var z = float.Parse(state.Element("z").Value); 71 | var w = float.Parse(state.Element("w").Value); 72 | return new Vector4(x, y, z, w); 73 | } 74 | if (type == typeof(Quaternion)) 75 | { 76 | var x = float.Parse(state.Element("x").Value); 77 | var y = float.Parse(state.Element("y").Value); 78 | var z = float.Parse(state.Element("z").Value); 79 | var w = float.Parse(state.Element("w").Value); 80 | return new Quaternion(x, y, z, w); 81 | } 82 | 83 | return null; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/LazyData.Numerics/LazyData.Numerics.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.0;net46 6 | LazyData.Numerics 7 | Grofit (LP) 8 | https://github.com/grofit/lazydata/blob/master/LICENSE 9 | https://github.com/grofit/lazydata 10 | false 11 | Add default handling for System.Numerics.Vectors 12 | serialization game-development json xml binary 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.0.0\ref\netcoreapp2.0\System.Numerics.Vectors.dll 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/LazyData.PerformanceTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/Models/DynamicTypesModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LazyData.PerformanceTests.Models 4 | { 5 | public class DynamicTypesModel 6 | { 7 | public object DynamicNestedProperty { get; set; } 8 | public object DynamicPrimitiveProperty { get; set; } 9 | public IList DynamicList { get; set; } 10 | public IDictionary DynamicDictionary { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/Models/Gender.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData.PerformanceTests.Models 2 | { 3 | public enum Gender 4 | { 5 | Unknown, Male, Female, 6 | } 7 | } -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/Models/Person.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData.PerformanceTests.Models 2 | { 3 | public class Person 4 | { 5 | public int Age { get; set; } 6 | public string FirstName { get; set; } 7 | public string LastName { get; set; } 8 | public Gender Gender { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/Models/PersonList.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData.PerformanceTests.Models 2 | { 3 | public class PersonList 4 | { 5 | public Person[] Models { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/PerformanceConfig.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Columns; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Diagnosers; 4 | using BenchmarkDotNet.Environments; 5 | using BenchmarkDotNet.Exporters; 6 | using BenchmarkDotNet.Horology; 7 | using BenchmarkDotNet.Jobs; 8 | using BenchmarkDotNet.Reports; 9 | 10 | namespace LazyData.PerformanceTests 11 | { 12 | public class PerformanceConfig : ManualConfig 13 | { 14 | public PerformanceConfig() 15 | { 16 | Add(MarkdownExporter.GitHub); 17 | Add(MemoryDiagnoser.Default); 18 | 19 | var job = Job.ShortRun.WithLaunchCount(1) 20 | .WithIterationCount(1) 21 | .WithWarmupCount(1) 22 | .With(Runtime.Core) 23 | .With(Platform.X64); 24 | Add(job); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/PerformanceScenario.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using BenchmarkDotNet.Attributes; 5 | using LazyData.Binary; 6 | using LazyData.Json; 7 | using LazyData.Mappings.Mappers; 8 | using LazyData.Mappings.Types; 9 | using LazyData.PerformanceTests.Models; 10 | using LazyData.Registries; 11 | using LazyData.Serialization; 12 | using LazyData.Xml; 13 | 14 | namespace LazyData.PerformanceTests 15 | { 16 | [Config(typeof(PerformanceConfig))] 17 | public class PerformanceScenario 18 | { 19 | [Params(1, 1000)] 20 | public int Iterations; 21 | 22 | private IBinarySerializer _binarySerializer; 23 | private IBinaryDeserializer _binaryDeserializer; 24 | 25 | private IJsonSerializer _jsonSerializer; 26 | private IJsonDeserializer _jsonDeserializer; 27 | 28 | private IXmlSerializer _xmlSerializer; 29 | private IXmlDeserializer _xmlDeserializer; 30 | 31 | [GlobalSetup] 32 | public void Setup() 33 | { 34 | var typeCreator = new TypeCreator(); 35 | var typeAnalyzer = new TypeAnalyzer(); 36 | var typeMapper = new EverythingTypeMapper(typeAnalyzer); 37 | var mappingRegistry = new MappingRegistry(typeMapper); 38 | 39 | _binarySerializer = new BinarySerializer(mappingRegistry); 40 | _binaryDeserializer = new BinaryDeserializer(mappingRegistry, typeCreator); 41 | 42 | _jsonSerializer = new JsonSerializer(mappingRegistry); 43 | _jsonDeserializer = new JsonDeserializer(mappingRegistry, typeCreator); 44 | 45 | _xmlSerializer = new XmlSerializer(mappingRegistry); 46 | _xmlDeserializer = new XmlDeserializer(mappingRegistry, typeCreator); 47 | } 48 | 49 | private DataObject SerializeModel(object model, ISerializer serializer) 50 | {return serializer.Serialize(model); } 51 | 52 | private void DeserializeModel(Type type, DataObject data, IDeserializer serializer) 53 | { serializer.Deserialize(data, type); } 54 | 55 | private Person CreatePerson() 56 | { 57 | return new Person 58 | { 59 | Age = 99999, 60 | FirstName = "John", 61 | LastName = "Doe", 62 | Gender = Gender.Male, 63 | }; 64 | } 65 | 66 | private PersonList CreatePersonList() 67 | { 68 | return new PersonList 69 | { 70 | Models = Enumerable.Range(0, Iterations).Select(x => CreatePerson()).ToArray() 71 | }; 72 | } 73 | 74 | private DynamicTypesModel CreateDynamicModel() 75 | { 76 | var model = new DynamicTypesModel(); 77 | model.DynamicNestedProperty = CreatePerson(); 78 | model.DynamicPrimitiveProperty = 12; 79 | 80 | model.DynamicList = new List(); 81 | model.DynamicList.Add(CreatePerson()); 82 | model.DynamicList.Add("Hello"); 83 | model.DynamicList.Add(20); 84 | 85 | model.DynamicDictionary = new Dictionary(); 86 | model.DynamicDictionary.Add("key1", 62); 87 | model.DynamicDictionary.Add(CreatePerson(), 54); 88 | model.DynamicDictionary.Add(1, CreatePerson()); 89 | return model; 90 | } 91 | 92 | [Benchmark] 93 | public void IterateBinarySerialization() 94 | { 95 | var model = CreatePerson(); 96 | for (var i = 0; i < Iterations; i++) 97 | { 98 | var dataObject = SerializeModel(model, _binarySerializer); 99 | DeserializeModel(typeof(Person), dataObject, _binaryDeserializer); 100 | } 101 | } 102 | 103 | [Benchmark] 104 | public void IterateJsonSerialization() 105 | { 106 | var model = CreatePerson(); 107 | for (var i = 0; i < Iterations; i++) 108 | { 109 | var dataObject = SerializeModel(model, _jsonSerializer); 110 | DeserializeModel(typeof(Person), dataObject, _jsonDeserializer); 111 | } 112 | } 113 | 114 | [Benchmark] 115 | public void IterateXmlSerialization() 116 | { 117 | var model = CreatePerson(); 118 | for (var i = 0; i < Iterations; i++) 119 | { 120 | var dataObject = SerializeModel(model, _xmlSerializer); 121 | DeserializeModel(typeof(Person), dataObject, _xmlDeserializer); 122 | } 123 | } 124 | 125 | [Benchmark] 126 | public void CollectionBinarySerialization() 127 | { 128 | var model = CreatePersonList(); 129 | var dataObject = SerializeModel(model, _binarySerializer); 130 | DeserializeModel(typeof(PersonList), dataObject, _binaryDeserializer); 131 | } 132 | 133 | [Benchmark] 134 | public void CollectionJsonSerialization() 135 | { 136 | var model = CreatePersonList(); 137 | var dataObject = SerializeModel(model, _jsonSerializer); 138 | DeserializeModel(typeof(PersonList), dataObject, _jsonDeserializer); 139 | } 140 | 141 | [Benchmark] 142 | public void CollectionXmlSerialization() 143 | { 144 | var model = CreatePersonList(); 145 | var dataObject = SerializeModel(model, _xmlSerializer); 146 | DeserializeModel(typeof(PersonList), dataObject, _xmlDeserializer); 147 | } 148 | 149 | [Benchmark] 150 | public void DynamicBinarySerialization() 151 | { 152 | var model = CreateDynamicModel(); 153 | for (var i = 0; i < Iterations; i++) 154 | { 155 | var dataObject = SerializeModel(model, _binarySerializer); 156 | DeserializeModel(typeof(DynamicTypesModel), dataObject, _binaryDeserializer); 157 | } 158 | } 159 | 160 | [Benchmark] 161 | public void DynamicJsonSerialization() 162 | { 163 | var model = CreateDynamicModel(); 164 | for (var i = 0; i < Iterations; i++) 165 | { 166 | var dataObject = SerializeModel(model, _jsonSerializer); 167 | DeserializeModel(typeof(DynamicTypesModel), dataObject, _jsonDeserializer); 168 | } 169 | } 170 | 171 | [Benchmark] 172 | public void DynamicXmlSerialization() 173 | { 174 | var model = CreateDynamicModel(); 175 | for (var i = 0; i < Iterations; i++) 176 | { 177 | var dataObject = SerializeModel(model, _xmlSerializer); 178 | DeserializeModel(typeof(DynamicTypesModel), dataObject, _xmlDeserializer); 179 | } 180 | } 181 | } 182 | } -------------------------------------------------------------------------------- /src/LazyData.PerformanceTests/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Columns; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Horology; 4 | using BenchmarkDotNet.Loggers; 5 | using BenchmarkDotNet.Reports; 6 | using BenchmarkDotNet.Running; 7 | 8 | namespace LazyData.PerformanceTests 9 | { 10 | public class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | #if RELEASE 15 | var config = new PerformanceConfig() 16 | .With(new SummaryStyle 17 | { 18 | TimeUnit = TimeUnit.Millisecond, SizeUnit = SizeUnit.KB, PrintUnitsInHeader = true, 19 | PrintUnitsInContent = true 20 | }) 21 | .With(ConsoleLogger.Default) 22 | .With(DefaultColumnProviders.Instance); 23 | 24 | BenchmarkRunner.Run(config); 25 | #elif DEBUG 26 | var scenario = new PerformanceScenario(); 27 | scenario.Iterations = 10; 28 | scenario.Setup(); 29 | 30 | scenario.CollectionBinarySerialization(); 31 | scenario.CollectionJsonSerialization(); 32 | scenario.CollectionXmlSerialization(); 33 | scenario.DynamicBinarySerialization(); 34 | scenario.DynamicJsonSerialization(); 35 | scenario.DynamicXmlSerialization(); 36 | scenario.IterateBinarySerialization(); 37 | scenario.IterateJsonSerialization(); 38 | scenario.IterateXmlSerialization(); 39 | #endif 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/LazyData.SuperLazy/LazyData.SuperLazy.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 0.0.0 4 | netstandard2.0;net46 5 | LazyData.SuperLazy 6 | Grofit (LP) 7 | https://github.com/grofit/lazydata/blob/master/LICENSE 8 | https://github.com/grofit/lazydata 9 | false 10 | A super lazy helper class to statically access serializers 11 | serialization game-development json xml binary 12 | 13 | 14 | 15 | 16 | 17 | 18 | {8AE4F137-FCFB-4B1C-B8E0-CE6CF98EE3D9} 19 | LazyData 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/LazyData.SuperLazy/Transformer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Binary; 2 | using LazyData.Json; 3 | using LazyData.Mappings.Mappers; 4 | using LazyData.Mappings.Types; 5 | using LazyData.Registries; 6 | using LazyData.Xml; 7 | 8 | namespace LazyData.SuperLazy 9 | { 10 | public static class Transformer 11 | { 12 | private static readonly IMappingRegistry _mappingRegistry; 13 | private static readonly ITypeAnalyzer _typeAnalyzer; 14 | private static readonly ITypeCreator _typeCreator; 15 | private static readonly ITypeMapper _typeMapper; 16 | 17 | private static readonly IJsonSerializer _jsonSerializer; 18 | private static readonly IJsonDeserializer _jsonDeserializer; 19 | private static readonly IBinarySerializer _binarySerializer; 20 | private static readonly IBinaryDeserializer _binaryDeserializer; 21 | private static readonly IXmlSerializer _xmlSerializer; 22 | private static readonly IXmlDeserializer _xmlDeserializer; 23 | 24 | static Transformer() 25 | { 26 | _typeCreator = new TypeCreator(); 27 | _typeAnalyzer = new TypeAnalyzer(); 28 | _typeMapper = new EverythingTypeMapper(_typeAnalyzer); 29 | _mappingRegistry = new MappingRegistry(_typeMapper); 30 | 31 | _jsonSerializer = new JsonSerializer(_mappingRegistry); 32 | _jsonDeserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 33 | _binarySerializer = new BinarySerializer(_mappingRegistry); 34 | _binaryDeserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator); 35 | _xmlSerializer = new XmlSerializer(_mappingRegistry); 36 | _xmlDeserializer = new XmlDeserializer(_mappingRegistry, _typeCreator); 37 | } 38 | 39 | public static byte[] ToBinary(T obj) 40 | { return _binarySerializer.Serialize(obj).AsBytes; } 41 | 42 | public static T FromBinary(byte[] binary) where T : new() 43 | { return _binaryDeserializer.Deserialize(new DataObject(binary)); } 44 | 45 | public static string ToJson(T obj) 46 | { return _jsonSerializer.Serialize(obj).AsString; } 47 | 48 | public static T FromJson(string json) where T : new() 49 | { return _jsonDeserializer.Deserialize(new DataObject(json)); } 50 | 51 | public static string ToXml(T obj) 52 | { return _xmlSerializer.Serialize(obj).AsString; } 53 | 54 | public static T FromXml(string xml) where T : new() 55 | { return _xmlDeserializer.Deserialize(new DataObject(xml)); } 56 | 57 | public static byte[] FromXmlToBinary(string xml) 58 | { 59 | var obj = _xmlDeserializer.Deserialize(new DataObject(xml), typeof(T)); 60 | return _binarySerializer.Serialize(obj).AsBytes; 61 | } 62 | 63 | public static byte[] FromJsonToBinary(string json) 64 | { 65 | var obj = _jsonDeserializer.Deserialize(new DataObject(json), typeof(T)); 66 | return _binarySerializer.Serialize(obj).AsBytes; 67 | } 68 | 69 | public static string FromJsonToXml(string json) 70 | { 71 | var obj = _jsonDeserializer.Deserialize(new DataObject(json), typeof(T)); 72 | return _xmlSerializer.Serialize(obj).AsString; 73 | } 74 | 75 | public static string FromBinaryToXml(byte[] binary) 76 | { 77 | var obj = _binaryDeserializer.Deserialize(new DataObject(binary), typeof(T)); 78 | return _xmlSerializer.Serialize(obj).AsString; 79 | } 80 | 81 | public static string FromXmlToJson(string json) 82 | { 83 | var obj = _xmlDeserializer.Deserialize(new DataObject(json), typeof(T)); 84 | return _jsonSerializer.Serialize(obj).AsString; 85 | } 86 | 87 | public static string FromBinaryToJson(byte[] binary) 88 | { 89 | var obj = _binaryDeserializer.Deserialize(new DataObject(binary), typeof(T)); 90 | return _jsonSerializer.Serialize(obj).AsString; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Extensions/AssertExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using Xunit; 5 | 6 | namespace LazyData.Tests.Extensions 7 | { 8 | public class AssertExtensions : Assert 9 | { 10 | public static void AreEqual(object expected, object actual) 11 | { 12 | var expectedStr = JsonConvert.SerializeObject(expected); 13 | var actualStr = JsonConvert.SerializeObject(actual); 14 | Equal(expectedStr, actualStr); 15 | } 16 | 17 | public static void AreEqual(JObject expected, JObject actual) 18 | { 19 | var expectedStr = expected.ToString(); 20 | var actualStr = actual.ToString(); 21 | Equal(expectedStr, actualStr); 22 | } 23 | 24 | public static void IsRuntimeType(Type type) 25 | { Equal(typeof(T), type); } 26 | } 27 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Helpers/SerializationTestHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Numerics; 4 | using LazyData.Tests.Models; 5 | using Newtonsoft.Json.Linq; 6 | using Assert = LazyData.Tests.Extensions.AssertExtensions; 7 | 8 | namespace LazyData.Tests.Helpers 9 | { 10 | public static class SerializationTestHelper 11 | { 12 | public static ComplexModel GeneratePopulatedModel() 13 | { 14 | var a = new ComplexModel(); 15 | a.TestValue = "WOW"; 16 | a.NonPersisted = 100; 17 | a.Stuff.Add("woop"); 18 | a.Stuff.Add("poow"); 19 | 20 | a.NestedValue = new B 21 | { 22 | IntValue = 0, 23 | StringValue = "Hello", 24 | NestedArray = new[] { new C { FloatValue = 2.43f } } 25 | }; 26 | 27 | a.NestedArray = new B[2]; 28 | a.NestedArray[0] = new B 29 | { 30 | IntValue = 20, 31 | StringValue = "There", 32 | NestedArray = new[] { new C { FloatValue = 3.5f } } 33 | }; 34 | 35 | a.NestedArray[1] = new B 36 | { 37 | IntValue = 30, 38 | StringValue = "Sir", 39 | NestedArray = new[] 40 | { 41 | new C { FloatValue = 4.1f }, 42 | new C { FloatValue = 5.2f } 43 | } 44 | }; 45 | 46 | a.CustomList.Add(1); 47 | a.CustomList.Add(2); 48 | a.CustomList.Add(3); 49 | 50 | a.AllTypes = new CommonTypesModel 51 | { 52 | ByteValue = byte.MaxValue, 53 | ShortValue = short.MaxValue, 54 | IntValue = int.MaxValue, 55 | LongValue = long.MaxValue, 56 | GuidValue = Guid.NewGuid(), 57 | DateTimeValue = DateTime.MaxValue, 58 | TimeSpanValue = TimeSpan.FromMilliseconds(10), 59 | SomeType = SomeTypes.Known 60 | }; 61 | 62 | a.SimpleDictionary.Add("key1", "some-value"); 63 | a.SimpleDictionary.Add("key2", "some-other-value"); 64 | 65 | a.CustomDictionary.Add(1,2); 66 | a.CustomDictionary.Add(3,4); 67 | 68 | a.ComplexDictionary.Add(new E { IntValue = 10 }, new C { FloatValue = 32.2f }); 69 | 70 | return a; 71 | } 72 | 73 | public static ComplexModel GenerateNulledModel() 74 | { 75 | var a = new ComplexModel(); 76 | a.TestValue = null; 77 | a.NonPersisted = 0; 78 | a.Stuff = null; 79 | a.NestedValue = null; 80 | a.NestedArray = new B[2]; 81 | a.NestedArray[0] = new B 82 | { 83 | IntValue = 0, 84 | StringValue = null, 85 | NestedArray = null 86 | }; 87 | a.NestedArray[1] = null; 88 | a.AllTypes = null; 89 | a.SimpleDictionary.Add("key1", null); 90 | a.ComplexDictionary = null; 91 | 92 | return a; 93 | } 94 | 95 | public static NullableTypesModel GenerateNulledNullableModel() 96 | { 97 | var model = new NullableTypesModel(); 98 | model.NullableFloat = null; 99 | model.NullableInt = null; 100 | return model; 101 | } 102 | 103 | public static NullableTypesModel GeneratePopulatedNullableModel() 104 | { 105 | var model = new NullableTypesModel(); 106 | model.NullableFloat = 10.0f; 107 | model.NullableInt = 22; 108 | return model; 109 | } 110 | 111 | public static DynamicTypesModel GeneratePopulatedDynamicTypesModel() 112 | { 113 | var model = new DynamicTypesModel(); 114 | model.DynamicNestedProperty = new E { IntValue = 10 }; 115 | model.DynamicPrimitiveProperty = 12; 116 | 117 | model.DynamicList = new List(); 118 | model.DynamicList.Add(new E { IntValue = 22 }); 119 | model.DynamicList.Add(new C { FloatValue = 25 }); 120 | model.DynamicList.Add(20); 121 | 122 | model.DynamicArray = new object[] 123 | { 124 | new E { IntValue = 12 }, 125 | new C { FloatValue = 54.2f } 126 | }; 127 | 128 | model.DynamicEnumerable = new object[] 129 | { 130 | new E { IntValue = 45 }, 131 | new C { FloatValue = 22.7f } 132 | }; 133 | 134 | model.DynamicDictionary = new Dictionary(); 135 | model.DynamicDictionary.Add("key1", 62); 136 | model.DynamicDictionary.Add(new E{IntValue = 99}, 54); 137 | model.DynamicDictionary.Add(1, new C {FloatValue = 51.0f}); 138 | return model; 139 | } 140 | 141 | public static NumericsTypesModel GenerateNumericsModel() 142 | { 143 | var model = new NumericsTypesModel(); 144 | model.NullableVector2Value = model.Vector2Value = Vector2.One; 145 | model.NullableVector3Value = model.Vector3Value = Vector3.One; 146 | model.NullableVector4Value = model.Vector4Value = Vector4.One; 147 | model.NullableQuaternionValue = model.QuaternionValue = new Quaternion(1.0f, 1.0f, 1.0f, 1.0f); 148 | return model; 149 | } 150 | 151 | public static DynamicTypesModel GenerateNulledDynamicTypesModel() 152 | { 153 | var model = new DynamicTypesModel(); 154 | model.DynamicNestedProperty = null; 155 | model.DynamicPrimitiveProperty = null; 156 | 157 | model.DynamicList = new List(); 158 | model.DynamicList.Add(new E() { IntValue = 22 }); 159 | model.DynamicList.Add(null); 160 | model.DynamicList.Add(20); 161 | 162 | model.DynamicDictionary = new Dictionary(); 163 | model.DynamicDictionary.Add("key1", null); 164 | model.DynamicDictionary.Add(new E { IntValue = 99 }, null); 165 | model.DynamicDictionary.Add(1, null); 166 | return model; 167 | } 168 | 169 | public static void AssertPopulatedData(ComplexModel expected, ComplexModel actual) 170 | { 171 | var expectedObject = JObject.FromObject(expected); 172 | expectedObject.Property("NonPersisted").Remove(); 173 | 174 | var actualObject = JObject.FromObject(actual); 175 | actualObject.Property("NonPersisted").Remove(); 176 | 177 | Assert.AreEqual(expectedObject, actualObject); 178 | } 179 | 180 | public static void AssertNulledData(ComplexModel expected, ComplexModel actual) 181 | { Assert.AreEqual(actual, expected); } 182 | 183 | public static void AssertPopulatedDynamicTypesData(DynamicTypesModel expected, DynamicTypesModel actual) 184 | { Assert.AreEqual(actual, expected); } 185 | 186 | public static void AsserNulledDynamicTypesData(DynamicTypesModel expected, DynamicTypesModel actual) 187 | { Assert.AreEqual(actual, expected); } 188 | 189 | public static void AssertNullableModelData(NullableTypesModel expected, NullableTypesModel actual) 190 | { Assert.AreEqual(actual, expected); } 191 | } 192 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/LazyData.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp2.0;net46 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {9ADF5C4D-B71B-46E8-8811-D855259C79BB} 17 | LazyData.SuperLazy 18 | 19 | 20 | 21 | {8AE4F137-FCFB-4B1C-B8E0-CE6CF98EE3D9} 22 | LazyData 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/B.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Attributes; 2 | 3 | namespace LazyData.Tests.Models 4 | { 5 | public class B 6 | { 7 | [PersistData] 8 | public string StringValue { get; set; } 9 | 10 | [PersistData] 11 | public int IntValue { get; set; } 12 | 13 | [PersistData] 14 | public C[] NestedArray { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/C.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Attributes; 2 | 3 | namespace LazyData.Tests.Models 4 | { 5 | [Persist] 6 | public class C 7 | { 8 | [PersistData] 9 | public float FloatValue { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/CommonTypesModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Attributes; 3 | 4 | namespace LazyData.Tests.Models 5 | { 6 | public class CommonTypesModel 7 | { 8 | [PersistData] public byte ByteValue { get; set; } 9 | [PersistData] public short ShortValue { get; set; } 10 | [PersistData] public int IntValue { get; set; } 11 | [PersistData] public long LongValue { get; set; } 12 | [PersistData] public Guid GuidValue { get; set; } 13 | [PersistData] public DateTime DateTimeValue { get; set; } 14 | [PersistData] public TimeSpan TimeSpanValue { get; set; } 15 | [PersistData] public SomeTypes SomeType { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/ComplexModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using LazyData.Attributes; 3 | 4 | namespace LazyData.Tests.Models 5 | { 6 | public class CustomDictionary : Dictionary{} 7 | public class CustomList : List{} 8 | 9 | [Persist] 10 | public class ComplexModel 11 | { 12 | [PersistData] 13 | public string TestValue { get; set; } 14 | 15 | public int NonPersisted { get; set; } 16 | 17 | [PersistData] 18 | public B NestedValue { get; set; } 19 | 20 | [PersistData] 21 | public B[] NestedArray { get; set; } 22 | 23 | [PersistData] 24 | public IList Stuff { get; set; } 25 | 26 | [PersistData] 27 | public CustomList CustomList { get; set; } 28 | 29 | [PersistData] 30 | public CommonTypesModel AllTypes { get; set; } 31 | 32 | [PersistData] 33 | public IDictionary SimpleDictionary { get; set; } 34 | 35 | [PersistData] 36 | public IDictionary ComplexDictionary { get; set; } 37 | 38 | [PersistData] 39 | public CustomDictionary CustomDictionary { get; set; } 40 | 41 | public ComplexModel() 42 | { 43 | Stuff = new List(); 44 | SimpleDictionary = new Dictionary(); 45 | ComplexDictionary = new Dictionary(); 46 | CustomDictionary = new CustomDictionary(); 47 | CustomList = new CustomList(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/CyclicModels.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData.Tests.Models 2 | { 3 | public class CyclicA 4 | { 5 | public CyclicB References { get; set; } 6 | } 7 | 8 | public class CyclicB 9 | { 10 | public CyclicA References { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/DynamicTypesModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using LazyData.Attributes; 3 | 4 | namespace LazyData.Tests.Models 5 | { 6 | [Persist] 7 | public class DynamicTypesModel 8 | { 9 | [PersistData] 10 | public object DynamicNestedProperty { get; set; } 11 | 12 | [PersistData] 13 | public object DynamicPrimitiveProperty { get; set; } 14 | 15 | [PersistData] 16 | public IList DynamicList { get; set; } 17 | 18 | [PersistData] 19 | public object[] DynamicArray { get; set; } 20 | 21 | [PersistData] 22 | public IEnumerable DynamicEnumerable { get; set; } 23 | 24 | [PersistData] 25 | public IDictionary DynamicDictionary { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/E.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Attributes; 2 | 3 | namespace LazyData.Tests.Models 4 | { 5 | [Persist] 6 | public class E 7 | { 8 | [PersistData] 9 | public int IntValue { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/NullableTypesModel.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Attributes; 2 | 3 | namespace LazyData.Tests.Models 4 | { 5 | [Persist] 6 | public class NullableTypesModel 7 | { 8 | [PersistData] 9 | public int? NullableInt { get; set; } 10 | 11 | [PersistData] 12 | public float? NullableFloat { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/NumericsTypesModel.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace LazyData.Tests.Models 4 | { 5 | public class NumericsTypesModel 6 | { 7 | public Vector2 Vector2Value { get; set; } 8 | public Vector3 Vector3Value { get; set; } 9 | public Vector4 Vector4Value { get; set; } 10 | public Quaternion QuaternionValue { get; set; } 11 | 12 | public Vector2? NullableVector2Value { get; set; } 13 | public Vector3? NullableVector3Value { get; set; } 14 | public Vector4? NullableVector4Value { get; set; } 15 | public Quaternion? NullableQuaternionValue { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Models/SomeTypes.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData.Tests.Models 2 | { 3 | public enum SomeTypes 4 | { 5 | Unknown = 0, 6 | Known = 1, 7 | Maybe = 2 8 | } 9 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/SanityTests/BsonSanityTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Bson; 3 | using LazyData.Mappings.Mappers; 4 | using LazyData.Mappings.Types; 5 | using LazyData.Registries; 6 | using LazyData.SuperLazy; 7 | using LazyData.Tests.Helpers; 8 | using LazyData.Tests.Models; 9 | using Xunit; 10 | using Xunit.Abstractions; 11 | using Assert = LazyData.Tests.Extensions.AssertExtensions; 12 | 13 | namespace LazyData.Tests.SanityTests 14 | { 15 | public class BsonSanityTests 16 | { 17 | private IMappingRegistry _mappingRegistry; 18 | private ITypeCreator _typeCreator; 19 | private ITestOutputHelper _testOutputHelper; 20 | 21 | public BsonSanityTests(ITestOutputHelper testOutputHelper) 22 | { 23 | _testOutputHelper = testOutputHelper; 24 | _typeCreator = new TypeCreator(); 25 | 26 | var analyzer = new TypeAnalyzer(); 27 | var mapper = new EverythingTypeMapper(analyzer); 28 | _mappingRegistry = new MappingRegistry(mapper); 29 | } 30 | 31 | [Fact] 32 | public void check_it_converts_sensibly() 33 | { 34 | var serializer = new BsonSerializer(_mappingRegistry); 35 | var deserializer = new BsonDeserializer(_mappingRegistry, _typeCreator); 36 | var expectedModel = SerializationTestHelper.GeneratePopulatedModel(); 37 | 38 | var data = serializer.Serialize(expectedModel); 39 | _testOutputHelper.WriteLine("Outputted Bson: "); 40 | _testOutputHelper.WriteLine(BitConverter.ToString(data.AsBytes)); 41 | 42 | var actualModel = deserializer.Deserialize(data); 43 | SerializationTestHelper.AssertPopulatedData(expectedModel, actualModel); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/SanityTests/GeneralTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using LazyData.Bson; 4 | using LazyData.Json; 5 | using LazyData.Mappings.Mappers; 6 | using LazyData.Mappings.Types; 7 | using LazyData.Registries; 8 | using LazyData.SuperLazy; 9 | using LazyData.Tests.Helpers; 10 | using LazyData.Tests.Models; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | using Assert = LazyData.Tests.Extensions.AssertExtensions; 14 | 15 | namespace LazyData.Tests.SanityTests 16 | { 17 | public class ContainsDictionary 18 | { 19 | public string Something { get; set; } 20 | public CustomDictionary Proxy { get; set; } = new CustomDictionary(); 21 | } 22 | 23 | public class GeneralTests 24 | { 25 | private IMappingRegistry _mappingRegistry; 26 | private ITypeCreator _typeCreator; 27 | private ITestOutputHelper _testOutputHelper; 28 | 29 | public GeneralTests(ITestOutputHelper testOutputHelper) 30 | { 31 | _testOutputHelper = testOutputHelper; 32 | _typeCreator = new TypeCreator(); 33 | 34 | var analyzer = new TypeAnalyzer(); 35 | var mapper = new EverythingTypeMapper(analyzer); 36 | _mappingRegistry = new MappingRegistry(mapper); 37 | } 38 | 39 | [Fact] 40 | public void check_json_can_convert_object_with_dictionary() 41 | { 42 | var serializer = new JsonSerializer(_mappingRegistry); 43 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 44 | 45 | var obj = new ContainsDictionary {Something = "blah"}; 46 | obj.Proxy.Add(1, 2); 47 | obj.Proxy.Add(3, 4); 48 | 49 | var data = serializer.Serialize(obj); 50 | _testOutputHelper.WriteLine("Outputted Json: "); 51 | _testOutputHelper.WriteLine(data.AsString); 52 | 53 | var actualModel = deserializer.Deserialize(data); 54 | Assert.NotNull(actualModel); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/SanityTests/ModelInterchangableTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using LazyData.Bson; 4 | using LazyData.Json; 5 | using LazyData.Mappings.Mappers; 6 | using LazyData.Mappings.Types; 7 | using LazyData.Registries; 8 | using LazyData.Tests.Helpers; 9 | using LazyData.Tests.Models; 10 | using Xunit; 11 | using Xunit.Abstractions; 12 | 13 | namespace LazyData.Tests.SanityTests 14 | { 15 | public class ModelA 16 | { 17 | public int Id { get; set; } 18 | public IEnumerable Data { get; set; } 19 | } 20 | 21 | public class ModelB 22 | { 23 | public int Id { get; set; } 24 | public List Data { get; set; } 25 | } 26 | 27 | public class ModelInterchangableTests 28 | { 29 | private IMappingRegistry _mappingRegistry; 30 | private ITypeCreator _typeCreator; 31 | private ITestOutputHelper _testOutputHelper; 32 | 33 | public ModelInterchangableTests(ITestOutputHelper testOutputHelper) 34 | { 35 | _testOutputHelper = testOutputHelper; 36 | _typeCreator = new TypeCreator(); 37 | 38 | var analyzer = new TypeAnalyzer(); 39 | var mapper = new EverythingTypeMapper(analyzer); 40 | _mappingRegistry = new MappingRegistry(mapper); 41 | } 42 | 43 | [Fact] 44 | public void check_it_can_convert_from_a_to_b_to_a() 45 | { 46 | var serializer = new JsonSerializer(_mappingRegistry); 47 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 48 | 49 | var child1 = new C {FloatValue = 22}; 50 | var child2 = new C {FloatValue = 30}; 51 | var child3 = new C {FloatValue = 1}; 52 | 53 | var startingModel = new ModelA 54 | { 55 | Id = 1, 56 | Data = new[] { child1, child2 } 57 | }; 58 | 59 | var data = serializer.Serialize(startingModel); 60 | _testOutputHelper.WriteLine("Starting JSON: "); 61 | _testOutputHelper.WriteLine(data.AsString); 62 | 63 | var interimModel = deserializer.Deserialize(data); 64 | interimModel.Data.Add(child3); 65 | 66 | var interimData = serializer.Serialize(interimModel); 67 | _testOutputHelper.WriteLine("Interim JSON: "); 68 | _testOutputHelper.WriteLine(interimData.AsString); 69 | 70 | var actualModel = deserializer.Deserialize(interimData); 71 | 72 | Assert.Equal(startingModel.Id, actualModel.Id); 73 | Assert.NotNull(actualModel.Data); 74 | Assert.Contains(actualModel.Data, x => x.FloatValue == child1.FloatValue); 75 | Assert.Contains(actualModel.Data, x => x.FloatValue == child2.FloatValue); 76 | Assert.Contains(actualModel.Data, x => x.FloatValue == child3.FloatValue); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/SanityTests/SuperLazyTransformerTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.SuperLazy; 3 | using LazyData.Tests.Helpers; 4 | using LazyData.Tests.Models; 5 | using Xunit; 6 | using Xunit.Abstractions; 7 | using Assert = LazyData.Tests.Extensions.AssertExtensions; 8 | 9 | namespace LazyData.Tests.SanityTests 10 | { 11 | public class SuperLazyTransformerTests 12 | { 13 | private readonly ITestOutputHelper testOutputHelper; 14 | 15 | public SuperLazyTransformerTests(ITestOutputHelper testOutputHelper) 16 | { 17 | this.testOutputHelper = testOutputHelper; 18 | } 19 | 20 | [Fact] 21 | public void check_it_converts_sensibly() 22 | { 23 | var model = SerializationTestHelper.GeneratePopulatedModel(); 24 | var expectdString = Transformer.ToJson(model); 25 | 26 | testOutputHelper.WriteLine("Outputted Json: "); 27 | testOutputHelper.WriteLine(expectdString); 28 | var xml = Transformer.FromJsonToXml(expectdString); 29 | 30 | testOutputHelper.WriteLine("Converted Xml: "); 31 | testOutputHelper.WriteLine(xml); 32 | var binary = Transformer.FromXmlToBinary(xml); 33 | 34 | testOutputHelper.WriteLine("Converted Binary: "); 35 | testOutputHelper.WriteLine(BitConverter.ToString(binary)); 36 | var json = Transformer.FromBinaryToJson(binary); 37 | 38 | testOutputHelper.WriteLine("Outputted Json: "); 39 | testOutputHelper.WriteLine(json); 40 | Assert.AreEqual(expectdString, json); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/SanityTests/YamlSanityTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Mappings.Mappers; 3 | using LazyData.Mappings.Types; 4 | using LazyData.Registries; 5 | using LazyData.SuperLazy; 6 | using LazyData.Tests.Helpers; 7 | using LazyData.Tests.Models; 8 | using LazyData.Yaml; 9 | using Xunit; 10 | using Xunit.Abstractions; 11 | using Assert = LazyData.Tests.Extensions.AssertExtensions; 12 | 13 | namespace LazyData.Tests.SanityTests 14 | { 15 | public class YamlSanityTests 16 | { 17 | private IMappingRegistry _mappingRegistry; 18 | private ITypeCreator _typeCreator; 19 | private ITestOutputHelper _testOutputHelper; 20 | 21 | public YamlSanityTests(ITestOutputHelper testOutputHelper) 22 | { 23 | _testOutputHelper = testOutputHelper; 24 | _typeCreator = new TypeCreator(); 25 | 26 | var analyzer = new TypeAnalyzer(); 27 | var mapper = new EverythingTypeMapper(analyzer); 28 | _mappingRegistry = new MappingRegistry(mapper); 29 | } 30 | 31 | [Fact] 32 | public void check_it_converts_sensibly() 33 | { 34 | var serializer = new YamlSerializer(_mappingRegistry); 35 | var deserializer = new YamlDeserializer(_mappingRegistry, _typeCreator); 36 | var expectedModel = SerializationTestHelper.GeneratePopulatedModel(); 37 | 38 | var data = serializer.Serialize(expectedModel); 39 | _testOutputHelper.WriteLine("Outputted Yaml: "); 40 | _testOutputHelper.WriteLine(data.AsString); 41 | 42 | var actualModel = deserializer.Deserialize(data); 43 | SerializationTestHelper.AssertPopulatedData(expectedModel, actualModel); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Serialization/CyclicSerializationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Json; 3 | using LazyData.Mappings.Mappers; 4 | using LazyData.Mappings.Types; 5 | using LazyData.Registries; 6 | using LazyData.Tests.Models; 7 | using Xunit; 8 | using Xunit.Abstractions; 9 | 10 | namespace LazyData.Tests.Serialization 11 | { 12 | public class CyclicSerializationTests 13 | { 14 | private IMappingRegistry _mappingRegistry; 15 | private ITypeCreator _typeCreator; 16 | private ITestOutputHelper _testOutputHelper; 17 | 18 | public CyclicSerializationTests(ITestOutputHelper testOutputHelper) 19 | { 20 | _testOutputHelper = testOutputHelper; 21 | 22 | _typeCreator = new TypeCreator(); 23 | 24 | var analyzer = new TypeAnalyzer(); 25 | var mapper = new EverythingTypeMapper(analyzer); 26 | _mappingRegistry = new MappingRegistry(mapper); 27 | } 28 | 29 | //[Fact] 30 | public void should_throw_exception_with_cyclic_dependency() 31 | { 32 | var a = new CyclicA(); 33 | var b = new CyclicB(); 34 | 35 | a.References = b; 36 | b.References = a; 37 | 38 | var serializer = new JsonSerializer(_mappingRegistry); 39 | 40 | Assert.Throws(() => 41 | { 42 | var output = serializer.Serialize(a); 43 | _testOutputHelper.WriteLine(output.AsString); 44 | }); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Serialization/NullableModelSerializationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Binary; 3 | using LazyData.Json; 4 | using LazyData.Mappings.Mappers; 5 | using LazyData.Mappings.Types; 6 | using LazyData.Registries; 7 | using LazyData.Serialization.Debug; 8 | using LazyData.Tests.Helpers; 9 | using LazyData.Tests.Models; 10 | using LazyData.Xml; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | namespace LazyData.Tests.Serialization 15 | { 16 | public class NullableModelSerializationTests 17 | { 18 | private IMappingRegistry _mappingRegistry; 19 | private ITypeCreator _typeCreator; 20 | private ITestOutputHelper _outputHelper; 21 | 22 | public NullableModelSerializationTests(ITestOutputHelper outputHelper) 23 | { 24 | _outputHelper = outputHelper; 25 | _typeCreator = new TypeCreator(); 26 | 27 | var analyzer = new TypeAnalyzer(); 28 | var mapper = new DefaultTypeMapper(analyzer); 29 | _mappingRegistry = new MappingRegistry(mapper); 30 | } 31 | 32 | [Fact] 33 | public void should_serialize_populated_nullable_data_with_debug_serializer() 34 | { 35 | var model = SerializationTestHelper.GeneratePopulatedNullableModel(); 36 | var serializer = new DebugSerializer(_mappingRegistry); 37 | 38 | var output = serializer.Serialize(model); 39 | _outputHelper.WriteLine(output.AsString); 40 | } 41 | 42 | [Fact] 43 | public void should_correctly_serialize_populated_nullable_data_with_json() 44 | { 45 | var model = SerializationTestHelper.GeneratePopulatedNullableModel(); 46 | var serializer = new JsonSerializer(_mappingRegistry); 47 | 48 | var output = serializer.Serialize(model); 49 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 50 | _outputHelper.WriteLine(output.AsString); 51 | 52 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 53 | var result = deserializer.Deserialize(output); 54 | 55 | SerializationTestHelper.AssertNullableModelData(model, result); 56 | } 57 | 58 | [Fact] 59 | public void should_correctly_serialize_populated_nullable_data_into_existing_object_with_json() 60 | { 61 | var model = SerializationTestHelper.GeneratePopulatedNullableModel(); 62 | var serializer = new JsonSerializer(_mappingRegistry); 63 | 64 | var output = serializer.Serialize(model); 65 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 66 | _outputHelper.WriteLine(output.AsString); 67 | 68 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 69 | var result = new NullableTypesModel(); 70 | deserializer.DeserializeInto(output, result); 71 | 72 | SerializationTestHelper.AssertNullableModelData(model, result); 73 | } 74 | 75 | [Fact] 76 | public void should_correctly_serialize_populated_nullable_data_with_binary() 77 | { 78 | var model = SerializationTestHelper.GeneratePopulatedNullableModel(); 79 | 80 | var serializer = new BinarySerializer(_mappingRegistry); 81 | var output = serializer.Serialize(model); 82 | _outputHelper.WriteLine("FileSize: " + output.AsBytes.Length + " bytes"); 83 | _outputHelper.WriteLine(BitConverter.ToString(output.AsBytes)); 84 | 85 | var deserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator); 86 | var result = deserializer.Deserialize(output); 87 | 88 | SerializationTestHelper.AssertNullableModelData(model, result); 89 | } 90 | 91 | [Fact] 92 | public void should_correctly_serialize_populated_nullable_data_into_existing_object_with_binary() 93 | { 94 | var model = SerializationTestHelper.GeneratePopulatedNullableModel(); 95 | 96 | var serializer = new BinarySerializer(_mappingRegistry); 97 | var output = serializer.Serialize(model); 98 | _outputHelper.WriteLine("FileSize: " + output.AsBytes.Length + " bytes"); 99 | _outputHelper.WriteLine(BitConverter.ToString(output.AsBytes)); 100 | 101 | var deserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator); 102 | var result = new NullableTypesModel(); 103 | deserializer.DeserializeInto(output, result); 104 | 105 | SerializationTestHelper.AssertNullableModelData(model, result); 106 | } 107 | 108 | [Fact] 109 | public void should_correctly_serialize_populated_nullable_data_with_xml() 110 | { 111 | var model = SerializationTestHelper.GeneratePopulatedNullableModel(); 112 | 113 | var serializer = new XmlSerializer(_mappingRegistry); 114 | var output = serializer.Serialize(model); 115 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 116 | _outputHelper.WriteLine(output.AsString); 117 | 118 | var deserializer = new XmlDeserializer(_mappingRegistry, _typeCreator); 119 | var result = deserializer.Deserialize(output); 120 | 121 | SerializationTestHelper.AssertNullableModelData(model, result); 122 | } 123 | 124 | [Fact] 125 | public void should_correctly_serialize_populated_nullable_data_into_existing_object_with_xml() 126 | { 127 | var model = SerializationTestHelper.GeneratePopulatedNullableModel(); 128 | 129 | var serializer = new XmlSerializer(_mappingRegistry); 130 | var output = serializer.Serialize(model); 131 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 132 | _outputHelper.WriteLine(output.AsString); 133 | 134 | var deserializer = new XmlDeserializer(_mappingRegistry, _typeCreator); 135 | var result = new NullableTypesModel(); 136 | deserializer.DeserializeInto(output, result); 137 | 138 | SerializationTestHelper.AssertNullableModelData(model, result); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Serialization/NulledModelSerializationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Binary; 3 | using LazyData.Json; 4 | using LazyData.Mappings.Mappers; 5 | using LazyData.Mappings.Types; 6 | using LazyData.Registries; 7 | using LazyData.Serialization.Debug; 8 | using LazyData.Tests.Helpers; 9 | using LazyData.Tests.Models; 10 | using LazyData.Xml; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | namespace LazyData.Tests.Serialization 15 | { 16 | public class NulledModelSerializationTests 17 | { 18 | private IMappingRegistry _mappingRegistry; 19 | private ITypeCreator _typeCreator; 20 | private ITestOutputHelper _outputHelper; 21 | 22 | public NulledModelSerializationTests(ITestOutputHelper outputHelper) 23 | { 24 | _outputHelper = outputHelper; 25 | _typeCreator = new TypeCreator(); 26 | 27 | var analyzer = new TypeAnalyzer(); 28 | var mapper = new DefaultTypeMapper(analyzer); 29 | _mappingRegistry = new MappingRegistry(mapper); 30 | } 31 | 32 | [Fact] 33 | public void should_serialize_nulled_data_with_debug_serializer() 34 | { 35 | var model = SerializationTestHelper.GenerateNulledModel(); 36 | var serializer = new DebugSerializer(_mappingRegistry); 37 | 38 | var output = serializer.Serialize(model); 39 | _outputHelper.WriteLine(output.AsString); 40 | } 41 | 42 | [Fact] 43 | public void should_correctly_serialize_nulled_data_with_json() 44 | { 45 | var model = SerializationTestHelper.GenerateNulledModel(); 46 | var serializer = new JsonSerializer(_mappingRegistry); 47 | 48 | var output = serializer.Serialize(model); 49 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 50 | _outputHelper.WriteLine(output.AsString); 51 | 52 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 53 | var result = deserializer.Deserialize(output); 54 | 55 | SerializationTestHelper.AssertNulledData(model, result); 56 | } 57 | 58 | [Fact] 59 | public void should_correctly_serialize_nulled_data_into_existing_object_with_json() 60 | { 61 | var model = SerializationTestHelper.GenerateNulledModel(); 62 | var serializer = new JsonSerializer(_mappingRegistry); 63 | 64 | var output = serializer.Serialize(model); 65 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 66 | _outputHelper.WriteLine(output.AsString); 67 | 68 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 69 | var result = new ComplexModel(); 70 | deserializer.DeserializeInto(output, result); 71 | 72 | SerializationTestHelper.AssertNulledData(model, result); 73 | } 74 | 75 | [Fact] 76 | public void should_correctly_serialize_nulled_data_with_binary() 77 | { 78 | var model = SerializationTestHelper.GenerateNulledModel(); 79 | 80 | var serializer = new BinarySerializer(_mappingRegistry); 81 | var output = serializer.Serialize(model); 82 | _outputHelper.WriteLine("FileSize: " + output.AsBytes.Length + " bytes"); 83 | _outputHelper.WriteLine(BitConverter.ToString(output.AsBytes)); 84 | 85 | var deserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator); 86 | var result = deserializer.Deserialize(output); 87 | 88 | SerializationTestHelper.AssertNulledData(model, result); 89 | } 90 | 91 | [Fact] 92 | public void should_correctly_serialize_nulled_data_into_existing_object_with_binary() 93 | { 94 | var model = SerializationTestHelper.GenerateNulledModel(); 95 | 96 | var serializer = new BinarySerializer(_mappingRegistry); 97 | var output = serializer.Serialize(model); 98 | _outputHelper.WriteLine("FileSize: " + output.AsBytes.Length + " bytes"); 99 | _outputHelper.WriteLine(BitConverter.ToString(output.AsBytes)); 100 | 101 | var deserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator); 102 | var result = new ComplexModel(); 103 | deserializer.DeserializeInto(output, result); 104 | 105 | SerializationTestHelper.AssertNulledData(model, result); 106 | } 107 | 108 | [Fact] 109 | public void should_correctly_serialize_nulled_data_with_xml() 110 | { 111 | var model = SerializationTestHelper.GenerateNulledModel(); 112 | 113 | var serializer = new XmlSerializer(_mappingRegistry); 114 | var output = serializer.Serialize(model); 115 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 116 | _outputHelper.WriteLine(output.AsString); 117 | 118 | var deserializer = new XmlDeserializer(_mappingRegistry, _typeCreator); 119 | var result = deserializer.Deserialize(output); 120 | 121 | SerializationTestHelper.AssertNulledData(model, result); 122 | } 123 | 124 | [Fact] 125 | public void should_correctly_serialize_nulled_data_into_existing_object_with_xml() 126 | { 127 | var model = SerializationTestHelper.GenerateNulledModel(); 128 | 129 | var serializer = new XmlSerializer(_mappingRegistry); 130 | var output = serializer.Serialize(model); 131 | _outputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 132 | _outputHelper.WriteLine(output.AsString); 133 | 134 | var deserializer = new XmlDeserializer(_mappingRegistry, _typeCreator); 135 | var result = new ComplexModel(); 136 | deserializer.DeserializeInto(output, result); 137 | 138 | SerializationTestHelper.AssertNulledData(model, result); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Serialization/NumericsModelSerializationTests.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Binary; 2 | using LazyData.Json; 3 | using LazyData.Mappings.Mappers; 4 | using LazyData.Mappings.Types; 5 | using LazyData.Mappings.Types.Primitives; 6 | using LazyData.Mappings.Types.Primitives.Checkers; 7 | using LazyData.Numerics.Checkers; 8 | using LazyData.Numerics.Handlers; 9 | using LazyData.Registries; 10 | using LazyData.Tests.Helpers; 11 | using LazyData.Tests.Models; 12 | using LazyData.Xml; 13 | using Xunit; 14 | using Xunit.Abstractions; 15 | using Assert = LazyData.Tests.Extensions.AssertExtensions; 16 | 17 | namespace LazyData.Tests.Serialization 18 | { 19 | public class NumericsModelSerializationTests 20 | { 21 | private IMappingRegistry _mappingRegistry; 22 | private ITypeCreator _typeCreator; 23 | private ITestOutputHelper _outputHelper; 24 | 25 | public NumericsModelSerializationTests(ITestOutputHelper outputHelper) 26 | { 27 | _outputHelper = outputHelper; 28 | _typeCreator = new TypeCreator(); 29 | 30 | var primitiveRegistry = new PrimitiveRegistry(); 31 | primitiveRegistry.AddPrimitiveCheck(new BasicPrimitiveChecker()); 32 | primitiveRegistry.AddPrimitiveCheck(new NumericsPrimitiveChecker()); 33 | var analyzer = new TypeAnalyzer(primitiveRegistry); 34 | 35 | var mapper = new EverythingTypeMapper(analyzer); 36 | _mappingRegistry = new MappingRegistry(mapper); 37 | } 38 | 39 | [Fact] 40 | public void should_handle_numerics_data_as_binary_with_primitive_handler() 41 | { 42 | var expected = SerializationTestHelper.GenerateNumericsModel(); 43 | var serializer = new BinarySerializer(_mappingRegistry, new []{ new NumericsBinaryPrimitiveHandler() }); 44 | var deserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator, new []{ new NumericsBinaryPrimitiveHandler() }); 45 | 46 | var output = serializer.Serialize(expected); 47 | _outputHelper.WriteLine(output.AsString); 48 | 49 | var actual = deserializer.Deserialize(output); 50 | 51 | Assert.AreEqual(expected, actual); 52 | } 53 | 54 | [Fact] 55 | public void should_handle_numerics_data_as_json_with_primitive_handler() 56 | { 57 | var expected = SerializationTestHelper.GenerateNumericsModel(); 58 | var serializer = new JsonSerializer(_mappingRegistry, new[] { new NumericsJsonPrimitiveHandler() }); 59 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator, new[] { new NumericsJsonPrimitiveHandler() }); 60 | 61 | var output = serializer.Serialize(expected); 62 | _outputHelper.WriteLine(output.AsString); 63 | 64 | var actual = deserializer.Deserialize(output); 65 | 66 | Assert.AreEqual(expected, actual); 67 | } 68 | 69 | [Fact] 70 | public void should_handle_numerics_data_as_xml_with_primitive_handler() 71 | { 72 | var expected = SerializationTestHelper.GenerateNumericsModel(); 73 | var serializer = new XmlSerializer(_mappingRegistry, new[] { new NumericsXmlPrimitiveHandler() }); 74 | var deserializer = new XmlDeserializer(_mappingRegistry, _typeCreator, new[] { new NumericsXmlPrimitiveHandler() }); 75 | 76 | var output = serializer.Serialize(expected); 77 | _outputHelper.WriteLine(output.AsString); 78 | 79 | var actual = deserializer.Deserialize(output); 80 | 81 | Assert.AreEqual(expected, actual); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/Serialization/PopulatedModelSerializationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Binary; 3 | using LazyData.Json; 4 | using LazyData.Mappings.Mappers; 5 | using LazyData.Mappings.Types; 6 | using LazyData.Registries; 7 | using LazyData.Serialization.Debug; 8 | using LazyData.Tests.Helpers; 9 | using LazyData.Tests.Models; 10 | using LazyData.Xml; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | namespace LazyData.Tests.Serialization 15 | { 16 | public class PopulatedModelSerializationTests 17 | { 18 | private IMappingRegistry _mappingRegistry; 19 | private ITypeCreator _typeCreator; 20 | 21 | private ITestOutputHelper testOutputHelper; 22 | 23 | public PopulatedModelSerializationTests(ITestOutputHelper testOutputHelper) 24 | { 25 | this.testOutputHelper = testOutputHelper; 26 | _typeCreator = new TypeCreator(); 27 | 28 | var analyzer = new TypeAnalyzer(); 29 | var mapper = new DefaultTypeMapper(analyzer); 30 | _mappingRegistry = new MappingRegistry(mapper); 31 | } 32 | 33 | [Fact] 34 | public void should_serialize_populated_data_with_debug_serializer() 35 | { 36 | var model = SerializationTestHelper.GeneratePopulatedModel(); 37 | var serializer = new DebugSerializer(_mappingRegistry); 38 | 39 | var output = serializer.Serialize(model); 40 | testOutputHelper.WriteLine(output.AsString); 41 | } 42 | 43 | [Fact] 44 | public void should_correctly_serialize_populated_data_with_json() 45 | { 46 | var model = SerializationTestHelper.GeneratePopulatedModel(); 47 | var serializer = new JsonSerializer(_mappingRegistry); 48 | 49 | var output = serializer.Serialize(model); 50 | testOutputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 51 | testOutputHelper.WriteLine(output.AsString); 52 | 53 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 54 | var result = deserializer.Deserialize(output); 55 | 56 | SerializationTestHelper.AssertPopulatedData(model, result); 57 | } 58 | 59 | [Fact] 60 | public void should_correctly_serialize_populated_data_into_existing_object_with_json() 61 | { 62 | var model = SerializationTestHelper.GeneratePopulatedModel(); 63 | var serializer = new JsonSerializer(_mappingRegistry); 64 | 65 | var output = serializer.Serialize(model); 66 | testOutputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 67 | testOutputHelper.WriteLine(output.AsString); 68 | 69 | var deserializer = new JsonDeserializer(_mappingRegistry, _typeCreator); 70 | var result = new ComplexModel(); 71 | deserializer.DeserializeInto(output, result); 72 | 73 | SerializationTestHelper.AssertPopulatedData(model, result); 74 | } 75 | 76 | [Fact] 77 | public void should_correctly_serialize_populated_data_with_binary() 78 | { 79 | var model = SerializationTestHelper.GeneratePopulatedModel(); 80 | 81 | var serializer = new BinarySerializer(_mappingRegistry); 82 | var output = serializer.Serialize(model); 83 | testOutputHelper.WriteLine("FileSize: " + output.AsBytes.Length + " bytes"); 84 | testOutputHelper.WriteLine(BitConverter.ToString(output.AsBytes)); 85 | 86 | var deserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator); 87 | var result = deserializer.Deserialize(output); 88 | 89 | SerializationTestHelper.AssertPopulatedData(model, result); 90 | } 91 | 92 | [Fact] 93 | public void should_correctly_serialize_populated_data_into_existing_object_with_binary() 94 | { 95 | var model = SerializationTestHelper.GeneratePopulatedModel(); 96 | 97 | var serializer = new BinarySerializer(_mappingRegistry); 98 | var output = serializer.Serialize(model); 99 | testOutputHelper.WriteLine("FileSize: " + output.AsBytes.Length + " bytes"); 100 | testOutputHelper.WriteLine(BitConverter.ToString(output.AsBytes)); 101 | 102 | var deserializer = new BinaryDeserializer(_mappingRegistry, _typeCreator); 103 | var result = new ComplexModel(); 104 | deserializer.DeserializeInto(output, result); 105 | 106 | SerializationTestHelper.AssertPopulatedData(model, result); 107 | } 108 | 109 | [Fact] 110 | public void should_correctly_serialize_populated_data_with_xml() 111 | { 112 | var model = SerializationTestHelper.GeneratePopulatedModel(); 113 | 114 | var serializer = new XmlSerializer(_mappingRegistry); 115 | var output = serializer.Serialize(model); 116 | testOutputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 117 | testOutputHelper.WriteLine(output.AsString); 118 | 119 | var deserializer = new XmlDeserializer(_mappingRegistry, _typeCreator); 120 | var result = deserializer.Deserialize(output); 121 | 122 | SerializationTestHelper.AssertPopulatedData(model, result); 123 | } 124 | 125 | [Fact] 126 | public void should_correctly_serialize_populated_data_into_existing_object_with_xml() 127 | { 128 | var model = SerializationTestHelper.GeneratePopulatedModel(); 129 | 130 | var serializer = new XmlSerializer(_mappingRegistry); 131 | var output = serializer.Serialize(model); 132 | testOutputHelper.WriteLine("FileSize: " + output.AsString.Length + " bytes"); 133 | testOutputHelper.WriteLine(output.AsString); 134 | 135 | var deserializer = new XmlDeserializer(_mappingRegistry, _typeCreator); 136 | var result = new ComplexModel(); 137 | deserializer.DeserializeInto(output, result); 138 | 139 | SerializationTestHelper.AssertPopulatedData(model, result); 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/TypeMapper/DefaultTypeMapperTests.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Extensions; 2 | using LazyData.Mappings.Mappers; 3 | using LazyData.Mappings.Types; 4 | using LazyData.Tests.Helpers; 5 | using LazyData.Tests.Models; 6 | using Xunit; 7 | 8 | namespace LazyData.Tests.TypeMapper 9 | { 10 | public class DefaultTypeMapperTests 11 | { 12 | [Fact] 13 | public void should_correctly_map_complex_type() 14 | { 15 | var type = typeof(ComplexModel); 16 | var typeAnalyzer = new TypeAnalyzer(); 17 | var typeMapper = new DefaultTypeMapper(typeAnalyzer); 18 | var typeMapping = typeMapper.GetTypeMappingsFor(type); 19 | 20 | Assert.NotNull(typeMapping); 21 | Assert.Equal(type, typeMapping.Type); 22 | Assert.Equal(type.GetPersistableName(), typeMapping.Name); 23 | 24 | TypeAssertionHelper.AssertComplexModel(typeMapping.InternalMappings); 25 | } 26 | 27 | [Fact] 28 | public void should_correctly_map_dynamic_type() 29 | { 30 | var type = typeof(DynamicTypesModel); 31 | var typeAnalyzer = new TypeAnalyzer(); 32 | var typeMapper = new DefaultTypeMapper(typeAnalyzer); 33 | var typeMapping = typeMapper.GetTypeMappingsFor(type); 34 | 35 | Assert.NotNull(typeMapping); 36 | Assert.Equal(type, typeMapping.Type); 37 | Assert.Equal(type.GetPersistableName(), typeMapping.Name); 38 | 39 | TypeAssertionHelper.AssertDynamicModel(typeMapping.InternalMappings); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/LazyData.Tests/TypeMapper/TypeAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using LazyData.Mappings.Types; 5 | using LazyData.Tests.Models; 6 | using Xunit; 7 | 8 | namespace LazyData.Tests.TypeMapper 9 | { 10 | public class TypeAnalyzerTests 11 | { 12 | [Theory] 13 | [InlineData(typeof(int), false)] 14 | [InlineData(typeof(IList<>), true)] 15 | [InlineData(typeof(ICollection<>), true)] 16 | [InlineData(typeof(IEnumerable<>), true)] 17 | [InlineData(typeof(IDictionary<,>), true)] 18 | [InlineData(typeof(IEnumerable), false)] 19 | [InlineData(typeof(List<>), true)] 20 | [InlineData(typeof(CustomList), false)] 21 | public void should_correctly_identify_generic_collection(Type collectionType, bool shouldMatch) 22 | { 23 | var typeAnalyzer = new TypeAnalyzer(); 24 | var isGenericCollection = typeAnalyzer.IsGenericCollection(collectionType); 25 | 26 | Assert.Equal(isGenericCollection, shouldMatch); 27 | } 28 | 29 | [Theory] 30 | [InlineData(typeof(int), false)] 31 | [InlineData(typeof(IList<>), true)] 32 | [InlineData(typeof(ICollection<>), true)] 33 | [InlineData(typeof(IEnumerable<>), false)] 34 | [InlineData(typeof(IDictionary<,>), true)] 35 | [InlineData(typeof(IEnumerable), false)] 36 | [InlineData(typeof(List<>), true)] 37 | [InlineData(typeof(CustomList), true)] 38 | public void should_correctly_identify_implemented_generic_collection(Type collectionType, bool shouldMatch) 39 | { 40 | var typeAnalyzer = new TypeAnalyzer(); 41 | var isGenericCollection = typeAnalyzer.HasImplementedGenericCollection(collectionType); 42 | 43 | Assert.Equal(isGenericCollection, shouldMatch); 44 | } 45 | 46 | [Theory] 47 | [InlineData(typeof(int), false)] 48 | [InlineData(typeof(IList<>), false)] 49 | [InlineData(typeof(ICollection<>), false)] 50 | [InlineData(typeof(IEnumerable<>), false)] 51 | [InlineData(typeof(IEnumerable), false)] 52 | [InlineData(typeof(IDictionary<,>), true)] 53 | [InlineData(typeof(Dictionary<,>), true)] 54 | [InlineData(typeof(CustomDictionary), false)] 55 | public void should_correctly_identify_generic_dictionary(Type collectionType, bool shouldMatch) 56 | { 57 | var typeAnalyzer = new TypeAnalyzer(); 58 | var isGenericCollection = typeAnalyzer.IsGenericDictionary(collectionType); 59 | 60 | Assert.Equal(isGenericCollection, shouldMatch); 61 | } 62 | 63 | [Theory] 64 | [InlineData(typeof(int), false)] 65 | [InlineData(typeof(IList<>), false)] 66 | [InlineData(typeof(ICollection<>), false)] 67 | [InlineData(typeof(IEnumerable<>), false)] 68 | [InlineData(typeof(IEnumerable), false)] 69 | [InlineData(typeof(IDictionary<,>), false)] 70 | [InlineData(typeof(Dictionary<,>), true)] 71 | [InlineData(typeof(CustomDictionary), true)] 72 | public void should_correctly_identify_implemented_generic_dictionary(Type collectionType, bool shouldMatch) 73 | { 74 | var typeAnalyzer = new TypeAnalyzer(); 75 | var isGenericCollection = typeAnalyzer.HasImplementedGenericDictionary(collectionType); 76 | 77 | Assert.Equal(isGenericCollection, shouldMatch); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/LazyData.Xml/Handlers/BasicXmlPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Linq; 3 | using LazyData.Extensions; 4 | using LazyData.Mappings.Types.Primitives.Checkers; 5 | 6 | namespace LazyData.Xml.Handlers 7 | { 8 | public class BasicXmlPrimitiveHandler : IXmlPrimitiveHandler 9 | { 10 | private readonly Type[] StringCompatibleTypes = 11 | { 12 | typeof(string), typeof(bool), typeof(byte), typeof(short), typeof(int), 13 | typeof(long), typeof(Guid), typeof(float), typeof(double), typeof(decimal) 14 | }; 15 | 16 | public IPrimitiveChecker PrimitiveChecker { get; } = new BasicPrimitiveChecker(); 17 | 18 | public void Serialize(XElement state, object data, Type type) 19 | { 20 | if (type == typeof(DateTime)) 21 | { 22 | var typedValue = (DateTime)data; 23 | var stringValue = typedValue.ToBinary().ToString(); 24 | state.Value = stringValue; 25 | return; 26 | } 27 | 28 | if (type == typeof(TimeSpan)) 29 | { 30 | var typedValue = (TimeSpan)data; 31 | var stringValue = typedValue.TotalMilliseconds.ToString(); 32 | state.Value = stringValue; 33 | return; 34 | } 35 | 36 | if (type.IsTypeOf(StringCompatibleTypes) || type.IsEnum) 37 | { 38 | state.Value = data.ToString(); 39 | return; 40 | } 41 | } 42 | 43 | public object Deserialize(XElement state, Type type) 44 | { 45 | if (type == typeof(byte)) { return byte.Parse(state.Value); } 46 | if (type == typeof(short)) { return short.Parse(state.Value); } 47 | if (type == typeof(int)) { return int.Parse(state.Value); } 48 | if (type == typeof(long)) { return long.Parse(state.Value); } 49 | if (type == typeof(bool)) { return bool.Parse(state.Value); } 50 | if (type == typeof(float)) { return float.Parse(state.Value); } 51 | if (type == typeof(double)) { return double.Parse(state.Value); } 52 | if (type == typeof(decimal)) { return decimal.Parse(state.Value); } 53 | if (type.IsEnum) { return Enum.Parse(type, state.Value); } 54 | 55 | if (type == typeof(Guid)) 56 | { 57 | return new Guid(state.Value); 58 | } 59 | 60 | if (type == typeof(DateTime)) 61 | { 62 | var binaryTime = long.Parse(state.Value); 63 | return DateTime.FromBinary(binaryTime); 64 | } 65 | 66 | if (type == typeof(TimeSpan)) 67 | { 68 | var milliseconds = double.Parse(state.Value); 69 | return TimeSpan.FromMilliseconds(milliseconds); 70 | } 71 | 72 | return state.Value; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/LazyData.Xml/Handlers/IXmlPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | using LazyData.Serialization; 3 | 4 | namespace LazyData.Xml.Handlers 5 | { 6 | public interface IXmlPrimitiveHandler : IPrimitiveHandler 7 | {} 8 | } -------------------------------------------------------------------------------- /src/LazyData.Xml/IXmlDeserializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Serialization; 2 | 3 | namespace LazyData.Xml 4 | { 5 | public interface IXmlDeserializer : IDeserializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Xml/IXmlSerializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Serialization; 2 | 3 | namespace LazyData.Xml 4 | { 5 | public interface IXmlSerializer : ISerializer { } 6 | } -------------------------------------------------------------------------------- /src/LazyData.Xml/LazyData.Xml.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.0;net46 6 | LazyData.Xml 7 | Grofit (LP) 8 | https://github.com/grofit/lazydata/blob/master/LICENSE 9 | https://github.com/grofit/lazydata 10 | false 11 | Xml serializer for use with LazyData 12 | serialization game-development xml 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/LazyData.Xml/XmlDeserializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Xml; 6 | using System.Xml.Linq; 7 | using LazyData.Mappings; 8 | using LazyData.Mappings.Types; 9 | using LazyData.Registries; 10 | using LazyData.Serialization; 11 | using LazyData.Xml.Handlers; 12 | 13 | namespace LazyData.Xml 14 | { 15 | public class XmlDeserializer : GenericDeserializer, IXmlDeserializer 16 | { 17 | public override IPrimitiveHandler DefaultPrimitiveHandler { get; } = new BasicXmlPrimitiveHandler(); 18 | 19 | public XmlDeserializer(IMappingRegistry mappingRegistry, ITypeCreator typeCreator, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, typeCreator, customPrimitiveHandlers) 20 | {} 21 | 22 | protected override bool IsDataNull(XElement state) 23 | { return state.Attribute(XmlSerializer.NullAttributeName) != null; } 24 | 25 | protected override bool IsObjectNull(XElement state) 26 | { return IsDataNull(state); } 27 | 28 | protected override int GetCountFromState(XElement state) 29 | { return int.Parse(state.Attribute(XmlSerializer.CountAttributeName).Value); } 30 | 31 | 32 | public override object Deserialize(DataObject data, Type type = null) 33 | { 34 | var xDoc = XDocument.Parse(data.AsString); 35 | var containerElement = xDoc.Element(XmlSerializer.ContainerElementName); 36 | 37 | if (type == null) 38 | { 39 | var typeName = containerElement.Attribute(XmlSerializer.TypeAttributeName).Value; 40 | type = TypeCreator.LoadType(typeName); 41 | } 42 | 43 | var typeMapping = MappingRegistry.GetMappingFor(type); 44 | 45 | var instance = Activator.CreateInstance(typeMapping.Type); 46 | Deserialize(typeMapping.InternalMappings, instance, containerElement); 47 | return instance; 48 | } 49 | 50 | public override void DeserializeInto(DataObject data, object existingInstance) 51 | { 52 | var xDoc = XDocument.Parse(data.AsString); 53 | var containerElement = xDoc.Element(XmlSerializer.ContainerElementName); 54 | var typeMapping = MappingRegistry.GetMappingFor(existingInstance.GetType()); 55 | 56 | Deserialize(typeMapping.InternalMappings, existingInstance, containerElement); 57 | } 58 | 59 | protected override void DeserializeCollection(CollectionMapping mapping, T instance, XElement state) 60 | { 61 | if (IsObjectNull(state)) 62 | { 63 | mapping.SetValue(instance, null); 64 | return; 65 | } 66 | 67 | var count = GetCountFromState(state); 68 | var collectionInstance = CreateCollectionFromMapping(mapping, count); 69 | mapping.SetValue(instance, collectionInstance); 70 | 71 | for (var i = 0; i < count; i++) 72 | { 73 | var collectionElement = state.Elements(XmlSerializer.CollectionElementName).ElementAt(i); 74 | var elementInstance = DeserializeCollectionElement(mapping, collectionElement); 75 | 76 | if (collectionInstance.IsFixedSize) 77 | { collectionInstance[i] = elementInstance; } 78 | else 79 | { collectionInstance.Insert(i, elementInstance); } 80 | } 81 | } 82 | 83 | protected override void DeserializeDictionary(DictionaryMapping mapping, T instance, XElement state) 84 | { 85 | if (IsObjectNull(state)) 86 | { 87 | mapping.SetValue(instance, null); 88 | return; 89 | } 90 | 91 | var count = GetCountFromState(state); 92 | var dictionary = CreateDictionaryFromMapping(mapping); 93 | mapping.SetValue(instance, dictionary); 94 | 95 | for (var i = 0; i < count; i++) 96 | { 97 | var keyValuePairElement = state.Elements(XmlSerializer.KeyValuePairElementName).ElementAt(i); 98 | DeserializeDictionaryKeyValuePair(mapping, dictionary, keyValuePairElement); 99 | } 100 | } 101 | 102 | protected override void DeserializeDictionaryKeyValuePair(DictionaryMapping mapping, IDictionary dictionary, XElement state) 103 | { 104 | var keyElement = state.Element(XmlSerializer.KeyElementName); 105 | var keyInstance = DeserializeDictionaryKey(mapping, keyElement); 106 | var valueElement = state.Element(XmlSerializer.ValueElementName); 107 | var valueInstance = DeserializeDictionaryValue(mapping, valueElement); 108 | dictionary.Add(keyInstance, valueInstance); 109 | } 110 | 111 | protected override void Deserialize(IEnumerable mappings, T instance, XElement state) 112 | { 113 | foreach (var mapping in mappings) 114 | { 115 | var childElement = state.Element(mapping.LocalName); 116 | DelegateMappingType(mapping, instance, childElement); 117 | } 118 | } 119 | 120 | protected override string GetDynamicTypeNameFromState(XElement state) 121 | { return state.Attribute(XmlSerializer.TypeAttributeName).Value; } 122 | 123 | protected override XElement GetDynamicTypeDataFromState(XElement state) 124 | { return state; } 125 | } 126 | } -------------------------------------------------------------------------------- /src/LazyData.Xml/XmlSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Xml.Linq; 5 | using LazyData.Extensions; 6 | using LazyData.Mappings; 7 | using LazyData.Registries; 8 | using LazyData.Serialization; 9 | using LazyData.Xml.Handlers; 10 | 11 | namespace LazyData.Xml 12 | { 13 | public class XmlSerializer : GenericSerializer, IXmlSerializer 14 | { 15 | public const string TypeAttributeName = "Type"; 16 | public const string NullAttributeName = "IsNull"; 17 | public const string CountAttributeName = "Count"; 18 | public const string KeyElementName = "Key"; 19 | public const string ValueElementName = "Value"; 20 | public const string KeyValuePairElementName = "KeyValuePair"; 21 | public const string CollectionElementName = "Collection"; 22 | public const string ContainerElementName = "Container"; 23 | 24 | public override IPrimitiveHandler DefaultPrimitiveHandler { get; } = new BasicXmlPrimitiveHandler(); 25 | 26 | public XmlSerializer(IMappingRegistry mappingRegistry, IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, customPrimitiveHandlers) 27 | {} 28 | 29 | protected override void HandleNullData(XElement state) 30 | { state.Add(new XAttribute(NullAttributeName, true)); } 31 | 32 | protected override void HandleNullObject(XElement state) 33 | { HandleNullData(state); } 34 | 35 | protected override void AddCountToState(XElement state, int count) 36 | { state.Add(new XAttribute(CountAttributeName, count)); } 37 | 38 | protected override XElement GetDynamicTypeState(XElement state, Type type) 39 | { 40 | var typeAttribute = new XAttribute(TypeAttributeName, type.GetPersistableName()); 41 | state.Add(typeAttribute); 42 | return state; 43 | } 44 | 45 | public override DataObject Serialize(object data, bool persistType = false) 46 | { 47 | var element = new XElement(ContainerElementName); 48 | var dataType = data.GetType(); 49 | var typeMapping = MappingRegistry.GetMappingFor(dataType); 50 | Serialize(typeMapping.InternalMappings, data, element); 51 | 52 | if (persistType) 53 | { 54 | var typeAttribute = new XAttribute(TypeAttributeName, dataType.GetPersistableName()); 55 | element.Add(typeAttribute); 56 | } 57 | 58 | var xmlString = element.ToString(); 59 | return new DataObject(xmlString); 60 | } 61 | 62 | protected override void Serialize(IEnumerable mappings, T data, XElement state) 63 | { 64 | foreach (var mapping in mappings) 65 | { 66 | var newElement = new XElement(mapping.LocalName); 67 | state.Add(newElement); 68 | 69 | DelegateMappingType(mapping, data, newElement); 70 | } 71 | } 72 | 73 | protected override void SerializeCollectionElement(CollectionMapping collectionMapping, T element, XElement state) 74 | { 75 | var newElement = new XElement(CollectionElementName); 76 | state.Add(newElement); 77 | 78 | if (element == null) 79 | { 80 | HandleNullObject(newElement); 81 | return; 82 | } 83 | 84 | if (collectionMapping.IsElementDynamicType) 85 | { 86 | SerializeDynamicTypeData(element, newElement); 87 | return; 88 | } 89 | 90 | if (collectionMapping.InternalMappings.Count > 0) 91 | { Serialize(collectionMapping.InternalMappings, element, newElement); } 92 | else 93 | { SerializePrimitive(element, collectionMapping.CollectionType, newElement); } 94 | } 95 | 96 | protected override void SerializeDictionaryKeyValuePair(DictionaryMapping dictionaryMapping, IDictionary dictionary, object key, XElement state) 97 | { 98 | var keyElement = new XElement(KeyElementName); 99 | SerializeDictionaryKey(dictionaryMapping, key, keyElement); 100 | 101 | var valueElement = new XElement(ValueElementName); 102 | SerializeDictionaryValue(dictionaryMapping, dictionary[key], valueElement); 103 | 104 | var keyValuePairElement = new XElement(KeyValuePairElementName); 105 | keyValuePairElement.Add(keyElement, valueElement); 106 | state.Add(keyValuePairElement); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /src/LazyData.Yaml/IYamlDeserializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Json; 2 | 3 | namespace LazyData.Yaml 4 | { 5 | public interface IYamlDeserializer : IJsonDeserializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Yaml/IYamlSerializer.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Json; 2 | 3 | namespace LazyData.Yaml 4 | { 5 | public interface IYamlSerializer : IJsonSerializer 6 | { } 7 | } -------------------------------------------------------------------------------- /src/LazyData.Yaml/LazyData.Yaml.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.0.0 5 | netstandard2.0;net46 6 | LazyData.Yaml 7 | Grofit (LP) 8 | https://github.com/grofit/lazydata/blob/master/LICENSE 9 | https://github.com/grofit/lazydata 10 | false 11 | Yaml serializer for use with LazyData 12 | serialization game-development yaml 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/LazyData.Yaml/YamlDeserializer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System; 4 | using LazyData.Json; 5 | using LazyData.Json.Handlers; 6 | using LazyData.Mappings.Types; 7 | using LazyData.Registries; 8 | using YamlDotNet.Serialization; 9 | 10 | namespace LazyData.Yaml 11 | { 12 | public class YamlDeserializer : JsonDeserializer, IYamlDeserializer 13 | { 14 | // This needs to be injectable but cant until #350 is solved 15 | // https://github.com/aaubry/YamlDotNet/issues/350 16 | private readonly Deserializer _yamlDeserializer; 17 | private readonly Serializer _yamlSerializer; 18 | 19 | public YamlDeserializer(IMappingRegistry mappingRegistry, ITypeCreator typeCreator, 20 | IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, typeCreator, 21 | customPrimitiveHandlers) 22 | { 23 | _yamlDeserializer = new DeserializerBuilder().Build(); 24 | _yamlSerializer = new SerializerBuilder().JsonCompatible().Build(); 25 | } 26 | 27 | private DataObject ConvertYamlToJson(DataObject data) 28 | { 29 | using (var reader = new StringReader(data.AsString)) 30 | { 31 | var transientObject = _yamlDeserializer.Deserialize(reader); 32 | var json = _yamlSerializer.Serialize(transientObject); 33 | return new DataObject(json); 34 | } 35 | } 36 | 37 | public override object Deserialize(DataObject data, Type type = null) 38 | { 39 | // This is very un-performant for now, but a foot in the door 40 | var jsonObject = ConvertYamlToJson(data); 41 | return base.Deserialize(jsonObject, type); 42 | } 43 | 44 | public override void DeserializeInto(DataObject data, object existingInstance) 45 | { 46 | // This is very unperformant for now, but a foot in the door 47 | var jsonObject = ConvertYamlToJson(data); 48 | base.DeserializeInto(data, existingInstance); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/LazyData.Yaml/YamlSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using LazyData.Extensions; 6 | using LazyData.Json; 7 | using LazyData.Json.Handlers; 8 | using LazyData.Registries; 9 | using Newtonsoft.Json.Linq; 10 | using YamlDotNet.Serialization; 11 | 12 | namespace LazyData.Yaml 13 | { 14 | public class YamlSerializer : JsonSerializer, IYamlSerializer 15 | { 16 | // This needs to be injectable but cant until #350 is solved 17 | // https://github.com/aaubry/YamlDotNet/issues/350 18 | private readonly Serializer _yamlSerializer; 19 | 20 | public YamlSerializer(IMappingRegistry mappingRegistry, 21 | IEnumerable customPrimitiveHandlers = null) : base(mappingRegistry, 22 | customPrimitiveHandlers) 23 | { 24 | _yamlSerializer = new SerializerBuilder().Build(); 25 | } 26 | 27 | static object ConvertJTokenToObject(JToken token) 28 | { 29 | switch (token) 30 | { 31 | case JValue _: return ((JValue) token).Value; 32 | case JArray _: return token.AsEnumerable().Select(ConvertJTokenToObject).ToList(); 33 | case JObject _: return token.AsEnumerable().Cast() 34 | .ToDictionary(x => x.Name, x => ConvertJTokenToObject(x.Value)); 35 | default: throw new InvalidOperationException("Unexpected token: " + token); 36 | } 37 | } 38 | 39 | public override DataObject Serialize(object data, bool persistType = false) 40 | { 41 | var node = new JObject(); 42 | var dataType = data.GetType(); 43 | var typeMapping = MappingRegistry.GetMappingFor(dataType); 44 | Serialize(typeMapping.InternalMappings, data, node); 45 | 46 | if (persistType) 47 | { 48 | var typeElement = new JProperty(TypeField, dataType.GetPersistableName()); 49 | node.Add(typeElement); 50 | } 51 | 52 | var temporaryObject = ConvertJTokenToObject(node); 53 | using (var writer = new StringWriter()) 54 | { 55 | _yamlSerializer.Serialize(writer, temporaryObject); 56 | var output = writer.ToString(); 57 | return new DataObject(output); 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/LazyData.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2036 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazyData", "LazyData\LazyData.csproj", "{8AE4F137-FCFB-4B1C-B8E0-CE6CF98EE3D9}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{2E8322A0-2ACC-473A-B814-49DCCBE5048F}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazyData.PerformanceTests", "LazyData.PerformanceTests\LazyData.PerformanceTests.csproj", "{C6C62930-5BB5-4C40-90CA-4C83BFEB17EF}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazyData.Tests", "LazyData.Tests\LazyData.Tests.csproj", "{E6B98C30-CE79-4EEF-8281-DB761F42AEB0}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazyData.Numerics", "LazyData.Numerics\LazyData.Numerics.csproj", "{8AD4BA8B-C06E-475E-84ED-7C6A16426354}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazyData.SuperLazy", "LazyData.SuperLazy\LazyData.SuperLazy.csproj", "{E286E373-EA01-4920-8E65-3316893A3637}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Serializers", "Serializers", "{F4C8D90A-35BA-4F88-B981-8F6B91C04992}" 19 | EndProject 20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extras", "Extras", "{C49FD081-6DEC-4481-9196-09B3DB2362CF}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyData.Binary", "LazyData.Binary\LazyData.Binary.csproj", "{89075695-D71B-454B-B7EA-5142E3940817}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyData.Json", "LazyData.Json\LazyData.Json.csproj", "{28FC6A59-62A8-4B4C-BBD9-C5929AA5E1F9}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyData.Xml", "LazyData.Xml\LazyData.Xml.csproj", "{A80985DA-061B-4D87-9489-A5EFF8D7F318}" 27 | EndProject 28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyData.Bson", "LazyData.Bson\LazyData.Bson.csproj", "{83991561-F141-4C84-8FCE-310D7BA1D848}" 29 | EndProject 30 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyData.Yaml", "LazyData.Yaml\LazyData.Yaml.csproj", "{6B45888C-8062-47D6-9BE8-A8525CE401A1}" 31 | EndProject 32 | Global 33 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 34 | Debug|Any CPU = Debug|Any CPU 35 | Release|Any CPU = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 38 | {8AE4F137-FCFB-4B1C-B8E0-CE6CF98EE3D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {8AE4F137-FCFB-4B1C-B8E0-CE6CF98EE3D9}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {8AE4F137-FCFB-4B1C-B8E0-CE6CF98EE3D9}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {8AE4F137-FCFB-4B1C-B8E0-CE6CF98EE3D9}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {C6C62930-5BB5-4C40-90CA-4C83BFEB17EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {C6C62930-5BB5-4C40-90CA-4C83BFEB17EF}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {C6C62930-5BB5-4C40-90CA-4C83BFEB17EF}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {C6C62930-5BB5-4C40-90CA-4C83BFEB17EF}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {E6B98C30-CE79-4EEF-8281-DB761F42AEB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {E6B98C30-CE79-4EEF-8281-DB761F42AEB0}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {E6B98C30-CE79-4EEF-8281-DB761F42AEB0}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {E6B98C30-CE79-4EEF-8281-DB761F42AEB0}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {8AD4BA8B-C06E-475E-84ED-7C6A16426354}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {8AD4BA8B-C06E-475E-84ED-7C6A16426354}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {8AD4BA8B-C06E-475E-84ED-7C6A16426354}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {8AD4BA8B-C06E-475E-84ED-7C6A16426354}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {E286E373-EA01-4920-8E65-3316893A3637}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {E286E373-EA01-4920-8E65-3316893A3637}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {E286E373-EA01-4920-8E65-3316893A3637}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {E286E373-EA01-4920-8E65-3316893A3637}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {89075695-D71B-454B-B7EA-5142E3940817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {89075695-D71B-454B-B7EA-5142E3940817}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {89075695-D71B-454B-B7EA-5142E3940817}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {89075695-D71B-454B-B7EA-5142E3940817}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {28FC6A59-62A8-4B4C-BBD9-C5929AA5E1F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {28FC6A59-62A8-4B4C-BBD9-C5929AA5E1F9}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {28FC6A59-62A8-4B4C-BBD9-C5929AA5E1F9}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {28FC6A59-62A8-4B4C-BBD9-C5929AA5E1F9}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {A80985DA-061B-4D87-9489-A5EFF8D7F318}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {A80985DA-061B-4D87-9489-A5EFF8D7F318}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {A80985DA-061B-4D87-9489-A5EFF8D7F318}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {A80985DA-061B-4D87-9489-A5EFF8D7F318}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {83991561-F141-4C84-8FCE-310D7BA1D848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 71 | {83991561-F141-4C84-8FCE-310D7BA1D848}.Debug|Any CPU.Build.0 = Debug|Any CPU 72 | {83991561-F141-4C84-8FCE-310D7BA1D848}.Release|Any CPU.ActiveCfg = Release|Any CPU 73 | {83991561-F141-4C84-8FCE-310D7BA1D848}.Release|Any CPU.Build.0 = Release|Any CPU 74 | {6B45888C-8062-47D6-9BE8-A8525CE401A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 75 | {6B45888C-8062-47D6-9BE8-A8525CE401A1}.Debug|Any CPU.Build.0 = Debug|Any CPU 76 | {6B45888C-8062-47D6-9BE8-A8525CE401A1}.Release|Any CPU.ActiveCfg = Release|Any CPU 77 | {6B45888C-8062-47D6-9BE8-A8525CE401A1}.Release|Any CPU.Build.0 = Release|Any CPU 78 | EndGlobalSection 79 | GlobalSection(SolutionProperties) = preSolution 80 | HideSolutionNode = FALSE 81 | EndGlobalSection 82 | GlobalSection(NestedProjects) = preSolution 83 | {C6C62930-5BB5-4C40-90CA-4C83BFEB17EF} = {2E8322A0-2ACC-473A-B814-49DCCBE5048F} 84 | {E6B98C30-CE79-4EEF-8281-DB761F42AEB0} = {2E8322A0-2ACC-473A-B814-49DCCBE5048F} 85 | {8AD4BA8B-C06E-475E-84ED-7C6A16426354} = {C49FD081-6DEC-4481-9196-09B3DB2362CF} 86 | {E286E373-EA01-4920-8E65-3316893A3637} = {C49FD081-6DEC-4481-9196-09B3DB2362CF} 87 | {89075695-D71B-454B-B7EA-5142E3940817} = {F4C8D90A-35BA-4F88-B981-8F6B91C04992} 88 | {28FC6A59-62A8-4B4C-BBD9-C5929AA5E1F9} = {F4C8D90A-35BA-4F88-B981-8F6B91C04992} 89 | {A80985DA-061B-4D87-9489-A5EFF8D7F318} = {F4C8D90A-35BA-4F88-B981-8F6B91C04992} 90 | {83991561-F141-4C84-8FCE-310D7BA1D848} = {F4C8D90A-35BA-4F88-B981-8F6B91C04992} 91 | {6B45888C-8062-47D6-9BE8-A8525CE401A1} = {F4C8D90A-35BA-4F88-B981-8F6B91C04992} 92 | EndGlobalSection 93 | GlobalSection(ExtensibilityGlobals) = postSolution 94 | SolutionGuid = {2822F9A4-82C4-4111-B49D-D96B78E71705} 95 | EndGlobalSection 96 | EndGlobal 97 | -------------------------------------------------------------------------------- /src/LazyData/Attributes/DynamicTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Property)] 6 | public class DynamicTypeAttribute : Attribute 7 | { } 8 | } -------------------------------------------------------------------------------- /src/LazyData/Attributes/PersistAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Class)] 6 | public class PersistAttribute : Attribute 7 | {} 8 | } -------------------------------------------------------------------------------- /src/LazyData/Attributes/PersistDataAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Property)] 6 | public class PersistDataAttribute : Attribute 7 | {} 8 | } -------------------------------------------------------------------------------- /src/LazyData/DataObject.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData 2 | { 3 | public struct DataObject 4 | { 5 | private readonly string _stringData; 6 | private readonly byte[] _byteData; 7 | 8 | public string AsString => _stringData ?? DefaultEncoding.Encoder.GetString(_byteData); 9 | public byte[] AsBytes => _byteData ?? DefaultEncoding.Encoder.GetBytes(_stringData); 10 | 11 | public DataObject(string data) 12 | { 13 | _stringData = data; 14 | _byteData = null; 15 | } 16 | 17 | public DataObject(byte[] data) 18 | { 19 | _stringData = null; 20 | _byteData = data; 21 | } 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /src/LazyData/DefaultEncoding.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace LazyData 4 | { 5 | public static class DefaultEncoding 6 | { 7 | public static Encoding Encoder = Encoding.UTF8; 8 | } 9 | } -------------------------------------------------------------------------------- /src/LazyData/Exceptions/NoKnownTypeException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Exceptions 4 | { 5 | public class NoKnownTypeException : Exception 6 | { 7 | public NoKnownTypeException(Type type) : base($"{type} is not a known type") 8 | {} 9 | } 10 | } -------------------------------------------------------------------------------- /src/LazyData/Exceptions/TypeNotPersistableException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Exceptions 4 | { 5 | public class TypeNotPersistableException : Exception 6 | { 7 | public TypeNotPersistableException(Type type) : base($"{type} is not persistable, ensure it has a Persist attribute") 8 | {} 9 | } 10 | } -------------------------------------------------------------------------------- /src/LazyData/Extensions/IListExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LazyData.Extensions 5 | { 6 | public static class IListExtension 7 | { 8 | public static void AddRange(this IList list, IEnumerable items) 9 | { 10 | if (list == null) throw new ArgumentNullException(nameof(list)); 11 | if (items == null) throw new ArgumentNullException(nameof(items)); 12 | 13 | if (list is List) 14 | { 15 | ((List)list).AddRange(items); 16 | } 17 | else 18 | { 19 | foreach (var item in items) 20 | { 21 | list.Add(item); 22 | } 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/LazyData/Extensions/ReflectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace LazyData.Extensions 7 | { 8 | public static class ReflectionExtensions 9 | { 10 | public static IEnumerable AllAttributes(this MemberInfo provider, params Type[] attributeTypes) 11 | { 12 | var allAttributes = provider.GetCustomAttributes(true).Cast(); 13 | 14 | if (attributeTypes.Length == 0) { return allAttributes; } 15 | 16 | return allAttributes.Where(a => attributeTypes.Any(x => a.GetType().DerivesFromOrEqual(x))); 17 | } 18 | 19 | public static bool DerivesFromOrEqual(this Type a, Type b) 20 | { return b == a || b.IsAssignableFrom(a); } 21 | 22 | public static bool HasAttribute( 23 | this ParameterInfo provider, params Type[] attributeTypes) 24 | { 25 | return provider.AllAttributes(attributeTypes).Any(); 26 | } 27 | 28 | public static bool HasAttribute(this MemberInfo provider) 29 | where T : Attribute 30 | { 31 | return provider.AllAttributes(typeof(T)).Any(); 32 | } 33 | 34 | public static bool HasAttribute(this ParameterInfo provider) 35 | where T : Attribute 36 | { 37 | return provider.AllAttributes(typeof(T)).Any(); 38 | } 39 | 40 | public static IEnumerable AllAttributes( 41 | this ParameterInfo provider) 42 | where T : Attribute 43 | { 44 | return provider.AllAttributes(typeof(T)).Cast(); 45 | } 46 | 47 | public static IEnumerable AllAttributes( 48 | this ParameterInfo provider, params Type[] attributeTypes) 49 | { 50 | var allAttributes = provider.GetCustomAttributes(true).Cast(); 51 | 52 | if (attributeTypes.Length == 0) { return allAttributes; } 53 | 54 | return allAttributes.Where(a => attributeTypes.Any(x => a.GetType().DerivesFromOrEqual(x))); 55 | } 56 | 57 | } 58 | } -------------------------------------------------------------------------------- /src/LazyData/Extensions/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace LazyData.Extensions 5 | { 6 | public static class TypeExtensions 7 | { 8 | public static bool IsTypeOf(this Type type, params Type[] types) 9 | { return types.Any(x => x == type); } 10 | 11 | public static string GetPersistableName(this Type type) 12 | { return type.FullName; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/LazyData/LazyData.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 0.0.0 4 | netstandard2.0;net46 5 | LazyData 6 | Grofit (LP) 7 | https://github.com/grofit/lazydata/blob/master/LICENSE 8 | https://github.com/grofit/lazydata 9 | false 10 | Fast serializer supporting multiple formats targetting game developers 11 | serialization game-development json xml binary 12 | 13 | -------------------------------------------------------------------------------- /src/LazyData/Mappings/CollectionMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace LazyData.Mappings 6 | { 7 | public class CollectionMapping : Mapping 8 | { 9 | public Type CollectionType { get; set; } 10 | public Func GetValue { get; set; } 11 | public Action SetValue { get; set; } 12 | public IList InternalMappings { get; private set; } 13 | public bool IsArray { get; set; } 14 | public bool IsElementDynamicType { get; set; } 15 | 16 | public CollectionMapping() 17 | { InternalMappings = new List(); } 18 | } 19 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/DictionaryMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace LazyData.Mappings 6 | { 7 | public class DictionaryMapping : Mapping 8 | { 9 | public Type KeyType { get; set; } 10 | public Type ValueType { get; set; } 11 | public Func GetValue { get; set; } 12 | public Action SetValue { get; set; } 13 | public IList KeyMappings { get; } 14 | public IList ValueMappings { get; } 15 | public bool IsKeyDynamicType { get; set; } 16 | public bool IsValueDynamicType { get; set; } 17 | 18 | public DictionaryMapping() 19 | { 20 | KeyMappings = new List(); 21 | ValueMappings = new List(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Mappers/DefaultTypeMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using LazyData.Attributes; 6 | using LazyData.Exceptions; 7 | using LazyData.Extensions; 8 | using LazyData.Mappings.Types; 9 | 10 | namespace LazyData.Mappings.Mappers 11 | { 12 | public class DefaultTypeMapper : TypeMapper 13 | { 14 | public DefaultTypeMapper(ITypeAnalyzer typeAnalyzer, MappingConfiguration configuration = null) : base(typeAnalyzer, configuration) 15 | {} 16 | 17 | public override IEnumerable GetPropertiesFor(Type type) 18 | { 19 | return base.GetPropertiesFor(type) 20 | .Where(x => x.HasAttribute()&& 21 | x.GetSetMethod().IsPublic && 22 | x.GetGetMethod().IsPublic); 23 | } 24 | 25 | public override TypeMapping GetTypeMappingsFor(Type type) 26 | { 27 | if (!type.HasAttribute()) 28 | { throw new TypeNotPersistableException(type); } 29 | 30 | return base.GetTypeMappingsFor(type); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Mappers/EverythingTypeMapper.cs: -------------------------------------------------------------------------------- 1 | using LazyData.Mappings.Types; 2 | 3 | namespace LazyData.Mappings.Mappers 4 | { 5 | /// 6 | /// This type mapper doesnt care about attributes 7 | /// and will attempt to map everything and anything 8 | /// in a class, so use with caution 9 | /// 10 | public class EverythingTypeMapper : TypeMapper 11 | { 12 | public EverythingTypeMapper(ITypeAnalyzer typeAnalyzer, MappingConfiguration configuration = null) : base(typeAnalyzer, configuration) 13 | {} 14 | } 15 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Mappers/ITypeMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Mappings.Types; 3 | 4 | namespace LazyData.Mappings.Mappers 5 | { 6 | public interface ITypeMapper 7 | { 8 | ITypeAnalyzer TypeAnalyzer { get; } 9 | TypeMapping GetTypeMappingsFor(Type type); 10 | } 11 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Mappers/MappingConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData.Mappings.Mappers 2 | { 3 | public class MappingConfiguration 4 | { 5 | public static MappingConfiguration Default => new MappingConfiguration(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Mappers/TypeMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using LazyData.Extensions; 7 | using LazyData.Mappings.Types; 8 | 9 | namespace LazyData.Mappings.Mappers 10 | { 11 | public abstract class TypeMapper : ITypeMapper 12 | { 13 | public MappingConfiguration Configuration { get; } 14 | public ITypeAnalyzer TypeAnalyzer { get; } 15 | 16 | protected TypeMapper(ITypeAnalyzer typeAnalyzer, MappingConfiguration configuration = null) 17 | { 18 | TypeAnalyzer = typeAnalyzer; 19 | Configuration = configuration ?? MappingConfiguration.Default; 20 | } 21 | 22 | public virtual TypeMapping GetTypeMappingsFor(Type type) 23 | { 24 | var typeMapping = new TypeMapping 25 | { 26 | Name = type.GetPersistableName(), 27 | Type = type 28 | }; 29 | 30 | var mappings = GetMappingsFromType(type, type.Name); 31 | typeMapping.InternalMappings.AddRange(mappings); 32 | 33 | return typeMapping; 34 | } 35 | 36 | public virtual List GetMappingsFromType(Type type, string scope) 37 | { 38 | var properties = GetPropertiesFor(type); 39 | 40 | if (TypeAnalyzer.HasIgnoredTypes()) 41 | { properties = properties.Where(x => TypeAnalyzer.IsIgnoredType(x.PropertyType)); } 42 | 43 | return properties.Select(propertyInfo => GetMappingFor(propertyInfo, scope)).ToList(); 44 | } 45 | 46 | public virtual IEnumerable GetPropertiesFor(Type type) 47 | { 48 | return type.GetProperties() 49 | .Where(x => x.CanRead && x.CanWrite); 50 | } 51 | 52 | public virtual Mapping GetMappingFor(PropertyInfo propertyInfo, string scope) 53 | { 54 | var currentScope = scope + "." + propertyInfo.Name; 55 | 56 | if (TypeAnalyzer.IsPrimitiveType(propertyInfo.PropertyType)) 57 | { return CreatePropertyMappingFor(propertyInfo, currentScope); } 58 | 59 | if (TypeAnalyzer.IsGenericDictionary(propertyInfo.PropertyType) || 60 | TypeAnalyzer.HasImplementedGenericDictionary(propertyInfo.PropertyType)) 61 | { return CreateDictionaryMappingFor(propertyInfo, currentScope); } 62 | 63 | if (propertyInfo.PropertyType.IsArray || 64 | TypeAnalyzer.IsGenericCollection(propertyInfo.PropertyType) || 65 | TypeAnalyzer.HasImplementedGenericCollection(propertyInfo.PropertyType)) 66 | { return CreateCollectionMappingFor(propertyInfo, currentScope); } 67 | 68 | var possibleType = TypeAnalyzer.GetNullableType(propertyInfo.PropertyType); 69 | if (possibleType != null) 70 | { 71 | if (TypeAnalyzer.IsPrimitiveType(possibleType)) 72 | { return CreatePropertyMappingFor(propertyInfo, currentScope); } 73 | } 74 | 75 | return CreateNestedMappingFor(propertyInfo, currentScope); 76 | } 77 | 78 | public virtual CollectionMapping CreateCollectionMappingFor(PropertyInfo propertyInfo, string scope) 79 | { 80 | var propertyType = propertyInfo.PropertyType; 81 | var collectionType = TypeAnalyzer.GetElementType(propertyType); 82 | 83 | var collectionMapping = new CollectionMapping 84 | { 85 | LocalName = propertyInfo.Name, 86 | ScopedName = scope, 87 | CollectionType = collectionType, 88 | Type = propertyInfo.PropertyType, 89 | GetValue = (x) => propertyInfo.GetValue(x, null) as IList, 90 | SetValue = (x, v) => propertyInfo.SetValue(x, v, null), 91 | IsArray = propertyType.IsArray, 92 | IsElementDynamicType = TypeAnalyzer.IsDynamicType(collectionType) 93 | }; 94 | 95 | var collectionMappingTypes = GetMappingsFromType(collectionType, scope); 96 | collectionMapping.InternalMappings.AddRange(collectionMappingTypes); 97 | 98 | return collectionMapping; 99 | } 100 | 101 | public virtual DictionaryMapping CreateDictionaryMappingFor(PropertyInfo propertyInfo, string scope) 102 | { 103 | var propertyType = propertyInfo.PropertyType; 104 | 105 | var dictionaryTypes = TypeAnalyzer.GetGenericTypes(propertyType, typeof(IDictionary<,>)); 106 | 107 | var keyType = dictionaryTypes[0]; 108 | var valueType = dictionaryTypes[1]; 109 | 110 | var dictionaryMapping = new DictionaryMapping 111 | { 112 | LocalName = propertyInfo.Name, 113 | ScopedName = scope, 114 | KeyType = keyType, 115 | ValueType = valueType, 116 | Type = propertyInfo.PropertyType, 117 | GetValue = (x) => propertyInfo.GetValue(x, null) as IDictionary, 118 | SetValue = (x, v) => propertyInfo.SetValue(x, v, null), 119 | IsKeyDynamicType = TypeAnalyzer.IsDynamicType(keyType), 120 | IsValueDynamicType = TypeAnalyzer.IsDynamicType(valueType) 121 | }; 122 | 123 | var keyMappingTypes = GetMappingsFromType(keyType, scope); 124 | dictionaryMapping.KeyMappings.AddRange(keyMappingTypes); 125 | 126 | var valueMappingTypes = GetMappingsFromType(valueType, scope); 127 | dictionaryMapping.ValueMappings.AddRange(valueMappingTypes); 128 | 129 | return dictionaryMapping; 130 | } 131 | 132 | public virtual PropertyMapping CreatePropertyMappingFor(PropertyInfo propertyInfo, string scope) 133 | { 134 | return new PropertyMapping 135 | { 136 | LocalName = propertyInfo.Name, 137 | ScopedName = scope, 138 | Type = propertyInfo.PropertyType, 139 | GetValue = x => propertyInfo.GetValue(x, null), 140 | SetValue = (x, v) => propertyInfo.SetValue(x, v, null) 141 | }; 142 | } 143 | 144 | public virtual NestedMapping CreateNestedMappingFor(PropertyInfo propertyInfo, string scope) 145 | { 146 | var nestedMapping = new NestedMapping 147 | { 148 | LocalName = propertyInfo.Name, 149 | ScopedName = scope, 150 | Type = propertyInfo.PropertyType, 151 | GetValue = x => propertyInfo.GetValue(x, null), 152 | SetValue = (x, v) => propertyInfo.SetValue(x, v, null), 153 | IsDynamicType = TypeAnalyzer.IsDynamicType(propertyInfo) 154 | }; 155 | 156 | var mappingTypes = GetMappingsFromType(propertyInfo.PropertyType, scope); 157 | nestedMapping.InternalMappings.AddRange(mappingTypes); 158 | return nestedMapping; 159 | } 160 | 161 | public virtual T GetKey(IDictionary dictionary, int index) 162 | { return dictionary.Keys.ElementAt(index); } 163 | 164 | public virtual K GetValue(IDictionary dictionary, T key) 165 | { return dictionary[key]; } 166 | } 167 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Mapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LazyData.Mappings 5 | { 6 | public class Mapping 7 | { 8 | public string LocalName { get; set; } 9 | public string ScopedName { get; set; } 10 | public Type Type { get; set; } 11 | public IDictionary MetaData { get; } 12 | 13 | public Mapping() 14 | { 15 | MetaData = new Dictionary(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/NestedMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LazyData.Mappings 5 | { 6 | public class NestedMapping : Mapping 7 | { 8 | public Func GetValue { get; set; } 9 | public Action SetValue { get; set; } 10 | public IList InternalMappings { get; } 11 | public bool IsDynamicType { get; set; } 12 | 13 | public NestedMapping() 14 | { InternalMappings = new List(); } 15 | } 16 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/PropertyMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Mappings 4 | { 5 | public class PropertyMapping : Mapping 6 | { 7 | public Func GetValue { get; set; } 8 | public Action SetValue { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/TypeMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LazyData.Mappings 5 | { 6 | public class TypeMapping 7 | { 8 | public string Name { get; set; } 9 | public Type Type { get; set; } 10 | 11 | public IList InternalMappings { get; } 12 | 13 | public TypeMapping() 14 | { 15 | InternalMappings = new List(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/ITypeAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace LazyData.Mappings.Types 5 | { 6 | public interface ITypeAnalyzer 7 | { 8 | bool IsGenericCollection(Type type); 9 | bool IsGenericDictionary(Type type); 10 | bool IsDynamicType(Type type); 11 | bool IsDynamicType(PropertyInfo propertyInfo); 12 | Type GetNullableType(Type type); 13 | Type[] GetGenericTypes(Type type, Type matching); 14 | Type GetElementType(Type type); 15 | bool HasIgnoredTypes(); 16 | bool IsIgnoredType(Type type); 17 | bool IsPrimitiveType(Type type); 18 | bool HasImplementedGenericCollection(Type type); 19 | bool HasImplementedGenericDictionary(Type type); 20 | } 21 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/ITypeCreator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | namespace LazyData.Mappings.Types 5 | { 6 | public interface ITypeCreator 7 | { 8 | Type LoadType(string partialName); 9 | object Instantiate(Type type); 10 | IDictionary CreateDictionary(Type keyType, Type valueType); 11 | IList CreateFixedCollection(Type collectionType, int size); 12 | IList CreateList(Type elementType); 13 | } 14 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/Primitives/Checkers/BasicPrimitiveChecker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Mappings.Types.Primitives.Checkers 4 | { 5 | public class BasicPrimitiveChecker : IPrimitiveChecker 6 | { 7 | public bool IsPrimitive(Type type) 8 | { 9 | return type.IsPrimitive || 10 | type == typeof(string) || 11 | type == typeof(DateTime) || 12 | type == typeof(TimeSpan) || 13 | type == typeof(Guid) || 14 | type.IsEnum; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/Primitives/Checkers/IPrimitiveChecker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Mappings.Types.Primitives.Checkers 4 | { 5 | public interface IPrimitiveChecker 6 | { 7 | bool IsPrimitive(Type type); 8 | } 9 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/Primitives/Checkers/PredicatePrimitiveChecker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Mappings.Types.Primitives.Checkers 4 | { 5 | public class PredicatePrimitiveChecker : IPrimitiveChecker 6 | { 7 | private readonly Func _predicate; 8 | 9 | public PredicatePrimitiveChecker(Func predicate) 10 | { _predicate = predicate; } 11 | 12 | public bool IsPrimitive(Type type) 13 | { return _predicate(type); } 14 | } 15 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/Primitives/IPrimitiveRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using LazyData.Mappings.Types.Primitives.Checkers; 4 | 5 | namespace LazyData.Mappings.Types.Primitives 6 | { 7 | public interface IPrimitiveRegistry 8 | { 9 | IEnumerable PrimitiveChecks { get; } 10 | void AddPrimitiveCheck(IPrimitiveChecker primitiveCheck); 11 | bool IsKnownPrimitive(Type type); 12 | } 13 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/Primitives/PrimitiveRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using LazyData.Mappings.Types.Primitives.Checkers; 5 | 6 | namespace LazyData.Mappings.Types.Primitives 7 | { 8 | public class PrimitiveRegistry : IPrimitiveRegistry 9 | { 10 | private readonly IList _primitiveChecks; 11 | 12 | public IEnumerable PrimitiveChecks => _primitiveChecks; 13 | 14 | public PrimitiveRegistry(params IPrimitiveChecker[] primitiveCheckers) 15 | { _primitiveChecks = primitiveCheckers.ToList(); } 16 | 17 | public void AddPrimitiveCheck(IPrimitiveChecker primitiveCheck) 18 | { 19 | if(_primitiveChecks.Contains(primitiveCheck)) 20 | { return; } 21 | 22 | _primitiveChecks.Add(primitiveCheck); 23 | } 24 | 25 | public bool IsKnownPrimitive(Type type) 26 | { 27 | for (var i = 0; i < _primitiveChecks.Count; i++) 28 | { 29 | if(_primitiveChecks[i].IsPrimitive(type)) 30 | { return true; } 31 | } 32 | 33 | return false; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/TypeAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using LazyData.Attributes; 7 | using LazyData.Extensions; 8 | using LazyData.Mappings.Types.Primitives; 9 | using LazyData.Mappings.Types.Primitives.Checkers; 10 | 11 | namespace LazyData.Mappings.Types 12 | { 13 | public class TypeAnalyzer : ITypeAnalyzer 14 | { 15 | public TypeAnalyzerConfiguration Configuration { get; } 16 | public IPrimitiveRegistry PrimitiveRegistry { get; } 17 | 18 | public TypeAnalyzer(IPrimitiveRegistry primitiveRegistry = null, TypeAnalyzerConfiguration configuration = null) 19 | { 20 | if (primitiveRegistry == null) 21 | { 22 | PrimitiveRegistry = new PrimitiveRegistry(); 23 | PrimitiveRegistry.AddPrimitiveCheck(new BasicPrimitiveChecker()); 24 | } 25 | else 26 | { 27 | PrimitiveRegistry = primitiveRegistry; 28 | } 29 | 30 | Configuration = configuration ?? new TypeAnalyzerConfiguration(); 31 | } 32 | 33 | public bool HasImplementedGenericCollection(Type type) 34 | { 35 | return type.GetInterfaces().Any(x => x.IsGenericType && ( 36 | x.GetGenericTypeDefinition() == typeof(IEnumerable<>) || 37 | x.GetGenericTypeDefinition().GetInterface(nameof(IEnumerable)) != 38 | null)); 39 | } 40 | 41 | public bool IsGenericCollection(Type type) 42 | { 43 | return type.IsGenericType && (type.GetGenericTypeDefinition().IsAssignableFrom(typeof(ICollection<>)) || 44 | type.GetGenericTypeDefinition().GetInterface(nameof(IEnumerable)) != null); 45 | } 46 | 47 | public bool HasImplementedGenericDictionary(Type type) 48 | { 49 | return type.GetInterfaces().Any(x => x.IsGenericType && ( 50 | x.GetGenericTypeDefinition() == typeof(IDictionary<,>) || 51 | x.GetGenericTypeDefinition().GetInterface(nameof(IDictionary)) != null)); 52 | } 53 | 54 | public bool IsGenericDictionary(Type type) 55 | { 56 | return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IDictionary<,>) || 57 | type.GetGenericTypeDefinition().GetInterface(nameof(IDictionary)) != null); 58 | } 59 | 60 | public bool IsDynamicType(Type type) 61 | { return type.IsAbstract || type.IsInterface || type == typeof(object); } 62 | 63 | public bool IsDynamicType(PropertyInfo propertyInfo) 64 | { 65 | var typeIsDynamic = IsDynamicType(propertyInfo.PropertyType); 66 | return typeIsDynamic || propertyInfo.HasAttribute(); 67 | } 68 | 69 | public Type[] GetGenericTypes(Type type, Type genericType) 70 | { 71 | if (type.IsGenericType) 72 | { return type.GetGenericArguments(); } 73 | 74 | var proxyType = type.GetInterfaces().SingleOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType); 75 | if (proxyType == null) { return new Type[0]; } 76 | return proxyType.GetGenericArguments(); 77 | } 78 | 79 | public Type GetElementType(Type type) 80 | { 81 | if (type.IsArray) { return type.GetElementType(); } 82 | if (type.IsGenericType){ return type.GetGenericArguments()[0];} 83 | 84 | var proxyType = type.GetInterfaces().SingleOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)); 85 | return proxyType.GetGenericArguments()[0]; 86 | } 87 | 88 | public bool HasIgnoredTypes() 89 | { return Configuration.IgnoredTypes.Any(); } 90 | 91 | public bool IsIgnoredType(Type type) 92 | { return !Configuration.IgnoredTypes.Any(type.IsAssignableFrom); } 93 | 94 | public bool IsTypeMatch(Type actualType, Type expectedType) 95 | { 96 | if (actualType == expectedType || actualType.IsAssignableFrom(expectedType)) 97 | { return true; } 98 | 99 | if (actualType.IsGenericType) 100 | { 101 | var genericType = actualType.GetGenericTypeDefinition(); 102 | if (genericType == expectedType) 103 | { return true; } 104 | 105 | var genericInterfaces = genericType.GetInterfaces(); 106 | if (genericInterfaces.Any(x => x.Name == expectedType.Name)) 107 | { return true; } 108 | } 109 | 110 | var interfaces = actualType.GetInterfaces(); 111 | return interfaces.Any(x => x == expectedType); 112 | } 113 | 114 | public Type GetNullableType(Type possibleNullable) 115 | { return Nullable.GetUnderlyingType(possibleNullable); } 116 | 117 | public bool IsPrimitiveType(Type type) 118 | { return PrimitiveRegistry.IsKnownPrimitive(type); } 119 | } 120 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/TypeAnalyzerConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LazyData.Mappings.Types 5 | { 6 | public class TypeAnalyzerConfiguration 7 | { 8 | public IEnumerable IgnoredTypes { get; } 9 | 10 | public TypeAnalyzerConfiguration(IEnumerable ignoredTypes = null) 11 | { 12 | IgnoredTypes = ignoredTypes ?? new List(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/LazyData/Mappings/Types/TypeCreator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace LazyData.Mappings.Types 7 | { 8 | public class TypeCreator : ITypeCreator 9 | { 10 | protected readonly Type Dictionarytype = typeof(Dictionary<,>); 11 | protected readonly Type ListType = typeof(List<>); 12 | 13 | public IDictionary TypeCache { get; } 14 | 15 | public TypeCreator() 16 | { 17 | TypeCache = new Dictionary(); 18 | } 19 | 20 | public Type LoadType(string partialName) 21 | { 22 | if (TypeCache.ContainsKey(partialName)) 23 | { return TypeCache[partialName]; } 24 | 25 | var type = Type.GetType(partialName) ?? 26 | AppDomain.CurrentDomain.GetAssemblies() 27 | .Select(a => a.GetType(partialName)) 28 | .FirstOrDefault(t => t != null); 29 | 30 | TypeCache.Add(partialName, type); 31 | return type; 32 | } 33 | 34 | public IDictionary CreateDictionary(Type keyType, Type valueType) 35 | { 36 | var constructedDictionaryType = Dictionarytype.MakeGenericType(keyType, valueType); 37 | return (IDictionary)Activator.CreateInstance(constructedDictionaryType); 38 | } 39 | 40 | public IList CreateFixedCollection(Type collectionType, int size) 41 | { return (IList)Activator.CreateInstance(collectionType, size); } 42 | 43 | public IList CreateList(Type elementType) 44 | { 45 | var constructedListType = ListType.MakeGenericType(elementType); 46 | return (IList)Activator.CreateInstance(constructedListType); 47 | } 48 | 49 | public object Instantiate(Type type) 50 | { return Activator.CreateInstance(type); } 51 | } 52 | } -------------------------------------------------------------------------------- /src/LazyData/Registries/IMappingRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Mappings; 3 | using LazyData.Mappings.Mappers; 4 | 5 | namespace LazyData.Registries 6 | { 7 | public interface IMappingRegistry 8 | { 9 | ITypeMapper TypeMapper { get; } 10 | 11 | TypeMapping GetMappingFor() where T : new(); 12 | TypeMapping GetMappingFor(Type type); 13 | } 14 | } -------------------------------------------------------------------------------- /src/LazyData/Registries/MappingRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using LazyData.Mappings; 4 | using LazyData.Mappings.Mappers; 5 | 6 | namespace LazyData.Registries 7 | { 8 | public class MappingRegistry : IMappingRegistry 9 | { 10 | public ITypeMapper TypeMapper { get; } 11 | public IDictionary TypeMappings { get; } 12 | 13 | public MappingRegistry(ITypeMapper typeMapper) 14 | { 15 | TypeMapper = typeMapper; 16 | TypeMappings = new Dictionary(); 17 | } 18 | 19 | public TypeMapping GetMappingFor() where T : new() 20 | { 21 | var type = typeof(T); 22 | return GetMappingFor(type); 23 | } 24 | 25 | public TypeMapping GetMappingFor(Type type) 26 | { 27 | if(TypeMappings.ContainsKey(type)) 28 | { return TypeMappings[type]; } 29 | 30 | var typeMapping = TypeMapper.GetTypeMappingsFor(type); 31 | TypeMappings.Add(type, typeMapping); 32 | return typeMapping; 33 | } 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /src/LazyData/Serialization/Debug/DebugSerializer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | using LazyData.Mappings; 4 | using LazyData.Registries; 5 | 6 | namespace LazyData.Serialization.Debug 7 | { 8 | public class DebugSerializer : ISerializer 9 | { 10 | public IMappingRegistry MappingRegistry { get; private set; } 11 | 12 | public DebugSerializer(IMappingRegistry mappingRegistry) 13 | { 14 | MappingRegistry = mappingRegistry; 15 | } 16 | 17 | public DataObject Serialize(object data, bool persistType = false) 18 | { 19 | var output = new StringBuilder(); 20 | var typeMapping = MappingRegistry.GetMappingFor(data.GetType()); 21 | 22 | var result = Serialize(typeMapping.InternalMappings, data); 23 | output.AppendLine(result); 24 | var outputString = output.ToString(); 25 | return new DataObject(outputString); 26 | } 27 | 28 | private string SerializeProperty(PropertyMapping propertyMapping, T data) 29 | { 30 | if (data == null) { return string.Format("{0} : {1} \n", propertyMapping.ScopedName, null); } 31 | 32 | var output = propertyMapping.GetValue(data); 33 | return string.Format("{0} : {1}", propertyMapping.ScopedName, output); 34 | } 35 | 36 | private string SerializeNestedObject(NestedMapping nestedMapping, T data) 37 | { 38 | if (data == null) { return string.Format("{0} : {1} \n", nestedMapping.ScopedName, null); } 39 | 40 | var output = new StringBuilder(); 41 | var currentData = nestedMapping.GetValue(data); 42 | var result = Serialize(nestedMapping.InternalMappings, currentData); 43 | output.Append(result); 44 | return output.ToString(); 45 | } 46 | 47 | private string Serialize(IEnumerable mappings, T data) 48 | { 49 | var output = new StringBuilder(); 50 | 51 | foreach (var mapping in mappings) 52 | { 53 | if (mapping is PropertyMapping) 54 | { 55 | var result = SerializeProperty((mapping as PropertyMapping), data); 56 | output.AppendLine(result); 57 | } 58 | else if (mapping is NestedMapping) 59 | { 60 | var result = SerializeNestedObject((mapping as NestedMapping), data); 61 | output.Append(result); 62 | } 63 | else if (mapping is DictionaryMapping) 64 | { 65 | var result = SerializeDictionary((mapping as DictionaryMapping), data); 66 | output.Append(result); 67 | } 68 | else 69 | { 70 | var result = SerializeCollection((mapping as CollectionMapping), data); 71 | output.Append(result); 72 | } 73 | } 74 | return output.ToString(); 75 | } 76 | 77 | private string SerializeCollection(CollectionMapping collectionMapping, T data) 78 | { 79 | if (data == null) { return string.Format("{0} : {1} \n", collectionMapping.ScopedName, null); } 80 | 81 | var output = new StringBuilder(); 82 | var collectionValue = collectionMapping.GetValue(data); 83 | if (collectionValue == null) { return string.Format("{0} : {1} \n", collectionMapping.ScopedName, null); } 84 | 85 | output.AppendFormat("{0} : {1} \n", collectionMapping.ScopedName, collectionValue.Count); 86 | 87 | for (var i = 0; i < collectionValue.Count; i++) 88 | { 89 | var currentData = collectionValue[i]; 90 | if (collectionMapping.InternalMappings.Count > 0) 91 | { 92 | var result = Serialize(collectionMapping.InternalMappings, currentData); 93 | output.Append(result); 94 | } 95 | else 96 | { 97 | output.AppendFormat("{0} : {1} \n", collectionMapping.ScopedName + ".value", currentData); 98 | } 99 | } 100 | 101 | return output.ToString(); 102 | } 103 | 104 | private string SerializeDictionary(DictionaryMapping dictionaryMapping, T data) 105 | { 106 | var output = new StringBuilder(); 107 | var dictionaryValue = dictionaryMapping.GetValue(data); 108 | 109 | if (dictionaryValue == null) { return string.Format("{0} : {1} \n", dictionaryMapping.ScopedName, null); } 110 | 111 | output.AppendFormat("{0} : {1} \n", dictionaryMapping.ScopedName, dictionaryValue.Count); 112 | 113 | foreach (var currentKey in dictionaryValue.Keys) 114 | { 115 | if (dictionaryMapping.KeyMappings.Count > 0) 116 | { 117 | var result = Serialize(dictionaryMapping.KeyMappings, currentKey); 118 | output.Append(result); 119 | } 120 | else 121 | { 122 | output.AppendFormat("{0} : {1} \n", dictionaryMapping.ScopedName + ".key", currentKey); 123 | } 124 | 125 | var currentValue = dictionaryValue[currentKey]; 126 | if (dictionaryMapping.ValueMappings.Count > 0) 127 | { 128 | var result = Serialize(dictionaryMapping.ValueMappings, currentValue); 129 | output.Append(result); 130 | } 131 | else 132 | { 133 | output.AppendFormat("{0} : {1} \n", dictionaryMapping.ScopedName + ".value", currentValue); 134 | } 135 | } 136 | 137 | return output.ToString(); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /src/LazyData/Serialization/IDeserializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LazyData.Serialization 4 | { 5 | public interface IDeserializer 6 | { 7 | object Deserialize(DataObject data, Type type = null); 8 | T Deserialize(DataObject data) where T : new(); 9 | 10 | void DeserializeInto(DataObject data, object existingInstance); 11 | void DeserializeInto(DataObject data, T existingInstance); 12 | } 13 | } -------------------------------------------------------------------------------- /src/LazyData/Serialization/IPrimitiveHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LazyData.Mappings.Types.Primitives.Checkers; 3 | 4 | namespace LazyData.Serialization 5 | { 6 | public interface IPrimitiveHandler 7 | { 8 | IPrimitiveChecker PrimitiveChecker { get; } 9 | void Serialize(Tin state, object data, Type type); 10 | object Deserialize(Tout state, Type type); 11 | } 12 | } -------------------------------------------------------------------------------- /src/LazyData/Serialization/ISerializer.cs: -------------------------------------------------------------------------------- 1 | namespace LazyData.Serialization 2 | { 3 | public interface ISerializer 4 | { 5 | DataObject Serialize(object data, bool persistType = false); 6 | } 7 | } --------------------------------------------------------------------------------