foundation_ur/ur/
decoder.rs

1// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. <hello@foundationdevices.com>
2// SPDX-FileCopyrightText: © 2020 Dominik Spicher <dominikspicher@gmail.com>
3// SPDX-License-Identifier: MIT
4
5//! Decoder.
6
7use crate::{
8    bytewords::{self, Style},
9    collections::Vec,
10    fountain,
11    ur::UR,
12};
13use core::{fmt, str};
14
15/// A decoder.
16#[cfg(feature = "alloc")]
17pub type Decoder = BaseDecoder<Alloc>;
18
19/// A static decoder.
20///
21/// Does not allocate memory.
22pub type HeaplessDecoder<
23    const MAX_MESSAGE_LEN: usize,
24    const MAX_MIXED_PARTS: usize,
25    const MAX_FRAGMENT_LEN: usize,
26    const MAX_SEQUENCE_COUNT: usize,
27    const QUEUE_SIZE: usize,
28    const MAX_UR_TYPE: usize,
29> = BaseDecoder<
30    Heapless<
31        MAX_MESSAGE_LEN,
32        MAX_MIXED_PARTS,
33        MAX_FRAGMENT_LEN,
34        MAX_SEQUENCE_COUNT,
35        QUEUE_SIZE,
36        MAX_UR_TYPE,
37    >,
38>;
39
40impl<
41        const MAX_MESSAGE_LEN: usize,
42        const MAX_MIXED_PARTS: usize,
43        const MAX_FRAGMENT_LEN: usize,
44        const MAX_SEQUENCE_COUNT: usize,
45        const QUEUE_SIZE: usize,
46        const MAX_UR_TYPE: usize,
47    >
48    HeaplessDecoder<
49        MAX_MESSAGE_LEN,
50        MAX_MIXED_PARTS,
51        MAX_FRAGMENT_LEN,
52        MAX_SEQUENCE_COUNT,
53        QUEUE_SIZE,
54        MAX_UR_TYPE,
55    >
56{
57    /// Construct a new [`HeaplessDecoder`].
58    pub const fn new() -> Self {
59        Self {
60            fountain: fountain::decoder::HeaplessDecoder::new(),
61            fragment: heapless::Vec::new(),
62            ur_type: heapless::Vec::new(),
63        }
64    }
65}
66
67/// A uniform resource decoder able to receive URIs that encode a fountain part.
68///
69/// # Examples
70///
71/// See the [`crate`] module documentation for an example.
72#[derive(Default)]
73pub struct BaseDecoder<T: Types> {
74    fountain: fountain::decoder::BaseDecoder<T::Decoder>,
75    fragment: T::Fragment,
76    ur_type: T::URType,
77}
78
79impl<T: Types> BaseDecoder<T> {
80    /// Receives a URI representing a CBOR and `bytewords`-encoded fountain part
81    /// into the decoder.
82    ///
83    /// # Examples
84    ///
85    /// See the [`crate`] module documentation for examples.
86    ///
87    /// # Errors
88    ///
89    /// This function may error along all the necessary decoding steps:
90    ///  - The string may not be a well-formed URI according to the uniform resource scheme
91    ///  - The URI payload may not be a well-formed `bytewords` string
92    ///  - The decoded byte payload may not be valid CBOR
93    ///  - The CBOR-encoded fountain part may be inconsistent with previously received ones
94    ///
95    /// In all these cases, an error will be returned.
96    pub fn receive(&mut self, ur: UR) -> Result<(), Error> {
97        if !ur.is_multi_part() {
98            return Err(Error::NotMultiPart);
99        }
100
101        if self.ur_type.is_empty() {
102            self.ur_type
103                .try_extend_from_slice(ur.as_type().as_bytes())
104                .map_err(|_| Error::URTypeTooBig {
105                    size: ur.as_type().as_bytes().len(),
106                })?;
107        } else if (&self.ur_type as &[_]) != ur.as_type().as_bytes() {
108            return Err(Error::InconsistentType);
109        }
110
111        let part = if !ur.is_deserialized() {
112            let bytewords = ur
113                .as_bytewords()
114                .expect("resource shouldn't be deserialized at this point");
115
116            let size = bytewords::validate(bytewords, Style::Minimal)?;
117            self.fragment.clear();
118            self.fragment
119                .try_resize(size, 0)
120                .map_err(|_| Error::FragmentTooBig { size })?;
121
122            bytewords::decode_to_slice(bytewords, &mut self.fragment, Style::Minimal)?;
123            Some(minicbor::decode(&self.fragment[..size])?)
124        } else {
125            None
126        };
127
128        let part = part.as_ref().unwrap_or_else(|| ur.as_part().unwrap());
129        self.fountain.receive(part)?;
130        Ok(())
131    }
132
133    /// Returns whether the decoder is complete and hence the message available.
134    ///
135    /// # Examples
136    ///
137    /// See the [`crate`] module documentation for an example.
138    #[must_use]
139    #[inline]
140    pub fn is_complete(&self) -> bool {
141        self.fountain.is_complete()
142    }
143
144    /// Returns the UR type.
145    pub fn ur_type(&self) -> Option<&str> {
146        if !self.ur_type.is_empty() {
147            Some(str::from_utf8(&self.ur_type).unwrap())
148        } else {
149            None
150        }
151    }
152
153    /// If [`complete`], returns the decoded message, `None` otherwise.
154    ///
155    /// # Errors
156    ///
157    /// If an inconsistent internal state is detected, an error will be
158    /// returned.
159    ///
160    /// # Examples
161    ///
162    /// See the [`crate`] documentation for an example.
163    ///
164    /// [`complete`]: BaseDecoder::is_complete
165    #[inline]
166    pub fn message(&self) -> Result<Option<&[u8]>, Error> {
167        self.fountain.message().map_err(Error::from)
168    }
169
170    /// Calculate estimated percentage of completion.
171    #[inline]
172    pub fn estimated_percent_complete(&self) -> f64 {
173        self.fountain.estimated_percent_complete()
174    }
175
176    /// Returns `true` if the decoder doesn't contain any data.
177    ///
178    /// Once a part is successfully [received](Self::receive) this method will
179    /// return `false`.
180    ///
181    /// # Examples
182    ///
183    /// ```
184    /// # use foundation_ur::fountain::HeaplessDecoder;
185    /// let decoder: HeaplessDecoder<8, 8, 8, 8, 8> = HeaplessDecoder::new();
186    /// assert!(decoder.is_empty());
187    /// ```
188    #[must_use]
189    pub fn is_empty(&self) -> bool {
190        self.fountain.is_empty()
191    }
192
193    /// Clear the decoder so that it can be used again.
194    pub fn clear(&mut self) {
195        self.fountain.clear();
196        self.fragment.clear();
197        self.ur_type.clear();
198    }
199}
200
201/// Types for [`BaseDecoder`].
202pub trait Types: Default {
203    /// Fountain decoder.
204    type Decoder: fountain::decoder::Types;
205
206    /// CBOR decoding buffer.
207    type Fragment: Vec<u8>;
208
209    /// The UR type.
210    type URType: Vec<u8>;
211}
212
213/// [`alloc`] types for [`BaseDecoder`].
214#[derive(Default)]
215#[cfg(feature = "alloc")]
216pub struct Alloc;
217
218#[cfg(feature = "alloc")]
219impl Types for Alloc {
220    type Decoder = fountain::decoder::Alloc;
221
222    type Fragment = alloc::vec::Vec<u8>;
223
224    type URType = alloc::vec::Vec<u8>;
225}
226
227/// [`heapless`] types for [`BaseDecoder`].
228#[derive(Default)]
229pub struct Heapless<
230    const MAX_MESSAGE_LEN: usize,
231    const MAX_MIXED_PARTS: usize,
232    const MAX_FRAGMENT_LEN: usize,
233    const MAX_SEQUENCE_COUNT: usize,
234    const QUEUE_SIZE: usize,
235    const MAX_UR_TYPE: usize,
236>;
237
238impl<
239        const MAX_MESSAGE_LEN: usize,
240        const MAX_MIXED_PARTS: usize,
241        const MAX_FRAGMENT_LEN: usize,
242        const MAX_SEQUENCE_COUNT: usize,
243        const QUEUE_SIZE: usize,
244        const MAX_UR_TYPE: usize,
245    > Types
246    for Heapless<
247        MAX_MESSAGE_LEN,
248        MAX_MIXED_PARTS,
249        MAX_FRAGMENT_LEN,
250        MAX_SEQUENCE_COUNT,
251        QUEUE_SIZE,
252        MAX_UR_TYPE,
253    >
254{
255    type Decoder = fountain::decoder::Heapless<
256        MAX_MESSAGE_LEN,
257        MAX_MIXED_PARTS,
258        MAX_FRAGMENT_LEN,
259        MAX_SEQUENCE_COUNT,
260        QUEUE_SIZE,
261    >;
262
263    type Fragment = heapless::Vec<u8, MAX_FRAGMENT_LEN>;
264
265    type URType = heapless::Vec<u8, MAX_UR_TYPE>;
266}
267
268/// Errors that can happen during decoding.
269#[derive(Debug)]
270pub enum Error {
271    /// CBOR decoding error.
272    Cbor(minicbor::decode::Error),
273    /// Fountain decoder error.
274    Fountain(fountain::decoder::Error),
275    /// Bytewords decoding error.
276    Bytewords(bytewords::DecodeError),
277    /// The part received is not multi-part.
278    NotMultiPart,
279    /// The received part is too big to decode.
280    FragmentTooBig {
281        /// The size of the received fragment.
282        size: usize,
283    },
284    /// The received part contained an UR type that is too big for the decoder.
285    URTypeTooBig {
286        /// The size of the UR type.
287        size: usize,
288    },
289    /// The UR type of this fragment is not consistent.
290    InconsistentType,
291}
292
293#[cfg(feature = "std")]
294impl std::error::Error for Error {}
295
296impl fmt::Display for Error {
297    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298        match self {
299            Error::Cbor(e) => write!(f, "CBOR decoding error: {e}"),
300            Error::Fountain(e) => write!(f, "Fountain decoding error: {e}"),
301            Error::Bytewords(e) => write!(f, "Bytewords decoding error: {e}"),
302            Error::NotMultiPart => write!(f, "The Uniform Resource is not multi-part"),
303            Error::FragmentTooBig { size } => write!(
304                f,
305                "The fragment size ({size} bytes) is too big for the decoder"
306            ),
307            Error::URTypeTooBig { size } => {
308                write!(f, "The UR type ({size} bytes) is too big for the decoder")
309            }
310            Error::InconsistentType => write!(
311                f,
312                "The received fragment is not consistent with the type of the previous fragments"
313            ),
314        }
315    }
316}
317
318impl From<minicbor::decode::Error> for Error {
319    fn from(e: minicbor::decode::Error) -> Self {
320        Self::Cbor(e)
321    }
322}
323
324impl From<bytewords::DecodeError> for Error {
325    fn from(e: bytewords::DecodeError) -> Self {
326        Self::Bytewords(e)
327    }
328}
329
330impl From<fountain::decoder::Error> for Error {
331    fn from(e: fountain::decoder::Error) -> Self {
332        Self::Fountain(e)
333    }
334}