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}