musli_storage/
encoding.rs

1//! Module that defines [`Encoding`] whith allows for customization of the
2//! encoding format, and the [`DEFAULT`] encoding configuration.
3
4#[cfg(feature = "alloc")]
5use alloc::vec::Vec;
6use core::marker;
7#[cfg(feature = "std")]
8use std::io;
9
10use musli::de::Decode;
11use musli::en::Encode;
12use musli::mode::Binary;
13use musli::Context;
14use musli_utils::fixed::FixedBytes;
15use musli_utils::options::{self, Options};
16use musli_utils::{Reader, Writer};
17
18use crate::de::StorageDecoder;
19use crate::en::StorageEncoder;
20use crate::error::Error;
21
22/// Default options to use with [`Encoding`].
23pub const OPTIONS: Options = options::new().build();
24
25/// The default configuration.
26///
27/// Uses variable-encoded numerical fields and variable-encoded prefix lengths.
28///
29/// The variable length encoding uses [`zigzag`] with [`continuation`] encoding
30/// for numbers.
31///
32/// [`zigzag`]: musli_utils::int::zigzag
33/// [`continuation`]: musli_utils::int::continuation
34pub const DEFAULT: Encoding = Encoding::new();
35
36/// Encode the given value to the given [`Writer`] using the [`DEFAULT`]
37/// configuration.
38#[inline]
39pub fn encode<W, T>(writer: W, value: &T) -> Result<(), Error>
40where
41    W: Writer,
42    T: ?Sized + Encode<Binary>,
43{
44    DEFAULT.encode(writer, value)
45}
46
47/// Encode the given value to the given [Write][io::Write] using the [`DEFAULT`]
48/// configuration.
49#[cfg(feature = "std")]
50#[inline]
51pub fn to_writer<W, T>(writer: W, value: &T) -> Result<(), Error>
52where
53    W: io::Write,
54    T: ?Sized + Encode<Binary>,
55{
56    DEFAULT.to_writer(writer, value)
57}
58
59/// Encode the given value to a [`Vec`] using the [`DEFAULT`] configuration.
60#[cfg(feature = "alloc")]
61#[inline]
62pub fn to_vec<T>(value: &T) -> Result<Vec<u8>, Error>
63where
64    T: ?Sized + Encode<Binary>,
65{
66    DEFAULT.to_vec(value)
67}
68
69/// Encode the given value to a fixed-size bytes using the [`DEFAULT`]
70/// configuration.
71#[inline]
72pub fn to_fixed_bytes<const N: usize, T>(value: &T) -> Result<FixedBytes<N>, Error>
73where
74    T: ?Sized + Encode<Binary>,
75{
76    DEFAULT.to_fixed_bytes::<N, _>(value)
77}
78
79/// Decode the given type `T` from the given [`Reader`] using the [`DEFAULT`]
80/// configuration.
81#[inline]
82pub fn decode<'de, R, T>(reader: R) -> Result<T, Error>
83where
84    R: Reader<'de>,
85    T: Decode<'de, Binary>,
86{
87    DEFAULT.decode(reader)
88}
89
90/// Decode the given type `T` from the given slice using the [`DEFAULT`]
91/// configuration.
92#[inline]
93pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T, Error>
94where
95    T: Decode<'de, Binary>,
96{
97    DEFAULT.from_slice(bytes)
98}
99
100/// Setting up encoding with parameters.
101pub struct Encoding<const OPT: Options = OPTIONS, M = Binary> {
102    _marker: marker::PhantomData<M>,
103}
104
105impl Encoding<OPTIONS, Binary> {
106    /// Construct a new [`Encoding`] instance which uses [`OPTIONS`].
107    ///
108    /// You can modify this behavior by using a custom [`Options`] instance:
109    ///
110    /// ```
111    /// use musli::{Encode, Decode};
112    /// use musli_utils::options::{self, Options, Integer};
113    /// use musli_storage::Encoding;
114    ///
115    /// const OPTIONS: Options = options::new().with_integer(Integer::Fixed).build();
116    /// const CONFIG: Encoding<OPTIONS> = Encoding::new().with_options();
117    ///
118    /// #[derive(Debug, PartialEq, Encode, Decode)]
119    /// struct Struct<'a> {
120    ///     name: &'a str,
121    ///     age: u32,
122    /// }
123    ///
124    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
125    /// let mut out = Vec::new();
126    ///
127    /// let expected = Struct {
128    ///     name: "Aristotle",
129    ///     age: 61,
130    /// };
131    ///
132    /// CONFIG.encode(&mut out, &expected)?;
133    /// let actual = CONFIG.decode(&out[..])?;
134    ///
135    /// assert_eq!(expected, actual);
136    /// # Ok(()) }
137    /// ```
138    pub const fn new() -> Self {
139        Encoding {
140            _marker: marker::PhantomData,
141        }
142    }
143}
144
145impl<const OPT: Options, M> Encoding<OPT, M> {
146    /// Change the mode of the encoding.
147    ///
148    /// # Examples
149    ///
150    /// ```rust
151    /// use musli_storage::{OPTIONS, Encoding};
152    ///
153    /// enum Custom {}
154    ///
155    /// const CONFIG: Encoding<OPTIONS, Custom> = Encoding::new().with_mode();
156    /// ```
157    pub const fn with_mode<T>(self) -> Encoding<OPT, T> {
158        Encoding {
159            _marker: marker::PhantomData,
160        }
161    }
162
163    /// Change the options of the encoding.
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// use musli_utils::options::{self, Options, Integer};
169    /// use musli_storage::Encoding;
170    ///
171    /// const OPTIONS: Options = options::new().with_integer(Integer::Fixed).build();
172    /// const CONFIG: Encoding<OPTIONS> = Encoding::new().with_options();
173    /// ```
174    pub const fn with_options<const U: Options>(self) -> Encoding<U, M> {
175        Encoding {
176            _marker: marker::PhantomData,
177        }
178    }
179
180    musli_utils::encoding_impls!(
181        M,
182        StorageEncoder::<_, OPT, _>::new,
183        StorageDecoder::<_, OPT, _>::new
184    );
185    musli_utils::encoding_from_slice_impls!(M);
186}
187
188impl<const OPT: Options, M> Clone for Encoding<OPT, M> {
189    #[inline]
190    fn clone(&self) -> Self {
191        *self
192    }
193}
194
195impl<const OPT: Options, M> Copy for Encoding<OPT, M> {}