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