Skip to main content

osdp/reply/
keypad.rs

1//! `osdp_KEYPAD` (`0x53`) — keypad data.
2//!
3//! # Spec: §7.12
4
5use crate::error::Error;
6use crate::payload_util::require_at_least;
7use alloc::vec::Vec;
8
9/// `osdp_KEYPAD` body.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Keypad {
12    /// Reader number.
13    pub reader: u8,
14    /// Number of digits in `digits`.
15    pub digit_count: u8,
16    /// Digits (ASCII; `0x7F` = clear, `0x0D` = enter).
17    pub digits: Vec<u8>,
18}
19
20impl Keypad {
21    /// Encode.
22    pub fn encode(&self) -> Result<Vec<u8>, Error> {
23        if self.digits.len() != self.digit_count as usize {
24            return Err(Error::MalformedPayload {
25                code: 0x53,
26                reason: "KEYPAD digit_count disagrees with digits",
27            });
28        }
29        let mut out = Vec::with_capacity(2 + self.digits.len());
30        out.push(self.reader);
31        out.push(self.digit_count);
32        out.extend_from_slice(&self.digits);
33        Ok(out)
34    }
35
36    /// Decode.
37    pub fn decode(data: &[u8]) -> Result<Self, Error> {
38        require_at_least(data, 2, 0x53)?;
39        let digit_count = data[1];
40        if data.len() != 2 + digit_count as usize {
41            return Err(Error::MalformedPayload {
42                code: 0x53,
43                reason: "KEYPAD digit count disagrees with payload",
44            });
45        }
46        Ok(Self {
47            reader: data[0],
48            digit_count,
49            digits: data[2..].to_vec(),
50        })
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn roundtrip() {
60        let body = Keypad {
61            reader: 0x00,
62            digit_count: 3,
63            digits: alloc::vec![b'1', b'2', b'3'],
64        };
65        let bytes = body.encode().unwrap();
66        assert_eq!(bytes, [0x00, 3, b'1', b'2', b'3']);
67        assert_eq!(Keypad::decode(&bytes).unwrap(), body);
68    }
69
70    #[test]
71    fn encode_rejects_count_disagreement() {
72        let body = Keypad {
73            reader: 0,
74            digit_count: 5,                  // claims 5
75            digits: alloc::vec![b'1', b'2'], // but only carries 2
76        };
77        assert!(matches!(
78            body.encode(),
79            Err(Error::MalformedPayload { code: 0x53, .. })
80        ));
81    }
82
83    #[test]
84    fn decode_rejects_count_disagreement() {
85        // count=4 but only 1 digit byte follows.
86        assert!(matches!(
87            Keypad::decode(&[0x00, 4, b'1']),
88            Err(Error::MalformedPayload { code: 0x53, .. })
89        ));
90    }
91}