Skip to main content

dvb_si/descriptors/
related_content.rs

1//! Related Content Descriptor โ€” ETSI TS 102 323 ยง10.4.1, Table 108 (tag 0x74).
2//!
3//! Carried in a PMT ES_info loop to flag that the elementary stream delivers
4//! a Related Content Table (RCT) sub_table. The descriptor body is empty โ€” it
5//! is a pure marker. Per the TVA PDF (etsi_ts_102_323_v01.04.01, p. 94,
6//! Table 108): the only fields are `descriptor_tag` and `descriptor_length`,
7//! and "descriptor_length ... shall be set to the number of bytes that follow
8//! it" (i.e. zero). At most one related_content descriptor per PMT sub_table.
9
10use super::descriptor_body;
11use crate::error::{Error, Result};
12use dvb_common::{Parse, Serialize};
13
14/// Descriptor tag for related_content_descriptor.
15pub const TAG: u8 = 0x74;
16const HEADER_LEN: usize = 2;
17
18/// Related Content Descriptor.
19///
20/// A zero-length marker โ€” it carries no payload fields.
21#[derive(Debug, Clone, PartialEq, Eq, Default)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize))]
23pub struct RelatedContentDescriptor;
24
25impl<'a> Parse<'a> for RelatedContentDescriptor {
26    type Error = crate::error::Error;
27    fn parse(bytes: &'a [u8]) -> Result<Self> {
28        let _body = descriptor_body(
29            bytes,
30            TAG,
31            "RelatedContentDescriptor",
32            "unexpected tag for related_content_descriptor",
33        )?;
34        // Body must be empty per Table 108. Trailing payload bytes are ignored
35        // (forward-compatibility), consistent with permissive parsing elsewhere.
36        Ok(Self)
37    }
38}
39
40impl Serialize for RelatedContentDescriptor {
41    type Error = crate::error::Error;
42    fn serialized_len(&self) -> usize {
43        HEADER_LEN
44    }
45
46    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
47        let len = self.serialized_len();
48        if buf.len() < len {
49            return Err(Error::OutputBufferTooSmall {
50                need: len,
51                have: buf.len(),
52            });
53        }
54        buf[0] = TAG;
55        buf[1] = 0;
56        Ok(len)
57    }
58}
59impl<'a> crate::traits::DescriptorDef<'a> for RelatedContentDescriptor {
60    const TAG: u8 = TAG;
61    const NAME: &'static str = "RELATED_CONTENT";
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn parse_empty_marker() {
70        let bytes = [TAG, 0];
71        let d = RelatedContentDescriptor::parse(&bytes).unwrap();
72        assert_eq!(d, RelatedContentDescriptor);
73    }
74
75    #[test]
76    fn parse_rejects_wrong_tag() {
77        assert!(matches!(
78            RelatedContentDescriptor::parse(&[0x73, 0]).unwrap_err(),
79            Error::InvalidDescriptor { tag: 0x73, .. }
80        ));
81    }
82
83    #[test]
84    fn parse_rejects_short_header() {
85        assert!(matches!(
86            RelatedContentDescriptor::parse(&[TAG]).unwrap_err(),
87            Error::BufferTooShort { .. }
88        ));
89    }
90
91    #[test]
92    fn parse_rejects_length_overrunning_buffer() {
93        let bytes = [TAG, 3, 1, 2];
94        assert!(matches!(
95            RelatedContentDescriptor::parse(&bytes).unwrap_err(),
96            Error::BufferTooShort { .. }
97        ));
98    }
99
100    #[test]
101    fn serialize_round_trip() {
102        let d = RelatedContentDescriptor;
103        let mut buf = vec![0u8; d.serialized_len()];
104        let n = d.serialize_into(&mut buf).unwrap();
105        assert_eq!(n, 2);
106        assert_eq!(buf, vec![TAG, 0]);
107        assert_eq!(RelatedContentDescriptor::parse(&buf).unwrap(), d);
108    }
109
110    #[test]
111    fn serialize_rejects_too_small_buffer() {
112        let d = RelatedContentDescriptor;
113        let mut buf = vec![0u8; 1];
114        assert!(matches!(
115            d.serialize_into(&mut buf).unwrap_err(),
116            Error::OutputBufferTooSmall { .. }
117        ));
118    }
119
120    #[cfg(feature = "serde")]
121    #[test]
122    fn serde_round_trip() {
123        let d = RelatedContentDescriptor;
124        let j = serde_json::to_string(&d).unwrap();
125        // Serialize-only: assert the emitted JSON re-parses (serialize-stable).
126        let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
127    }
128}