tokio_util_codec_compose/decode/
mod.rs

1//! A set of compositional operations on [`Decoder`].
2//!
3//! The operations take simpler decoders as inputs with customization functions and produce more powerful ones as output.
4
5pub mod adaptors;
6
7use self::adaptors::{
8    DecoderAndThen, DecoderBoxed, DecoderMap, DecoderMapErr, DecoderMapInto, DecoderThen,
9    DecoderTryMap, DecoderTryMapInto,
10};
11
12use tokio_util::codec::Decoder;
13
14/// Extension of [`Decoder`] with compositional operations.
15pub trait DecoderExt<A, E>: Decoder<Item = A, Error = E> {
16    /// Applies a function `f` of type `A -> B` over the decoded value when that is `Ok(Some(a))`.
17    ///
18    /// The function `f` cannot fail. If you need a fallible mapping, then consider [`DecoderExt::try_map`].
19    ///
20    /// # Examples
21    ///
22    /// ```
23    /// # use tokio_util::codec::Decoder;
24    /// # use bytes::BytesMut;
25    /// use tokio_util_codec_compose::{decode::DecoderExt, primitives::uint8};
26    ///
27    /// # #[derive(Debug, PartialEq, Eq)]
28    /// struct Device(u8);
29    ///
30    /// let device = uint8().map(Device).decode(&mut BytesMut::from("\x2A")).unwrap();
31    /// assert_eq!(device, Some(Device(42)));
32    /// ```
33    fn map<F, B>(self, f: F) -> DecoderMap<Self, F>
34    where
35        F: Fn(A) -> B,
36        Self: Sized,
37    {
38        DecoderMap::new(self, f)
39    }
40
41    /// Applies an `B::from` `A` conversion over the decoded value when that is `Ok(Some(a))`.
42    ///
43    /// The conversion cannot fail. If you need a fallible conversion, then consider [`DecoderExt::try_map_into`].
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// # use tokio_util::codec::Decoder;
49    /// # use bytes::BytesMut;
50    /// use tokio_util_codec_compose::{decode::DecoderExt, primitives::uint8};
51    ///
52    /// # #[derive(Debug, PartialEq, Eq)]
53    /// struct Device(u8);
54    ///
55    /// impl From<u8> for Device {
56    ///     fn from(value: u8) -> Self {
57    ///         Self(value)
58    ///     }
59    /// }
60    ///
61    /// let device = uint8().map_into::<Device>().decode(&mut BytesMut::from("\x2A")).unwrap();
62    /// assert_eq!(device, Some(Device(42)));
63    /// ```
64    fn map_into<B>(self) -> DecoderMapInto<Self, B>
65    where
66        B: From<A>,
67        Self: Sized,
68    {
69        DecoderMapInto::new(self)
70    }
71
72    /// Applies a fallible function `f` of type `A -> Result<B, EE>` over the decoded value when that is `Ok(Some(a))`.
73    ///
74    /// The function `f` can fail and that's handy when we interleave decoding with validation,
75    /// for instance, when mapping from a larger domain (e.g. `u8`) into a smaller co-domain (e.g. `Version::v1`).
76    /// If you don't need a fallible mapping, then consider [`DecoderExt::map`].
77    ///
78    /// The mapping can return an error type `EE` other than `E` as long as there is an implicit conversion [`From<E>`].
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// # use tokio_util::codec::Decoder;
84    /// # use bytes::BytesMut;
85    /// use tokio_util_codec_compose::{decode::DecoderExt, primitives::uint8};
86    ///
87    /// # #[derive(Debug, PartialEq, Eq)]
88    /// enum Version {
89    ///     V1
90    /// }
91    ///
92    /// impl TryFrom<u8> for Version {
93    ///     type Error = std::io::Error;
94    ///
95    ///     fn try_from(value: u8) -> Result<Self, Self::Error> {
96    ///             match value {
97    ///                 1 => Ok(Version::V1),
98    ///                 _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidData))
99    ///             }
100    ///     }
101    /// }
102    ///
103    /// let mut decoder = uint8().try_map(Version::try_from);
104    ///
105    /// let version_ok = decoder.decode(&mut BytesMut::from("\x01")).unwrap();
106    /// assert_eq!(version_ok, Some(Version::V1));
107    ///
108    /// let version_err = decoder.decode(&mut BytesMut::from("\x02")).unwrap_err();
109    /// assert_eq!(version_err.kind(), std::io::ErrorKind::InvalidData);
110    /// ```
111    fn try_map<F, B, EE>(self, f: F) -> DecoderTryMap<Self, F, EE>
112    where
113        F: Fn(A) -> Result<B, EE>,
114        Self: Sized,
115    {
116        DecoderTryMap::new(self, f)
117    }
118
119    /// Applies an `B::try_from` `A` conversion over the decoded value when that is `Ok(Some(a))`.
120    ///
121    /// The conversion can fail and that's handy when we interleave decoding with validation,
122    /// for instance, when mapping from a larger domain (e.g. `u8`) into a smaller co-domain (e.g. `Version::v1`).
123    /// If you don't need a fallible conversion, then consider [`DecoderExt::map`].
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// # use tokio_util::codec::Decoder;
129    /// # use bytes::BytesMut;
130    /// use tokio_util_codec_compose::{decode::DecoderExt, primitives::uint8};
131    ///
132    /// # #[derive(Debug, PartialEq, Eq)]
133    /// enum Version {
134    ///     V1
135    /// }
136    ///
137    /// impl TryFrom<u8> for Version {
138    ///     type Error = std::io::Error;
139    ///
140    ///     fn try_from(value: u8) -> Result<Self, Self::Error> {
141    ///             match value {
142    ///                 1 => Ok(Version::V1),
143    ///                 _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidData))
144    ///             }
145    ///     }
146    /// }
147    ///
148    /// let mut decoder = uint8().try_map_into::<Version>();
149    ///
150    /// let version_ok = decoder.decode(&mut BytesMut::from("\x01")).unwrap();
151    /// assert_eq!(version_ok, Some(Version::V1));
152    ///
153    /// let version_err = decoder.decode(&mut BytesMut::from("\x02")).unwrap_err();
154    /// assert_eq!(version_err.kind(), std::io::ErrorKind::InvalidData);
155    /// ```
156    fn try_map_into<B>(self) -> DecoderTryMapInto<Self, B, B::Error>
157    where
158        B: TryFrom<A>,
159        Self: Sized,
160    {
161        DecoderTryMapInto::new(self)
162    }
163
164    /// Applies a function `f` of type `E -> EE` over the decoding error when that is `Err(e)`.
165    ///
166    /// That's handy when we need to adapt errors across boundaries.
167    ///
168    /// # Examples
169    ///
170    /// ```
171    /// # use tokio_util::codec::Decoder;
172    /// # use bytes::BytesMut;
173    /// use tokio_util_codec_compose::{decode::DecoderExt, primitives::uint8};
174    ///
175    /// fn decoder_operation() -> impl Decoder<Item = Operation, Error = std::io::Error> {
176    /// #   uint8().try_map(|_| Err(std::io::Error::from(std::io::ErrorKind::Other)))
177    /// }
178    ///
179    /// # #[derive(Debug, PartialEq, Eq)]
180    /// enum Operation {
181    ///     TurnOff, Turning
182    /// }
183    ///
184    /// # #[derive(Debug, PartialEq, Eq)]
185    /// struct OperationError;
186    ///
187    /// impl From<std::io::Error> for OperationError {
188    ///     fn from(value: std::io::Error) -> Self {
189    ///         Self
190    ///     }
191    /// }
192    ///
193    /// let err = decoder_operation().map_err(|_| OperationError).decode(&mut BytesMut::from("\x00")); // invalid operation number
194    /// assert_eq!(err, Err(OperationError));
195    /// ```
196    fn map_err<F, EE>(self, f: F) -> DecoderMapErr<Self, F>
197    where
198        F: Fn(E) -> EE,
199        Self: Sized,
200    {
201        DecoderMapErr::new(self, f)
202    }
203
204    /// Chains a decoder of `B` on the *remaining* bytes after applying this decoder, then returns a pair of the individual values `(a, b)`.
205    ///
206    /// This enables the application of decoders in sequence where a step does not depend on its predecessor (when such a dependency exists, consider [`DecoderExt::and_then`].
207    ///
208    /// The next decoder can return an error type `EE` other than `E` as long as there is an implicit conversion [`From<E>`].
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// # use tokio_util::codec::Decoder;
214    /// # use bytes::BytesMut;
215    /// use tokio_util_codec_compose::{decode::DecoderExt, primitives::uint8};
216    ///
217    /// let pair = uint8().then(uint8()).decode(&mut BytesMut::from("\x2A\x3B")).unwrap();
218    ///
219    /// assert_eq!(pair, Some((0x2A, 0x3B)));
220    /// ```
221    // TODO: Flatten resulting tuple.
222    fn then<DNext, B, EE>(self, next: DNext) -> DecoderThen<Self, DNext, A, EE>
223    where
224        DNext: Decoder<Item = B, Error = EE>,
225        EE: From<E>,
226        Self: Sized,
227    {
228        DecoderThen::new(self, next)
229    }
230
231    /// Chains a function `f` of type `&A -> Box<Decoder<Item = B, Error = E>>` over the decoded value when that is `Ok(Some(a))`.
232    ///
233    /// Contrary to [`DecoderExt::map`], the function `f` can decide (dynamically) which decoder to return next according to `a`, which enables complex behaviors
234    /// out of simple building blocks by defining dependency relationships between decoders.
235    /// e.g. first we decode the header of a message and use that information, say protocol version, to then select the appropriate
236    /// decoder among multiple candidates, say one per protocol version, for the body.
237    ///
238    /// The next decoder can return an error type `EE` other than `E` as long as there is an implicit conversion [`From<E>`].
239    ///
240    /// The function `f` cannot fail.
241    ///
242    /// Notice that `f` can't take ownership of the first value `a`, hence the shared borrow, because otherwise it would not be possible to decode incomplete frames
243    /// without cloning or maybe saving incoming bytes and re-running this decoder. If you need access to the first value, use [`DecoderAndThen::first_value`]
244    /// or [`DecoderAndThen::first_value_as_mut`].
245    ///
246    /// # Stateful decoders and multi-frames
247    ///
248    /// Due to the stateful behaviour of this combinator, if you need to decode multiple frames, you'd need to [`DecoderAndThen::reset`] between frames to clean up
249    /// the previous value `a` and therefore its influence on `b`.
250    ///
251    /// # Examples
252    ///
253    /// ```
254    /// # use tokio_util::codec::Decoder;
255    /// # use bytes::BytesMut;
256    /// use tokio_util_codec_compose::{decode::{adaptors::DecoderBoxed, DecoderExt}, primitives::{uint8, uint16_be, uint16_le}};
257    ///
258    /// fn payload_for_version(version: &u8) -> DecoderBoxed<u16, std::io::Error> {
259    ///     if *version == 0x01 { uint16_be().boxed() } else { uint16_le().boxed() }
260    /// }
261    ///
262    /// let mut decoder = uint8().and_then(payload_for_version);
263    ///
264    /// let device_big_endian = decoder.decode(&mut BytesMut::from("\x01\x2A\x3B")).unwrap();
265    /// assert_eq!(device_big_endian, Some(0x2A3B));
266    ///
267    /// decoder.reset();
268    ///
269    /// let device_little_endian = decoder.decode(&mut BytesMut::from("\x00\x2A\x3B")).unwrap();
270    /// assert_eq!(device_little_endian, Some(0x3B2A));
271    /// ```
272    fn and_then<F, DNext, B, EE>(self, f: F) -> DecoderAndThen<Self, F, DNext, A, EE>
273    where
274        F: Fn(&A) -> DNext,
275        DNext: Decoder<Item = B, Error = EE>,
276        EE: From<E>,
277        Self: Sized,
278    {
279        DecoderAndThen::new(self, f)
280    }
281
282    /// Shorthand for boxing this decoder while also widening its type to ease inference and spelling.
283    ///
284    /// That's probably useful when combined with [`DecoderExt::and_then`] where the continuation
285    /// yields decoders with different types.
286    fn boxed(self) -> DecoderBoxed<A, E>
287    where
288        Self: Sized,
289        Self: 'static,
290    {
291        DecoderBoxed::new(self)
292    }
293}
294
295impl<D, A, E> DecoderExt<A, E> for D where D: Decoder<Item = A, Error = E> {}