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> {}