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 =
94            expect_payload_type(PacketType::Unicast, payload, PayloadType::MacCommand).unwrap();
95        assert_eq!(body, &[0x01u8]);
96    }
97
98    #[test]
99    fn expect_wrong_type_returns_invalid_payload_type() {
100        // Payload carries NodeIdentity (0x01) but caller expects MacCommand.
101        let payload = &[0x01u8, 0x02, 0x00];
102        let err =
103            expect_payload_type(PacketType::Unicast, payload, PayloadType::MacCommand).unwrap_err();
104        assert!(matches!(err, AppParseError::InvalidPayloadType(0x01)));
105    }
106
107    #[test]
108    fn expect_disallowed_for_packet_type_returns_error() {
109        // A text message is not allowed in a Broadcast packet.
110        let payload = &[0x03u8, 0x01];
111        let err = expect_payload_type(PacketType::Broadcast, payload, PayloadType::TextMessage)
112            .unwrap_err();
113        assert!(matches!(err, AppParseError::PayloadTypeNotAllowed { .. }));
114    }
115
116    #[test]
117    fn expect_mac_command_is_admitted_on_broadcast() {
118        // Broadcast admits MAC commands at the payload-type level; which
119        // commands are acted on is decided per-command at dispatch.
120        let payload = &[0x02u8, 0x01];
121        let body =
122            expect_payload_type(PacketType::Broadcast, payload, PayloadType::MacCommand).unwrap();
123        assert_eq!(body, &[0x01u8]);
124    }
125}