rsfn_file/header/fields/
cert_serial.rs1use std::fmt;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct CertSerial([u8; 32]);
6
7impl From<[u8; 32]> for CertSerial {
8 fn from(value: [u8; 32]) -> Self {
9 Self(value)
10 }
11}
12
13impl CertSerial {
14 pub fn value(&self) -> [u8; 32] {
15 self.0
16 }
17
18 fn ascii_value(&self) -> Result<String, ()> {
19 let value: String = self
20 .value()
21 .into_iter()
22 .skip_while(|&byte| byte == 0 || byte == b'0')
23 .map(|byte| byte as char)
24 .collect();
25 if !value.is_empty() && value.chars().all(|c| c.is_ascii_hexdigit()) {
26 Ok(value)
27 } else {
28 Err(())
29 }
30 }
31
32 pub fn describe_value(&self) -> String {
33 match self.ascii_value() {
34 Ok(value) => format!("0x{}", value.to_lowercase()),
35 Err(_) => "INVÁLIDO".to_string(),
36 }
37 }
38
39 pub fn is_valid(&self) -> bool {
40 self.ascii_value().is_ok()
41 }
42
43 pub fn to_bytes(&self) -> [u8; 32] {
44 self.value()
45 }
46}
47
48impl fmt::Display for CertSerial {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 let value: String = self
51 .value()
52 .iter()
53 .map(|byte| format!("{byte:02x}"))
54 .collect();
55 let desc = self.describe_value();
56 write!(f, "0x{value} [{desc}]")
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn value_binary_zero() {
66 let value = [0; 32];
67
68 let sut: CertSerial = value.into();
69
70 assert_eq!(sut, CertSerial(value));
71 assert_eq!(sut, value.into());
72 assert_eq!(sut.value(), value);
73 assert_eq!(sut.describe_value(), "INVÁLIDO");
74 assert!(!sut.is_valid());
75 assert_eq!(sut.to_bytes(), value);
76 assert_eq!(
77 sut.to_string(),
78 "0x0000000000000000000000000000000000000000000000000000000000000000 [INVÁLIDO]"
79 );
80 }
81
82 #[test]
83 fn value_ascii_zero() {
84 let value = [b'0'; 32];
85
86 let sut: CertSerial = value.into();
87
88 assert_eq!(sut, CertSerial(value));
89 assert_eq!(sut, value.into());
90 assert_eq!(sut.value(), value);
91 assert_eq!(sut.describe_value(), "INVÁLIDO");
92 assert!(!sut.is_valid());
93 assert_eq!(sut.to_bytes(), value);
94 assert_eq!(
95 sut.to_string(),
96 "0x3030303030303030303030303030303030303030303030303030303030303030 [INVÁLIDO]"
97 );
98 }
99
100 #[test]
101 fn value_some_bytes() {
102 let mut value = [0; 32];
103 for i in 26..32 {
104 value[i as usize] = b'1' + i - 26;
105 }
106 let value = value;
107
108 let sut: CertSerial = value.into();
109
110 assert_eq!(sut, CertSerial(value));
111 assert_eq!(sut, value.into());
112 assert_eq!(sut.value(), value);
113 assert_eq!(sut.describe_value(), "0x123456");
114 assert!(sut.is_valid());
115 assert_eq!(sut.to_bytes(), value);
116 assert_eq!(
117 sut.to_string(),
118 "0x0000000000000000000000000000000000000000000000000000313233343536 [0x123456]"
119 );
120 }
121
122 #[test]
123 fn value_invalid_bytes() {
124 let value = [0xff; 32];
125
126 let sut: CertSerial = value.into();
127
128 assert_eq!(sut, CertSerial(value));
129 assert_eq!(sut, value.into());
130 assert_eq!(sut.value(), value);
131 assert_eq!(sut.describe_value(), "INVÁLIDO");
132 assert!(!sut.is_valid());
133 assert_eq!(sut.to_bytes(), value);
134 assert_eq!(
135 sut.to_string(),
136 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff [INVÁLIDO]"
137 );
138 }
139
140 #[test]
141 fn value_full() {
142 let value: [u8; 32] = (0..16)
143 .flat_map(|byte| {
144 format!("{byte:02X}")
145 .chars()
146 .map(|c| c as u8)
147 .collect::<Vec<_>>()
148 })
149 .collect::<Vec<_>>()
150 .try_into()
151 .unwrap();
152
153 let sut: CertSerial = value.into();
154
155 assert_eq!(sut, CertSerial(value));
156 assert_eq!(sut, value.into());
157 assert_eq!(sut.value(), value);
158 assert_eq!(sut.describe_value(), "0x102030405060708090a0b0c0d0e0f");
159 assert!(sut.is_valid());
160 assert_eq!(sut.to_bytes(), value);
161 assert_eq!(
162 sut.to_string(),
163 "0x3030303130323033303430353036303730383039304130423043304430453046 [0x102030405060708090a0b0c0d0e0f]"
164 );
165 }
166}