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