umsh_node/
app_payload.rs

1use umsh_core::{PacketType, PayloadType};
2
3use crate::{AppParseError, MacCommand, NodeIdentityPayload, mac_command};
4
5pub fn split_payload_type(payload: &[u8]) -> Result<(PayloadType, &[u8]), AppParseError> {
6    if payload.is_empty() {
7        return Ok((PayloadType::Empty, &[]));
8    }
9    if let Some(payload_type) = PayloadType::from_byte(payload[0]) {
10        Ok((payload_type, &payload[1..]))
11    } else {
12        Ok((PayloadType::Empty, payload))
13    }
14}
15
16pub fn expect_payload_type(
17    packet_type: PacketType,
18    payload: &[u8],
19    expected: PayloadType,
20) -> Result<&[u8], AppParseError> {
21    let (payload_type, body) = split_payload_type(payload)?;
22    if !payload_type.allowed_for(packet_type) {
23        return Err(AppParseError::PayloadTypeNotAllowed {
24            payload_type: payload_type as u8,
25            packet_type,
26        });
27    }
28    if payload_type != expected {
29        return Err(AppParseError::InvalidPayloadType(payload_type as u8));
30    }
31    Ok(body)
32}
33
34pub fn parse_mac_command_payload(
35    packet_type: PacketType,
36    payload: &[u8],
37) -> Result<MacCommand<'_>, AppParseError> {
38    mac_command::parse(expect_payload_type(
39        packet_type,
40        payload,
41        PayloadType::MacCommand,
42    )?)
43}
44
45pub fn parse_node_identity_payload(
46    packet_type: PacketType,
47    payload: &[u8],
48) -> Result<NodeIdentityPayload, AppParseError> {
49    NodeIdentityPayload::from_bytes(expect_payload_type(
50        packet_type,
51        payload,
52        PayloadType::NodeIdentity,
53    )?)
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    // --- split_payload_type ---
61
62    #[test]
63    fn split_empty_gives_empty_type() {
64        let (ty, body) = split_payload_type(&[]).unwrap();
65        assert_eq!(ty, PayloadType::Empty);
66        assert_eq!(body, &[] as &[u8]);
67    }
68
69    #[test]
70    fn split_unknown_byte_gives_empty_type_with_full_slice() {
71        // 0x99 is not a known PayloadType byte; the full slice is returned as body.
72        let payload = &[0x99u8, 0x01, 0x02];
73        let (ty, body) = split_payload_type(payload).unwrap();
74        assert_eq!(ty, PayloadType::Empty);
75        assert_eq!(body, payload);
76    }
77
78    #[test]
79    fn split_known_byte_strips_type_prefix() {
80        // 0x02 = MacCommand
81        let payload = &[0x02u8, 0xAA, 0xBB];
82        let (ty, body) = split_payload_type(payload).unwrap();
83        assert_eq!(ty, PayloadType::MacCommand);
84        assert_eq!(body, &[0xAAu8, 0xBB]);
85    }
86
87    // --- expect_payload_type ---
88
89    #[test]
90    fn expect_correct_type_returns_body() {
91        // MacCommand is allowed for Unicast.
92        let payload = &[0x02u8, 0x01]; // MacCommand prefix + body byte
93        let body = expect_payload_type(PacketType::Unicast, payload, PayloadType::MacCommand).unwrap();
94        assert_eq!(body, &[0x01u8]);
95    }
96
97    #[test]
98    fn expect_wrong_type_returns_invalid_payload_type() {
99        // Payload carries NodeIdentity (0x01) but caller expects MacCommand.
100        let payload = &[0x01u8, 0x02, 0x00];
101        let err = expect_payload_type(PacketType::Unicast, payload, PayloadType::MacCommand)
102            .unwrap_err();
103        assert!(matches!(err, AppParseError::InvalidPayloadType(0x01)));
104    }
105
106    #[test]
107    fn expect_disallowed_for_packet_type_returns_error() {
108        // MacCommand is not allowed in a Broadcast packet.
109        let payload = &[0x02u8, 0x01];
110        let err =
111            expect_payload_type(PacketType::Broadcast, payload, PayloadType::MacCommand)
112                .unwrap_err();
113        assert!(matches!(err, AppParseError::PayloadTypeNotAllowed { .. }));
114    }
115}