musli_wire/
encoding.rs

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