packet/
util.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::ops::Deref;
6
7use zerocopy::SplitByteSlice;
8
9use crate::BufferView;
10
11/// A packet that can be created from a raw form.
12///
13/// `FromRaw` provides a common interface for packets that can be created from
14/// an "unchecked" form - that is, that are parsed raw without any higher-order
15/// validation.
16///
17/// The type parameter `R` is the raw type that the `FromRaw` type can be
18/// converted from, given some arguments of type `A`.
19pub trait FromRaw<R, A>: Sized {
20    /// The type of error that may happen during validation.
21    type Error;
22
23    /// Attempts to create `Self` from the raw form in `raw` with `args`.
24    fn try_from_raw_with(raw: R, args: A) -> Result<Self, Self::Error>;
25
26    /// Attempts to create `Self` from the raw form in `raw`.
27    fn try_from_raw(raw: R) -> Result<Self, <Self as FromRaw<R, A>>::Error>
28    where
29        Self: FromRaw<R, (), Error = <Self as FromRaw<R, A>>::Error>,
30    {
31        Self::try_from_raw_with(raw, ())
32    }
33}
34
35/// A type that encapsulates the result of a complete or incomplete parsing
36/// operation.
37///
38/// The type parameters `C` and `I` are the types for a "complete" and
39/// "incomplete" parsing result, respectively.
40#[derive(Copy, Clone, Debug, Eq, PartialEq)]
41pub enum MaybeParsed<C, I> {
42    Complete(C),
43    Incomplete(I),
44}
45
46impl<T> MaybeParsed<T, T> {
47    /// Creates a `MaybeParsed` instance with `bytes` observing a minimum
48    /// length `min_len`.
49    ///
50    /// Returns [`MaybeParsed::Complete`] if `bytes` is at least `min_len` long,
51    /// otherwise returns [`MaybeParsed::Incomplete`]. In both cases, `bytes`
52    /// is moved into one of the two `MaybeParsed` variants.
53    pub fn new_with_min_len(bytes: T, min_len: usize) -> Self
54    where
55        T: SplitByteSlice,
56    {
57        if bytes.len() >= min_len {
58            MaybeParsed::Complete(bytes)
59        } else {
60            MaybeParsed::Incomplete(bytes)
61        }
62    }
63
64    /// Consumes this `MaybeParsed` and returns its contained value if both the
65    /// `Complete` and `Incomplete` variants contain the same type.
66    pub fn into_inner(self) -> T {
67        match self {
68            MaybeParsed::Complete(c) => c,
69            MaybeParsed::Incomplete(i) => i,
70        }
71    }
72}
73
74impl<C, I> MaybeParsed<C, I> {
75    /// Creates a `MaybeParsed` instance taking `n` bytes from the front of
76    /// `buf` and mapping with `map`.
77    ///
78    /// If `buf` contains at least `n` bytes, then `n` bytes are consumed from
79    /// the beginning of `buf`, those `n` bytes are passed to `map`, and the
80    /// result is returned as [`MaybeParsed::Complete`]. Otherwise, all bytes
81    /// are consumed from `buf` and returned as [`MaybeParsed::Incomplete`].
82    pub fn take_from_buffer_with<BV: BufferView<I>, F>(buf: &mut BV, n: usize, map: F) -> Self
83    where
84        F: FnOnce(I) -> C,
85        I: SplitByteSlice,
86    {
87        if let Some(v) = buf.take_front(n) {
88            MaybeParsed::Complete(map(v))
89        } else {
90            MaybeParsed::Incomplete(buf.take_rest_front())
91        }
92    }
93
94    /// Maps a [`MaybeParsed::Complete`] variant to another type.
95    ///
96    /// If `self` is [`MaybeParsed::Incomplete`], it is left as-is.
97    pub fn map<M, F>(self, f: F) -> MaybeParsed<M, I>
98    where
99        F: FnOnce(C) -> M,
100    {
101        match self {
102            MaybeParsed::Incomplete(v) => MaybeParsed::Incomplete(v),
103            MaybeParsed::Complete(v) => MaybeParsed::Complete(f(v)),
104        }
105    }
106
107    /// Maps a [`MaybeParsed::Incomplete`] variant to another type.
108    ///
109    /// If `self` is [`MaybeParsed::Complete`], it is left as-is.
110    pub fn map_incomplete<M, F>(self, f: F) -> MaybeParsed<C, M>
111    where
112        F: FnOnce(I) -> M,
113    {
114        match self {
115            MaybeParsed::Incomplete(v) => MaybeParsed::Incomplete(f(v)),
116            MaybeParsed::Complete(v) => MaybeParsed::Complete(v),
117        }
118    }
119
120    /// Converts from `&MaybeParsed<C, I>` to `MaybeParsed<&C, &I>`.
121    pub fn as_ref(&self) -> MaybeParsed<&C, &I> {
122        match self {
123            MaybeParsed::Incomplete(v) => MaybeParsed::Incomplete(v),
124            MaybeParsed::Complete(v) => MaybeParsed::Complete(v),
125        }
126    }
127
128    /// Transforms `self` into a [`Result`], mapping the [`Complete`] variant
129    /// into [`Ok`].
130    ///
131    /// [`Complete`]: Self::Complete
132    /// [`Ok`]: Result::Ok
133    pub fn complete(self) -> Result<C, I> {
134        match self {
135            MaybeParsed::Complete(v) => Ok(v),
136            MaybeParsed::Incomplete(v) => Err(v),
137        }
138    }
139
140    /// Transforms `self` into a [`Result`], mapping the [`Incomplete`] variant
141    /// into [`Ok`].
142    ///
143    /// [`Incomplete`]: Self::Incomplete
144    /// [`Ok`]: Result::Ok
145    pub fn incomplete(self) -> Result<I, C> {
146        match self {
147            MaybeParsed::Complete(v) => Err(v),
148            MaybeParsed::Incomplete(v) => Ok(v),
149        }
150    }
151
152    /// Transforms this `MaybeIncomplete` into a [`Result`] where the
153    /// [`Complete`] variant becomes [`Ok`] and the [`Incomplete`] variant is
154    /// passed through `f` and mapped to [`Err`].
155    ///
156    /// [`Complete`]: Self::Complete
157    /// [`Incomplete`]: Self::Incomplete
158    /// [`Ok`]: Result::Ok
159    /// [`Err`]: Result::Err
160    pub fn ok_or_else<F, E>(self, f: F) -> Result<C, E>
161    where
162        F: FnOnce(I) -> E,
163    {
164        match self {
165            MaybeParsed::Complete(v) => Ok(v),
166            MaybeParsed::Incomplete(v) => Err(f(v)),
167        }
168    }
169}
170
171impl<C, I> MaybeParsed<C, I>
172where
173    C: Deref<Target = [u8]>,
174    I: Deref<Target = [u8]>,
175{
176    /// Returns the length in bytes of the contained data.
177    pub fn len(&self) -> usize {
178        match self {
179            MaybeParsed::Incomplete(v) => v.deref().len(),
180            MaybeParsed::Complete(v) => v.deref().len(),
181        }
182    }
183
184    /// Returns whether the contained data is empty - zero bytes long.
185    pub fn is_empty(&self) -> bool {
186        self.len() == 0
187    }
188}
189
190#[cfg(test)]
191mod tests {
192    use super::*;
193
194    impl<T> MaybeParsed<T, T> {
195        /// Creates a `MaybeParsed` instance taking `n` bytes from the front of
196        /// `buff`.
197        ///
198        /// Returns [`MaybeParsed::Complete`] with `n` bytes if `buff` contains at
199        /// least `n` bytes. Otherwise returns [`MaybeParsed::Incomplete`] greedily
200        /// taking all the remaining bytes from `buff`
201        #[cfg(test)]
202        pub fn take_from_buffer<BV: BufferView<T>>(buff: &mut BV, n: usize) -> Self
203        where
204            T: SplitByteSlice,
205        {
206            if let Some(v) = buff.take_front(n) {
207                MaybeParsed::Complete(v)
208            } else {
209                MaybeParsed::Incomplete(buff.take_rest_front())
210            }
211        }
212    }
213
214    #[test]
215    fn test_maybe_parsed_take_from_buffer() {
216        let buff = [1_u8, 2, 3, 4];
217        let mut bv = &mut &buff[..];
218        assert_eq!(MaybeParsed::take_from_buffer(&mut bv, 2), MaybeParsed::Complete(&buff[..2]));
219        assert_eq!(MaybeParsed::take_from_buffer(&mut bv, 3), MaybeParsed::Incomplete(&buff[2..]));
220    }
221
222    #[test]
223    fn test_maybe_parsed_min_len() {
224        let buff = [1_u8, 2, 3, 4];
225        assert_eq!(MaybeParsed::new_with_min_len(&buff[..], 3), MaybeParsed::Complete(&buff[..]));
226        assert_eq!(MaybeParsed::new_with_min_len(&buff[..], 5), MaybeParsed::Incomplete(&buff[..]));
227    }
228
229    #[test]
230    fn test_maybe_parsed_take_from_buffer_with() {
231        let buff = [1_u8, 2, 3, 4];
232        let mut bv = &mut &buff[..];
233        assert_eq!(
234            MaybeParsed::take_from_buffer_with(&mut bv, 2, |x| Some(usize::from(x[0] + x[1]))),
235            MaybeParsed::Complete(Some(3)),
236        );
237        assert_eq!(
238            MaybeParsed::take_from_buffer_with(&mut bv, 3, |_| panic!("map shouldn't be called")),
239            MaybeParsed::Incomplete(&buff[2..]),
240        );
241    }
242
243    #[test]
244    fn test_maybe_parsed_map() {
245        assert_eq!(
246            MaybeParsed::<&str, ()>::Complete("hello").map(|x| format!("{} you", x)),
247            MaybeParsed::Complete("hello you".to_string()),
248        );
249        assert_eq!(
250            MaybeParsed::<(), &str>::Incomplete("hello").map(|_| panic!("map shouldn't be called")),
251            MaybeParsed::Incomplete("hello"),
252        );
253    }
254
255    #[test]
256    fn test_maybe_parsed_len() {
257        let buff = [1_u8, 2, 3, 4];
258        let mp1 = MaybeParsed::new_with_min_len(&buff[..], 2);
259        let mp2 = MaybeParsed::new_with_min_len(&buff[..], 10);
260        assert_eq!(mp1.len(), 4);
261        assert_eq!(mp2.len(), 4);
262    }
263}