scte35_splice/commands/
private_command.rs1use crate::error::{Error, Result};
10use crate::traits::CommandDef;
11use broadcast_common::{Parse, Serialize};
12
13pub const COMMAND_TYPE: u8 = 0xFF;
15
16const IDENTIFIER_LEN: usize = 4;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize))]
22pub struct PrivateCommand<'a> {
23 pub identifier: u32,
25 pub private_bytes: &'a [u8],
27}
28
29impl<'a> Parse<'a> for PrivateCommand<'a> {
30 type Error = Error;
31 fn parse(bytes: &'a [u8]) -> Result<Self> {
32 let (id_bytes, private_bytes) =
33 bytes
34 .split_first_chunk::<IDENTIFIER_LEN>()
35 .ok_or(Error::BufferTooShort {
36 need: IDENTIFIER_LEN,
37 have: bytes.len(),
38 what: "private_command identifier",
39 })?;
40 let identifier = u32::from_be_bytes(*id_bytes);
41 Ok(Self {
42 identifier,
43 private_bytes,
44 })
45 }
46}
47
48impl Serialize for PrivateCommand<'_> {
49 type Error = Error;
50 fn serialized_len(&self) -> usize {
51 IDENTIFIER_LEN + self.private_bytes.len()
52 }
53 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
54 let need = self.serialized_len();
55 if buf.len() < need {
56 return Err(Error::OutputBufferTooSmall {
57 need,
58 have: buf.len(),
59 });
60 }
61 buf[0..IDENTIFIER_LEN].copy_from_slice(&self.identifier.to_be_bytes());
62 buf[IDENTIFIER_LEN..need].copy_from_slice(self.private_bytes);
63 Ok(need)
64 }
65}
66
67impl<'a> CommandDef<'a> for PrivateCommand<'a> {
68 const COMMAND_TYPE: u8 = COMMAND_TYPE;
69 const NAME: &'static str = "PRIVATE_COMMAND";
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn round_trip() {
78 let cmd = PrivateCommand {
79 identifier: 0x43554549,
80 private_bytes: &[0xDE, 0xAD, 0xBE, 0xEF],
81 };
82 let bytes = cmd.to_bytes();
83 assert_eq!(&bytes[0..4], &[0x43, 0x55, 0x45, 0x49]);
84 let back = PrivateCommand::parse(&bytes).unwrap();
85 assert_eq!(cmd, back);
86 assert_eq!(back.to_bytes(), bytes);
87 }
88
89 #[test]
90 fn empty_private_bytes() {
91 let cmd = PrivateCommand {
92 identifier: 0x01020304,
93 private_bytes: &[],
94 };
95 let bytes = cmd.to_bytes();
96 assert_eq!(bytes.len(), 4);
97 assert_eq!(PrivateCommand::parse(&bytes).unwrap(), cmd);
98 }
99
100 #[test]
101 fn rejects_short_identifier() {
102 assert!(matches!(
103 PrivateCommand::parse(&[0x00, 0x01]).unwrap_err(),
104 Error::BufferTooShort { .. }
105 ));
106 }
107}