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[0], chunk[1]]));
46 }
47 Ok(Self { ca_system_ids })
48 }
49}
50
51impl Serialize for CaIdentifierDescriptor {
52 type Error = crate::error::Error;
53 fn serialized_len(&self) -> usize {
54 HEADER_LEN + ENTRY_LEN * self.ca_system_ids.len()
55 }
56
57 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
58 let len = self.serialized_len();
59 if buf.len() < len {
60 return Err(Error::OutputBufferTooSmall {
61 need: len,
62 have: buf.len(),
63 });
64 }
65 let body_len = ENTRY_LEN * self.ca_system_ids.len();
66 if body_len > MAX_BODY_LEN {
68 return Err(Error::InvalidDescriptor {
69 tag: TAG,
70 reason: "CA_identifier_descriptor body exceeds 255 bytes",
71 });
72 }
73 buf[0] = TAG;
74 buf[1] = body_len as u8;
75 let mut pos = HEADER_LEN;
76 for caid in &self.ca_system_ids {
77 buf[pos..pos + ENTRY_LEN].copy_from_slice(&caid.to_be_bytes());
78 pos += ENTRY_LEN;
79 }
80 Ok(len)
81 }
82}
83impl<'a> crate::traits::DescriptorDef<'a> for CaIdentifierDescriptor {
84 const TAG: u8 = TAG;
85 const NAME: &'static str = "CA_IDENTIFIER";
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn parse_single_caid() {
94 let bytes = [TAG, 2, 0x06, 0x50];
95 let d = CaIdentifierDescriptor::parse(&bytes).unwrap();
96 assert_eq!(d.ca_system_ids, vec![0x0650]);
97 }
98
99 #[test]
100 fn parse_multiple_caids_preserves_order() {
101 let bytes = [TAG, 6, 0x05, 0x00, 0x06, 0x50, 0x0B, 0x00];
102 let d = CaIdentifierDescriptor::parse(&bytes).unwrap();
103 assert_eq!(d.ca_system_ids, vec![0x0500, 0x0650, 0x0B00]);
104 }
105
106 #[test]
107 fn parse_rejects_wrong_tag() {
108 assert!(matches!(
109 CaIdentifierDescriptor::parse(&[0x54, 2, 0x06, 0x50]).unwrap_err(),
110 Error::InvalidDescriptor { tag: 0x54, .. }
111 ));
112 }
113
114 #[test]
115 fn parse_rejects_short_buffer() {
116 let bytes = [TAG, 4, 0x06, 0x50];
118 assert!(matches!(
119 CaIdentifierDescriptor::parse(&bytes).unwrap_err(),
120 Error::BufferTooShort { .. }
121 ));
122 }
123
124 #[test]
125 fn parse_rejects_odd_length() {
126 let bytes = [TAG, 3, 0x06, 0x50, 0x00];
127 assert!(matches!(
128 CaIdentifierDescriptor::parse(&bytes).unwrap_err(),
129 Error::InvalidDescriptor { tag: TAG, .. }
130 ));
131 }
132
133 #[test]
134 fn empty_descriptor_valid() {
135 let d = CaIdentifierDescriptor::parse(&[TAG, 0]).unwrap();
136 assert!(d.ca_system_ids.is_empty());
137 }
138
139 #[test]
140 fn serialize_round_trip() {
141 let d = CaIdentifierDescriptor {
142 ca_system_ids: vec![0x0100, 0x1800, 0x2600],
143 };
144 let mut buf = vec![0u8; d.serialized_len()];
145 d.serialize_into(&mut buf).unwrap();
146 assert_eq!(CaIdentifierDescriptor::parse(&buf).unwrap(), d);
147 }
148
149 #[test]
150 fn serialize_rejects_over_range_body() {
151 let d = CaIdentifierDescriptor {
153 ca_system_ids: vec![0x0500; 128],
154 };
155 let mut buf = vec![0u8; d.serialized_len()];
156 assert!(matches!(
157 d.serialize_into(&mut buf).unwrap_err(),
158 Error::InvalidDescriptor { tag: TAG, .. }
159 ));
160 }
161
162 #[cfg(feature = "serde")]
163 #[test]
164 fn serde_round_trip() {
165 let d = CaIdentifierDescriptor {
166 ca_system_ids: vec![0x0500, 0x0650],
167 };
168 let json = serde_json::to_string(&d).unwrap();
169 let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
171 }
172}