Ceras 3.0.2 got released on NuGet, and there are a lot of new features.
A few things from the previous post didn’t make it, but the most important stuff (the things you’re probably most excited about) did 😀
Word of warning though: This is release is a “breaking change“. Which means if you saved any data serialized using Ceras into a file, this new version won’t be able to load it. Yeah, I know, breaking changes suck a bit, but they’re worth the performance improvements! 🙂 Also, upgrading your data is easy, just load the data using the old version, then save it using the new version, that’s it. This will most likely be the last breaking change though!
- Massive performance improvements
After implementing all the most wanted features I started a big optimization run, and the results are pretty intense.
Earlier benchmarks with other serializers (for example ‘MessagePack-CSharp’) had Ceras at ~3.9x the time taken compared to the fastest.
That was obviously pretty slow. But then again, Ceras also does one hell of a lot more than other serializers.
Anyway, after all the optimizations in the last days and weeks we’re now the fastest; improving our old time-factor to roughly ~0.9x compared to MessagePack-CSharp!
That’s a huge improvement.
I encourage you to run the benchmarks yourself though. Every situation is different, and your own data, settings, CPU, and requirements might change things a lot.
Yes, full support for every commonly used type in
UnityEngine. In order to use it, just copy the whole
Extension.csinto your Unity project.
If you’re a complete beginner then you probably want to read the few sentence I wrote into the readme file here as well.
Improved dependency injection for custom IFormatters
In the previous version – if you wanted to reference other formatters – you always had to have field types like
IFormatter<...>which made it impossible to get a specific type of formatter and thus also had a (small) impact on performance (since the runtime needed to do an interface dispatch).
Now you can explicitly request a formatter type like
public Int32Formatter IntFormatter;.
This is especially useful if you have multiple custom formatters that you provide to Ceras and you want them to be able to reference each other directly.
Formatter constructed types
Continuing on with custom
IFormatter<>implementations. In the past there was no way to let Ceras deserialize types that have no public parameterless constructor because it always wants to give you an instance. Now you can explicitly mark types as constructed by the formatter by calling:
That will make it so Ceras will no longer construct this type, so you can do it yourself in your custom IFormatter.
Very useful when dealing with immuable types!
As you know
Dictionary<>, and some more collections have a constructor that takes a “capacity” argument, which makes populating the collection much more efficient if you know how many entries it will get beforehand.
Ceras will now take advantage of those constructors and use them whenever possible; resulting in another performance improvement!
In order to keep the already pretty large
SerializerConfigfrom completely overwhelming beginners, many settings have been moved into the
That’s really all there is to it. If you’re missing anything now, it has been moved there.
Previously Ceras’ powerful
DynamicObjectFormatterhandled those two types, but that could cause problems in some rare scenarios (where you’d set an incompatible
DefaultTargets), which you could only resolve by manually specifying the rules for those types. None of those workarounds are needed anymore!
To protect against corrupted/malicious data, Ceras now has settings to limit how large content can be.
Take a look at
config.Advanced.SizeLimits, there you can limit how large strings, arrays, collections and byte-arrays (as a special case) are allowed to be.
Any inputs that exceed those limits will trigger an exception.
As you know Ceras perfectly handles full object-graphs, meaning automatically does things like maintaining object identity/references, resolving and handling circular references, …
However getting some feedback I realized that many people actually don’t really need that much functionality, and would like to be able to trade those features for more performance. So now you can!
config.PreserveReferences = false;Ceras will become like most other serializers (becoming a “tree-serializer”).
This skips over some code related to reference handling and give you a small performance boost.
But it obviously comes with the downsides of such an approach as well (which is simply crashing with a
StackOverflowExceptionshould the object you’re serializing have any “reference loops”).
Ceras now respects the
In order to restore the old funcionality (where Ceras simply ignores the attribute) you can simply set
config.RespectNonSerializedAttribute = false;.
Those improvements are mostly internal, but I thought I’d just include them as well.
Most of you have been using the
Membersmode of the readonly field handling feature (which just overwrites the content of a class, where just the reference to the class itself is readonly). For this scenario I’ve managed to improve the performance a bit and got rid of all allocations.
ForcedOverwrite(where readonly fields are serialized and deserialized as if they were not readonly at all) nothing has changed.
Ceras can now serialize delegates.
There are some reasonable limitations to it, so if you actually have a more advance use-case, then let me know!
This new feature also comes with a setting to turn the functionality on or off (off being the default for security reasons).
There are some features that didn’t make it. Luckily those were just minor ones:
- Static object pooling surprisingly turned out to (mostly) not be worth the effort. Maybe I’ll revisit that idea later.
- For the so called “Merge batching” it turns out that this idea would break custom formatters, so no luck there. Maybe I’ll find a way to make it work later.