Serialize
Types implement Serialize
separately from Archive
. Serialize
creates a resolver for some
object, then Archive
turns the value and that resolver into an archived type. Having a separate
Serialize
trait is necessary because although a type may have only one archived representation,
it may support many different types of serializers which fulfill its requirements.
The
Serialize
trait is parameterized over the serializer. The serializer is just a mutable object that helps the type serialize itself. The most basic types likeu32
orchar
don't bound their serializer type because they can serialize themselves with any kind of serializer. More complex types likeBox
andString
require a serializer that implementsWriter
, and even more complex types likeRc
andVec
require a serializer that additionally implementsSharing
orAllocator
.
Unlike Serialize
, Archive
doesn't parameterize over the serializer used to make it. It shouldn't
matter what serializer a resolver was made with, only that it's made correctly.
Serializer
rkyv provides default serializers which can serialize all standard library types, as well as components which can be combined into custom-built serializers. By combining rkyv's provided components, serializers can be customized for high-performance, no-std, and custom allocation.
When using the high-level API, a HighSerializer
provides a good balance of flexibility and
performance by default. When using the low-level API, a LowSerializer
does the same without any
allocations. You can make custom serializers using the Serializer
combinator, or by writing your
own from scratch.
rkyv comes with a few primary serializer traits built-in:
Positional
This core serializer trait provides positional information during serialization. Because types need
to know the relative distance between objects, the Positional
trait provides the current position
of the "write head" of the serializer. Resolvers will often store the position of some serialized
data so that a relative pointer can be calculated to it during resolve
.
Writer
Writer
accepts byte slices and writes them to some output. It is similar to the standard library's
Write
trait, but rkyv's Writer
trait works in no-std contexts. In rkyv, writers are always
write-forward - they never backtrack and rewrite data later. This makes it possible for writers to
eagerly sink bytes to disk or the network without having to first buffer the entire message.
Several kinds of Writer
s are supported by default:
Vec<u8>
AlignedVec
, which is a highly-aligned vector of bytes. This is the writer rkyv uses by default in most cases.Buffer
, which supports no-std use cases (for example, writing into fixed-size stack memory).- Types which implement
std::io::Write
can be adapted into aWriter
by wrapping them in theIoWriter
type.
Allocator
Many types require temporarily-allocated space during serialization. This space is used temporarily,
and then returned to the serializer before serialization finishes. For example, Vec
might request
a dynamically-sized allocation to store the resolvers for its elements until it finishes serializing
all of them. Allocating memory from the serializer allows the same bytes to be efficiently reused
many times, which reduces the number of slow memory allocations performed during serialization.
Sharing
rkyv serializes shared pointers like Rc
and Arc
and can control whether they are de-duplicated.
The Sharing
trait provides some mutable state on the serializer which keeps track of which shared
pointers have been serialized so far, and can instruct repeated shared pointers to point to a
previously-serialized instance. This also allows rkyv to preserve shared pointers during zero-copy
access and deserialization.