foundation_urtypes/
passport.rs

1// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. <hello@foundationdevices.com>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4//! # Passport-specific types.
5//!
6//! ## CDDL for Passport Model
7//!
8//! ```cddl
9//! passport-model = uint .size 4 .ne 0
10//! passport-model-founders-edition = 1
11//! passport-model-batch2 = 2
12//! ```
13
14use minicbor::data::Tag;
15use minicbor::decode::Error;
16use minicbor::encode::Write;
17use minicbor::{Decode, Decoder, Encode, Encoder};
18
19/// Passport model.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub enum Model {
22    /// Founders Edition.
23    FoundersEdition,
24    /// Batch 2.
25    Batch2,
26}
27
28impl Model {
29    /// Tag for embedding [`Model`] in other types.
30    pub const TAG: Tag = Tag::new(721);
31}
32
33impl<'b, C> Decode<'b, C> for Model {
34    fn decode(d: &mut Decoder<'b>, _ctx: &mut C) -> Result<Self, Error> {
35        Model::try_from(d.u32()?).map_err(|_| Error::message("invalid passport-model"))
36    }
37}
38
39impl<C> Encode<C> for Model {
40    fn encode<W: Write>(
41        &self,
42        e: &mut Encoder<W>,
43        _ctx: &mut C,
44    ) -> Result<(), minicbor::encode::Error<W::Error>> {
45        e.u32((*self).into())?;
46        Ok(())
47    }
48}
49
50impl TryFrom<u32> for Model {
51    type Error = InvalidModelError;
52
53    fn try_from(number: u32) -> Result<Self, Self::Error> {
54        match number {
55            1 => Ok(Model::FoundersEdition),
56            2 => Ok(Model::Batch2),
57            _ => Err(InvalidModelError { number }),
58        }
59    }
60}
61
62impl From<Model> for u32 {
63    fn from(model: Model) -> Self {
64        match model {
65            Model::FoundersEdition => 1,
66            Model::Batch2 => 2,
67        }
68    }
69}
70
71/// Invalid Passport model error.
72#[derive(Debug, Clone, Copy, Eq, PartialEq)]
73pub struct InvalidModelError {
74    /// Erroneous model number.
75    pub number: u32,
76}