dvb_si/descriptors/
service_move.rs1use super::descriptor_body;
8use crate::error::{Error, Result};
9use dvb_common::{Parse, Serialize};
10
11pub const TAG: u8 = 0x60;
13const HEADER_LEN: usize = 2;
14const BODY_LEN: u8 = 6;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize))]
20pub struct ServiceMoveDescriptor {
21 pub new_original_network_id: u16,
23 pub new_transport_stream_id: u16,
25 pub new_service_id: u16,
27}
28
29impl<'a> Parse<'a> for ServiceMoveDescriptor {
30 type Error = crate::error::Error;
31 fn parse(bytes: &'a [u8]) -> Result<Self> {
32 let body = descriptor_body(
33 bytes,
34 TAG,
35 "ServiceMoveDescriptor",
36 "unexpected tag for service_move_descriptor",
37 )?;
38 if body.len() != BODY_LEN as usize {
39 return Err(Error::InvalidDescriptor {
40 tag: TAG,
41 reason: "service_move_descriptor length must equal 6",
42 });
43 }
44 Ok(Self {
45 new_original_network_id: u16::from_be_bytes([body[0], body[1]]),
46 new_transport_stream_id: u16::from_be_bytes([body[2], body[3]]),
47 new_service_id: u16::from_be_bytes([body[4], body[5]]),
48 })
49 }
50}
51
52impl Serialize for ServiceMoveDescriptor {
53 type Error = crate::error::Error;
54 fn serialized_len(&self) -> usize {
55 HEADER_LEN + BODY_LEN as usize
56 }
57
58 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
59 let len = self.serialized_len();
60 if buf.len() < len {
61 return Err(Error::OutputBufferTooSmall {
62 need: len,
63 have: buf.len(),
64 });
65 }
66 buf[0] = TAG;
67 buf[1] = BODY_LEN;
68 let b = HEADER_LEN;
69 buf[b..b + 2].copy_from_slice(&self.new_original_network_id.to_be_bytes());
70 buf[b + 2..b + 4].copy_from_slice(&self.new_transport_stream_id.to_be_bytes());
71 buf[b + 4..b + 6].copy_from_slice(&self.new_service_id.to_be_bytes());
72 Ok(len)
73 }
74}
75impl<'a> crate::traits::DescriptorDef<'a> for ServiceMoveDescriptor {
76 const TAG: u8 = TAG;
77 const NAME: &'static str = "SERVICE_MOVE";
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn parse_extracts_triple() {
86 let bytes = [TAG, 6, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03];
87 let d = ServiceMoveDescriptor::parse(&bytes).unwrap();
88 assert_eq!(d.new_original_network_id, 0x0001);
89 assert_eq!(d.new_transport_stream_id, 0x0002);
90 assert_eq!(d.new_service_id, 0x0003);
91 }
92
93 #[test]
94 fn parse_rejects_wrong_tag() {
95 let err = ServiceMoveDescriptor::parse(&[0x61, 6, 0, 0, 0, 0, 0, 0]).unwrap_err();
96 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x61, .. }));
97 }
98
99 #[test]
100 fn parse_rejects_short_buffer() {
101 let err = ServiceMoveDescriptor::parse(&[TAG]).unwrap_err();
102 assert!(matches!(err, Error::BufferTooShort { .. }));
103 }
104
105 #[test]
106 fn parse_rejects_truncated_body() {
107 let err = ServiceMoveDescriptor::parse(&[TAG, 6, 0, 1, 0, 2]).unwrap_err();
109 assert!(matches!(err, Error::BufferTooShort { .. }));
110 }
111
112 #[test]
113 fn parse_rejects_wrong_length() {
114 let err = ServiceMoveDescriptor::parse(&[TAG, 5, 0, 1, 0, 2, 0]).unwrap_err();
115 assert!(matches!(err, Error::InvalidDescriptor { .. }));
116 }
117
118 #[test]
119 fn serialize_round_trip() {
120 let d = ServiceMoveDescriptor {
121 new_original_network_id: 0x1234,
122 new_transport_stream_id: 0x5678,
123 new_service_id: 0x9ABC,
124 };
125 let mut buf = vec![0u8; d.serialized_len()];
126 d.serialize_into(&mut buf).unwrap();
127 let re = ServiceMoveDescriptor::parse(&buf).unwrap();
128 assert_eq!(d, re);
129 }
130
131 #[test]
132 fn serialize_rejects_too_small_buffer() {
133 let d = ServiceMoveDescriptor {
134 new_original_network_id: 1,
135 new_transport_stream_id: 2,
136 new_service_id: 3,
137 };
138 let mut tiny = [0u8; 5];
139 let err = d.serialize_into(&mut tiny).unwrap_err();
140 assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
141 }
142
143 #[test]
144 fn descriptor_length_matches_payload() {
145 let d = ServiceMoveDescriptor {
146 new_original_network_id: 0,
147 new_transport_stream_id: 0,
148 new_service_id: 0,
149 };
150 assert_eq!(d.serialized_len() - 2, 6);
151 }
152
153 #[cfg(feature = "serde")]
154 #[test]
155 fn serde_round_trip() {
156 let d = ServiceMoveDescriptor {
157 new_original_network_id: 0x0001,
158 new_transport_stream_id: 0x0002,
159 new_service_id: 0x0003,
160 };
161 let json = serde_json::to_string(&d).unwrap();
162 let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
164 }
165}