cesrox/primitives/codes/
serial_number.rs

1use std::str::FromStr;
2
3use crate::{conversion::from_bytes_to_text, derivation_code::DerivationCode, error::Error};
4
5#[derive(PartialEq, Eq, Debug)]
6pub struct SerialNumberCode;
7
8impl DerivationCode for SerialNumberCode {
9    fn hard_size(&self) -> usize {
10        2
11    }
12
13    fn soft_size(&self) -> usize {
14        0
15    }
16
17    fn value_size(&self) -> usize {
18        22
19    }
20
21    fn to_str(&self) -> String {
22        "0A".into()
23    }
24}
25
26impl FromStr for SerialNumberCode {
27    type Err = Error;
28
29    fn from_str(s: &str) -> Result<Self, Self::Err> {
30        let code = s.get(..2).ok_or(Error::EmptyCodeError)?;
31
32        match code {
33            "0A" => Ok(SerialNumberCode),
34            _ => Err(Error::UnknownCodeError),
35        }
36    }
37}
38
39pub fn pack_sn(sn: u64) -> String {
40    let payload_type = SerialNumberCode;
41    let sn_raw: Vec<u8> = sn.to_be_bytes().into();
42
43    // Calculate how many zeros are missing to achieve expected base64 string
44    // length. Master code size is expected padding size.
45    let missing_zeros = payload_type.full_size() / 4 * 3 - payload_type.code_size() - sn_raw.len();
46    let sn_vec: Vec<u8> = std::iter::repeat(0)
47        .take(missing_zeros)
48        .chain(sn_raw)
49        .collect();
50    [
51        payload_type.to_str(),
52        from_bytes_to_text(&sn_vec)[2..].to_string(),
53    ]
54    .join("")
55}
56
57#[test]
58pub fn test_pack_sn() -> Result<(), Error> {
59    assert_eq!(pack_sn(1), "0AAAAAAAAAAAAAAAAAAAAAAB");
60    assert_eq!(pack_sn(64), "0AAAAAAAAAAAAAAAAAAAAABA");
61    assert_eq!(pack_sn(1000), "0AAAAAAAAAAAAAAAAAAAAAPo");
62
63    Ok(())
64}