mpeg2ts_reader/descriptor/
iso_639_language.rs1use super::DescriptorError;
5use std::borrow::Cow;
6use std::fmt;
7
8pub struct Iso639LanguageDescriptor<'buf> {
11 buf: &'buf [u8],
12}
13impl<'buf> Iso639LanguageDescriptor<'buf> {
14 pub const TAG: u8 = 10;
16 pub fn new(
19 _tag: u8,
20 buf: &'buf [u8],
21 ) -> Result<Iso639LanguageDescriptor<'buf>, DescriptorError> {
22 Ok(Iso639LanguageDescriptor { buf })
23 }
24
25 pub fn languages(&self) -> impl Iterator<Item = Result<Language<'buf>, LangError>> {
27 LanguageIterator::new(self.buf)
28 }
29}
30
31struct LanguageIterator<'buf> {
32 remaining_data: &'buf [u8],
33}
34impl<'buf> LanguageIterator<'buf> {
35 pub fn new(data: &'buf [u8]) -> LanguageIterator<'buf> {
36 LanguageIterator {
37 remaining_data: data,
38 }
39 }
40}
41impl<'buf> Iterator for LanguageIterator<'buf> {
42 type Item = Result<Language<'buf>, LangError>;
43
44 fn next(&mut self) -> Option<Self::Item> {
45 if self.remaining_data.is_empty() {
46 None
47 } else if self.remaining_data.len() < 4 {
48 let actual = self.remaining_data.len();
49 self.remaining_data = &self.remaining_data[0..0];
50 Some(Err(LangError::TooShort { actual }))
51 } else {
52 let (head, tail) = self.remaining_data.split_at(4);
53 self.remaining_data = tail;
54 Some(Ok(Language::new(head)))
55 }
56 }
57}
58
59#[derive(Debug)]
61pub enum LangError {
62 TooShort {
64 actual: usize,
66 },
67}
68
69#[derive(Debug, PartialEq, Eq)]
71pub enum AudioType {
72 Undefined,
74 CleanEffects,
76 HearingImpaired,
78 VisualImpairedCommentary,
80 Reserved(u8),
82}
83impl From<u8> for AudioType {
84 fn from(v: u8) -> Self {
85 match v {
86 0 => AudioType::Undefined,
87 1 => AudioType::CleanEffects,
88 2 => AudioType::HearingImpaired,
89 3 => AudioType::VisualImpairedCommentary,
90 _ => AudioType::Reserved(v),
91 }
92 }
93}
94pub struct Language<'buf> {
96 buf: &'buf [u8],
97}
98impl<'buf> Language<'buf> {
99 fn new(buf: &'buf [u8]) -> Language<'buf> {
100 assert_eq!(buf.len(), 4);
101 Language { buf }
102 }
103 pub fn code(&self) -> Cow<'_, str> {
106 encoding_rs::mem::decode_latin1(&self.buf[0..3])
107 }
108 pub fn audio_type(&self) -> AudioType {
111 AudioType::from(self.buf[3])
112 }
113}
114impl<'buf> fmt::Debug for Language<'buf> {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
116 f.debug_struct("Language")
117 .field("code", &self.code())
118 .field("audio_type", &self.audio_type())
119 .finish()
120 }
121}
122
123struct LangsDebug<'buf>(&'buf Iso639LanguageDescriptor<'buf>);
124impl<'buf> fmt::Debug for LangsDebug<'buf> {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
126 f.debug_list().entries(self.0.languages()).finish()
127 }
128}
129impl<'buf> fmt::Debug for Iso639LanguageDescriptor<'buf> {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
131 f.debug_struct("Iso639LanguageDescriptor")
132 .field("languages", &LangsDebug(self))
133 .finish()
134 }
135}
136
137#[cfg(test)]
138mod test {
139 use super::super::{CoreDescriptors, Descriptor};
140 use super::*;
141 use assert_matches::assert_matches;
142 use hex_literal::*;
143
144 #[test]
145 fn descriptor() {
146 let data = hex!("0a04656e6700");
147 let desc = CoreDescriptors::from_bytes(&data).unwrap();
148 assert_matches!(desc, CoreDescriptors::ISO639Language(iso_639_language) => {
149 let mut langs = iso_639_language.languages();
150 let first = langs.next().unwrap().unwrap();
151 assert_eq!("eng", first.code());
152 assert_eq!(AudioType::Undefined, first.audio_type());
153 assert_matches!(langs.next(), None);
154 });
155 }
156
157 #[test]
158 fn debug() {
159 let data = hex!("0a04656e6700");
160 let desc = CoreDescriptors::from_bytes(&data).unwrap();
161 assert_matches!(desc, CoreDescriptors::ISO639Language(iso_639_language) => {
162 assert!(!format!("{:?}", iso_639_language).is_empty());
163 });
164 }
165
166 #[test]
167 fn too_short() {
168 let data = hex!("0a03656e67");
169 let desc = CoreDescriptors::from_bytes(&data).unwrap();
170 if let CoreDescriptors::ISO639Language(iso_639_language) = desc {
171 let mut langs = iso_639_language.languages();
172 langs.next();
173 }
174 }
175}