1use crate::error::Error;
9use crate::payload_util::require_at_least;
10use alloc::vec::Vec;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14#[repr(u8)]
15#[allow(missing_docs)]
16pub enum NakErrorCode {
17 NoError = 0x00,
18 BadCrcOrChecksum = 0x01,
19 CommandLengthError = 0x02,
20 UnknownCommandCode = 0x03,
21 UnexpectedSequenceNumber = 0x04,
22 SecurityBlockTypeNotSupported = 0x05,
23 EncryptedCommunicationRequired = 0x06,
24 BioTypeNotSupported = 0x07,
25 BioFormatNotSupported = 0x08,
26 UnableToProcessCommandRecord = 0x09,
27}
28
29impl NakErrorCode {
30 pub const fn from_byte(b: u8) -> Result<Self, Error> {
32 Ok(match b {
33 0x00 => Self::NoError,
34 0x01 => Self::BadCrcOrChecksum,
35 0x02 => Self::CommandLengthError,
36 0x03 => Self::UnknownCommandCode,
37 0x04 => Self::UnexpectedSequenceNumber,
38 0x05 => Self::SecurityBlockTypeNotSupported,
39 0x06 => Self::EncryptedCommunicationRequired,
40 0x07 => Self::BioTypeNotSupported,
41 0x08 => Self::BioFormatNotSupported,
42 0x09 => Self::UnableToProcessCommandRecord,
43 _ => {
44 return Err(Error::MalformedPayload {
45 code: 0x41,
46 reason: "unknown NAK error code",
47 });
48 }
49 })
50 }
51
52 pub const fn as_byte(self) -> u8 {
54 self as u8
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct Nak {
61 pub error: NakErrorCode,
63 pub completion_codes: Vec<u8>,
65}
66
67impl Nak {
68 pub fn simple(err: NakErrorCode) -> Self {
70 Self {
71 error: err,
72 completion_codes: Vec::new(),
73 }
74 }
75
76 pub fn encode(&self) -> Result<Vec<u8>, Error> {
78 let mut out = Vec::with_capacity(1 + self.completion_codes.len());
79 out.push(self.error.as_byte());
80 out.extend_from_slice(&self.completion_codes);
81 Ok(out)
82 }
83
84 pub fn decode(data: &[u8]) -> Result<Self, Error> {
88 require_at_least(data, 1, 0x41)?;
89 let error = NakErrorCode::from_byte(data[0])?;
90 let completion_codes = if error == NakErrorCode::UnableToProcessCommandRecord {
91 data[1..].to_vec()
92 } else {
93 Vec::new()
94 };
95 Ok(Self {
96 error,
97 completion_codes,
98 })
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn simple_roundtrip() {
108 let n = Nak::simple(NakErrorCode::BadCrcOrChecksum);
109 let bytes = n.encode().unwrap();
110 let parsed = Nak::decode(&bytes).unwrap();
111 assert_eq!(parsed, n);
112 }
113
114 #[test]
115 fn record_completion_codes() {
116 let n = Nak {
117 error: NakErrorCode::UnableToProcessCommandRecord,
118 completion_codes: alloc::vec![0xAA, 0xBB, 0xCC],
119 };
120 let bytes = n.encode().unwrap();
121 let parsed = Nak::decode(&bytes).unwrap();
122 assert_eq!(parsed, n);
123 }
124
125 #[test]
126 fn rejects_unknown_code() {
127 assert!(Nak::decode(&[0xFE]).is_err());
128 }
129}