Skip to main content

osdp/reply/
pdcap.rs

1//! `osdp_PDCAP` (`0x46`) — peripheral capabilities.
2//!
3//! # Spec: §7.5, Annex B
4//!
5//! Body is a sequence of [`Capability`] triplets.
6
7use crate::caps::{Capability, FunctionCode};
8use crate::error::Error;
9use crate::payload_util::require_multiple_of;
10use alloc::vec::Vec;
11
12/// `osdp_PDCAP` body.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct PdCap {
15    /// All advertised capabilities, in the order they appeared on the wire.
16    pub capabilities: Vec<Capability>,
17}
18
19impl PdCap {
20    /// New body.
21    pub fn new(capabilities: Vec<Capability>) -> Self {
22        Self { capabilities }
23    }
24
25    /// Look up the first capability matching `code`, if present.
26    pub fn capability(&self, code: FunctionCode) -> Option<Capability> {
27        self.capabilities
28            .iter()
29            .copied()
30            .find(|c| c.code == code.as_byte())
31    }
32
33    /// Encode.
34    pub fn encode(&self) -> Result<Vec<u8>, Error> {
35        let mut out = Vec::with_capacity(self.capabilities.len() * Capability::WIRE_LEN);
36        for c in &self.capabilities {
37            out.extend_from_slice(&c.encode());
38        }
39        Ok(out)
40    }
41
42    /// Decode.
43    pub fn decode(data: &[u8]) -> Result<Self, Error> {
44        require_multiple_of(data, Capability::WIRE_LEN, 0x46)?;
45        let capabilities = data
46            .chunks_exact(Capability::WIRE_LEN)
47            .map(|c| Capability::decode([c[0], c[1], c[2]]))
48            .collect();
49        Ok(Self { capabilities })
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn lookup_function_code() {
59        let body = PdCap::new(alloc::vec![
60            Capability {
61                code: FunctionCode::CommunicationSecurity.as_byte(),
62                compliance: 1,
63                number_of: 1,
64            },
65            Capability {
66                code: FunctionCode::ReceiveBufferSize.as_byte(),
67                compliance: 0x80,
68                number_of: 0,
69            },
70        ]);
71        let aes = body
72            .capability(FunctionCode::CommunicationSecurity)
73            .unwrap();
74        assert_eq!(aes.compliance, 1);
75        let rxsize = body.capability(FunctionCode::ReceiveBufferSize).unwrap();
76        assert_eq!(rxsize.u16_value(), 128);
77    }
78
79    #[test]
80    fn roundtrip() {
81        let body = PdCap::new(alloc::vec![
82            Capability {
83                code: 1,
84                compliance: 1,
85                number_of: 4
86            },
87            Capability {
88                code: 2,
89                compliance: 1,
90                number_of: 2
91            },
92        ]);
93        let bytes = body.encode().unwrap();
94        assert_eq!(bytes, [1, 1, 4, 2, 1, 2]);
95        let parsed = PdCap::decode(&bytes).unwrap();
96        assert_eq!(parsed, body);
97    }
98}