1use crate::error::Error;
15use crate::payload_util::require_exact_len;
16use alloc::vec::Vec;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct PdId {
21 pub vendor_oui: [u8; 3],
23 pub model: u8,
25 pub version: u8,
27 pub serial: u32,
29 pub firmware: [u8; 3],
31}
32
33impl PdId {
34 pub const WIRE_LEN: usize = 12;
36
37 pub fn encode(&self) -> Result<Vec<u8>, Error> {
39 let mut out = Vec::with_capacity(Self::WIRE_LEN);
40 out.extend_from_slice(&self.vendor_oui);
41 out.push(self.model);
42 out.push(self.version);
43 out.extend_from_slice(&self.serial.to_le_bytes());
44 out.extend_from_slice(&self.firmware);
45 Ok(out)
46 }
47
48 pub fn decode(data: &[u8]) -> Result<Self, Error> {
50 require_exact_len(data, Self::WIRE_LEN, 0x45)?;
51 let mut vendor_oui = [0u8; 3];
52 vendor_oui.copy_from_slice(&data[..3]);
53 let mut firmware = [0u8; 3];
54 firmware.copy_from_slice(&data[9..12]);
55 Ok(Self {
56 vendor_oui,
57 model: data[3],
58 version: data[4],
59 serial: u32::from_le_bytes([data[5], data[6], data[7], data[8]]),
60 firmware,
61 })
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn roundtrip() {
71 let id = PdId {
72 vendor_oui: [0x00, 0x06, 0x8E], model: 0x12,
74 version: 0x34,
75 serial: 0xDEAD_BEEF,
76 firmware: [1, 2, 3],
77 };
78 let bytes = id.encode().unwrap();
79 assert_eq!(bytes.len(), 12);
80 let parsed = PdId::decode(&bytes).unwrap();
81 assert_eq!(parsed, id);
82 }
83
84 #[test]
85 fn rejects_truncated() {
86 assert!(PdId::decode(&[0; 11]).is_err());
87 assert!(PdId::decode(&[0; 13]).is_err());
88 }
89}