vector_buffers/encoding.rs
1use std::error;
2
3use bytes::{Buf, BufMut};
4
5/// Converts back and forth between user-friendly metadata types and the on-disk integer representation.
6pub trait AsMetadata: Sized {
7 /// Converts this metadata value into its integer representation.
8 fn into_u32(self) -> u32;
9
10 /// Converts an integer representation of metadata into its real type, if possible.
11 ///
12 /// If the given integer does not represent a valid representation of the given metadata type,
13 /// possibly due to including bits not valid for the type, and so on, then `None` will be
14 /// returned. Otherwise, `Some(Self)` will be returned.
15 fn from_u32(value: u32) -> Option<Self>;
16}
17
18impl AsMetadata for () {
19 fn into_u32(self) -> u32 {
20 0
21 }
22
23 fn from_u32(_: u32) -> Option<Self> {
24 Some(())
25 }
26}
27
28/// An object that can encode and decode itself to and from a buffer.
29///
30/// # Metadata
31///
32/// While an encoding implementation is typically fixed i.e. `MyJsonEncoderType` only encodes and
33/// decodes JSON, we want to provide the ability to change encodings and schemas over time without
34/// fundamentally changing all of the code in the buffer implementations.
35///
36/// We provide the ability to express "metadata" about the encoding implementation such that any
37/// relevant information can be included alongside the encoded object, and then passed back when
38/// decoding is required.
39///
40/// ## Implementation
41///
42/// As designed, an implementor would define a primary encoding scheme, schema version, and so on,
43/// that matched how an object would be encoded. This is acquired from `get_metadata` by code that
44/// depends on `Encodable` and will be stored alongside the encoded object. When the encoded object
45/// is later read back, and the caller wants to decode it, they would also read the metadata and do
46/// two things: check that the metadata is still valid for this implementation by calling
47/// `can_decode` and then pass it along to the `decode` call itself.
48///
49/// ## Verifying ability to decode
50///
51/// Calling `can_decode` first allows callers to check if the encoding implementation supports the
52/// parameters used to encode the given object, which provides a means to allow for versioning,
53/// schema evolution, and more. Practically speaking, an implementation might bump the version of
54/// its schema, but still support the old version for some time, and so `can_decode` might simply
55/// check that the metadata represents the current version of the schema, or the last version, but
56/// no other versions would be allowed. When the old version of the schema was finally removed and
57/// no longer supported, `can_decode` would no longer say it could decode any object whose metadata
58/// referenced that old version.
59///
60/// The `can_decode` method is provided separately, instead of being lumped together in the `decode`
61/// call, as a means to distinguish a lack of decoding support for a given metadata from a general
62/// decoding failure.
63///
64/// ## Metadata-aware decoding
65///
66/// Likewise, the call to `decode` is given the metadata that was stored with the encoded object so
67/// that it knows exactly what parameters were originally used and thus how it needs approach
68/// decoding the object.
69///
70/// ## Metadata format and meaning
71///
72/// Ostensibly, the metadata would represent either some sort of numeric version identifier, or
73/// could be used in a bitflags-style fashion, where each bit represents a particular piece of
74/// information: encoding type, schema version, whether specific information is present in the
75/// encoded object, and so on.
76pub trait Encodable: Sized {
77 type Metadata: AsMetadata + Copy;
78 type EncodeError: error::Error + Send + Sync + 'static;
79 type DecodeError: error::Error + Send + Sync + 'static;
80
81 /// Gets the version metadata associated with this encoding scheme.
82 ///
83 /// The value provided is ostensibly used as a bitfield-esque container, or potentially as a raw
84 /// numeric version identifier, that identifies how a value was encoded, as well as any other
85 /// information that may be necessary to successfully decode it.
86 fn get_metadata() -> Self::Metadata;
87
88 /// Whether or not this encoding scheme can understand and successfully decode a value based on
89 /// the given version metadata that was bundled with the value.
90 fn can_decode(metadata: Self::Metadata) -> bool;
91
92 /// Attempts to encode this value into the given buffer.
93 ///
94 /// # Errors
95 ///
96 /// If there is an error while attempting to encode this value, an error variant will be
97 /// returned describing the error.
98 ///
99 /// Practically speaking, based on the API, encoding errors should generally only occur if there
100 /// is insufficient space in the buffer to fully encode this value. However, this is not
101 /// guaranteed.
102 fn encode<B: BufMut>(self, buffer: &mut B) -> Result<(), Self::EncodeError>;
103
104 /// Gets the encoded size, in bytes, of this value, if available.
105 ///
106 /// Not all types can know ahead of time how many bytes they will occupy when encoded, hence the
107 /// fallibility of this method.
108 fn encoded_size(&self) -> Option<usize> {
109 None
110 }
111
112 /// Attempts to decode an instance of this type from the given buffer and metadata.
113 ///
114 /// # Errors
115 ///
116 /// If there is an error while attempting to decode a value from the given buffer, or the given
117 /// metadata is not valid for the implementation, an error variant will be returned describing
118 /// the error.
119 fn decode<B: Buf + Clone>(
120 metadata: Self::Metadata,
121 buffer: B,
122 ) -> Result<Self, Self::DecodeError>;
123}
124
125/// An object that can encode and decode itself to and from a buffer, with a fixed representation.
126///
127/// This trait is a companion trait to `Encodable` that provides a blanket implementation of
128/// `Encodable` that does not use or care about encoding metadata. It fulfills the necessary
129/// methods to work in `Encodable` contexts without requiring any of the boilerplate.
130///
131/// ## Warning
132///
133/// You should _not_ typically use this trait unless you're trying to implement `Encodable` for
134/// testing purposes where you won't be dealing with a need for versioning payloads, etc.
135///
136/// For any types that will potentially be encoded in real use cases, `Encodable` should be
137/// preferred as it requires an upfront decision to be made about metadata and how it's dealt with.
138pub trait FixedEncodable {
139 type EncodeError: error::Error + Send + Sync + 'static;
140 type DecodeError: error::Error + Send + Sync + 'static;
141
142 /// Attempts to encode this value into the given buffer.
143 ///
144 /// # Errors
145 ///
146 /// If there is an error while attempting to encode this value, an error variant will be
147 /// returned describing the error.
148 ///
149 /// Practically speaking, based on the API, encoding errors should generally only occur if there
150 /// is insufficient space in the buffer to fully encode this value. However, this is not
151 /// guaranteed.
152 fn encode<B: BufMut>(self, buffer: &mut B) -> Result<(), Self::EncodeError>;
153
154 /// Gets the encoded size, in bytes, of this value, if available.
155 ///
156 /// Not all types can know ahead of time how many bytes they will occupy when encoded, hence the
157 /// fallibility of this method.
158 fn encoded_size(&self) -> Option<usize> {
159 None
160 }
161
162 /// Attempts to decode an instance of this type from the given buffer.
163 ///
164 /// # Errors
165 ///
166 /// If there is an error while attempting to decode a value from the given buffer, an error
167 /// variant will be returned describing the error.
168 fn decode<B: Buf + Clone>(buffer: B) -> Result<Self, Self::DecodeError>
169 where
170 Self: Sized;
171}
172
173impl<T: FixedEncodable> Encodable for T {
174 type Metadata = ();
175 type EncodeError = <T as FixedEncodable>::EncodeError;
176 type DecodeError = <T as FixedEncodable>::DecodeError;
177
178 fn get_metadata() -> Self::Metadata {}
179
180 fn can_decode((): Self::Metadata) -> bool {
181 true
182 }
183
184 fn encode<B: BufMut>(self, buffer: &mut B) -> Result<(), Self::EncodeError> {
185 FixedEncodable::encode(self, buffer)
186 }
187
188 fn encoded_size(&self) -> Option<usize> {
189 FixedEncodable::encoded_size(self)
190 }
191
192 fn decode<B: Buf + Clone>((): Self::Metadata, buffer: B) -> Result<Self, Self::DecodeError> {
193 <Self as FixedEncodable>::decode(buffer)
194 }
195}