dvb_si/descriptors/
ca_identifier.rs1pub use super::ca::ca_system_name;
8use super::descriptor_body;
9use crate::error::{Error, Result};
10use alloc::vec::Vec;
11use dvb_common::{Parse, Serialize};
12
13pub const TAG: u8 = 0x53;
15const HEADER_LEN: usize = 2;
16const ENTRY_LEN: usize = 2;
17const MAX_BODY_LEN: usize = u8::MAX as usize;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize))]
23pub struct CaIdentifierDescriptor {
24 pub ca_system_ids: Vec<u16>,
26}
27
28impl<'a> Parse<'a> for CaIdentifierDescriptor {
29 type Error = crate::error::Error;
30 fn parse(bytes: &'a [u8]) -> Result<Self> {
31 let body = descriptor_body(
32 bytes,
33 TAG,
34 "CaIdentifierDescriptor",
35 "unexpected tag for CA_identifier_descriptor",
36 )?;
37 if body.len() % ENTRY_LEN != 0 {
38 return Err(Error::InvalidDescriptor {
39 tag: TAG,
40 reason: "descriptor_length must be a multiple of 2",
41 });
42 }
43 let mut ca_system_ids = Vec::with_capacity(body.len() / ENTRY_LEN);
44 for chunk in body.chunks_exact(ENTRY_LEN) {
45 ca_system_ids.push(u16::from_be_bytes(*chunk.first_chunk::<2>().unwrap()));
47 }
48 Ok(Self { ca_system_ids })
49 }
50}
51
52impl Serialize for CaIdentifierDescriptor {
53 type Error = crate::error::Error;
54 fn serialized_len(&self) -> usize {
55 HEADER_LEN + ENTRY_LEN * self.ca_system_ids.len()
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 let body_len = ENTRY_LEN * self.ca_system_ids.len();
67 if body_len > MAX_BODY_LEN {
69 return Err(Error::InvalidDescriptor {
70 tag: TAG,
71 reason: "CA_identifier_descriptor body exceeds 255 bytes",
72 });
73 }
74 buf[0] = TAG;
75 buf[1] = body_len as u8;
76 let mut pos = HEADER_LEN;
77 for caid in &self.ca_system_ids {
78 buf[pos..pos + ENTRY_LEN].copy_from_slice(&caid.to_be_bytes());
79 pos += ENTRY_LEN;
80 }
81 Ok(len)
82 }
83}
84impl<'a> crate::traits::DescriptorDef<'a> for CaIdentifierDescriptor {
85 const TAG: u8 = TAG;
86 const NAME: &'static str = "CA_IDENTIFIER";
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn parse_single_caid() {
95 let bytes = [TAG, 2, 0x06, 0x50];
96 let d = CaIdentifierDescriptor::parse(&bytes).unwrap();
97 assert_eq!(d.ca_system_ids, vec![0x0650]);
98 }
99
100 #[test]
101 fn parse_multiple_caids_preserves_order() {
102 let bytes = [TAG, 6, 0x05, 0x00, 0x06, 0x50, 0x0B, 0x00];
103 let d = CaIdentifierDescriptor::parse(&bytes).unwrap();
104 assert_eq!(d.ca_system_ids, vec![0x0500, 0x0650, 0x0B00]);
105 }
106
107 #[test]
108 fn parse_rejects_wrong_tag() {
109 assert!(matches!(
110 CaIdentifierDescriptor::parse(&[0x54, 2, 0x06, 0x50]).unwrap_err(),
111 Error::InvalidDescriptor { tag: 0x54, .. }
112 ));
113 }
114
115 #[test]
116 fn parse_rejects_short_buffer() {
117 let bytes = [TAG, 4, 0x06, 0x50];
119 assert!(matches!(
120 CaIdentifierDescriptor::parse(&bytes).unwrap_err(),
121 Error::BufferTooShort { .. }
122 ));
123 }
124
125 #[test]
126 fn parse_rejects_odd_length() {
127 let bytes = [TAG, 3, 0x06, 0x50, 0x00];
128 assert!(matches!(
129 CaIdentifierDescriptor::parse(&bytes).unwrap_err(),
130 Error::InvalidDescriptor { tag: TAG, .. }
131 ));
132 }
133
134 #[test]
135 fn empty_descriptor_valid() {
136 let d = CaIdentifierDescriptor::parse(&[TAG, 0]).unwrap();
137 assert!(d.ca_system_ids.is_empty());
138 }
139
140 #[test]
141 fn serialize_round_trip() {
142 let d = CaIdentifierDescriptor {
143 ca_system_ids: vec![0x0100, 0x1800, 0x2600],
144 };
145 let mut buf = vec![0u8; d.serialized_len()];
146 d.serialize_into(&mut buf).unwrap();
147 assert_eq!(CaIdentifierDescriptor::parse(&buf).unwrap(), d);
148 }
149
150 #[test]
151 fn serialize_rejects_over_range_body() {
152 let d = CaIdentifierDescriptor {
154 ca_system_ids: vec![0x0500; 128],
155 };
156 let mut buf = vec![0u8; d.serialized_len()];
157 assert!(matches!(
158 d.serialize_into(&mut buf).unwrap_err(),
159 Error::InvalidDescriptor { tag: TAG, .. }
160 ));
161 }
162
163 #[cfg(feature = "serde")]
164 #[test]
165 fn serde_round_trip() {
166 let d = CaIdentifierDescriptor {
167 ca_system_ids: vec![0x0500, 0x0650],
168 };
169 let json = serde_json::to_string(&d).unwrap();
170 let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
172 }
173}