mpeg2ts_reader/descriptor/
iso_639_language.rsuse super::DescriptorError;
use std::borrow::Cow;
use std::fmt;
pub struct Iso639LanguageDescriptor<'buf> {
buf: &'buf [u8],
}
impl<'buf> Iso639LanguageDescriptor<'buf> {
pub const TAG: u8 = 10;
pub fn new(
_tag: u8,
buf: &'buf [u8],
) -> Result<Iso639LanguageDescriptor<'buf>, DescriptorError> {
Ok(Iso639LanguageDescriptor { buf })
}
pub fn languages(&self) -> impl Iterator<Item = Result<Language<'buf>, LangError>> {
LanguageIterator::new(self.buf)
}
}
struct LanguageIterator<'buf> {
remaining_data: &'buf [u8],
}
impl<'buf> LanguageIterator<'buf> {
pub fn new(data: &'buf [u8]) -> LanguageIterator<'buf> {
LanguageIterator {
remaining_data: data,
}
}
}
impl<'buf> Iterator for LanguageIterator<'buf> {
type Item = Result<Language<'buf>, LangError>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining_data.is_empty() {
None
} else if self.remaining_data.len() < 4 {
let actual = self.remaining_data.len();
self.remaining_data = &self.remaining_data[0..0];
Some(Err(LangError::TooShort { actual }))
} else {
let (head, tail) = self.remaining_data.split_at(4);
self.remaining_data = tail;
Some(Ok(Language::new(head)))
}
}
}
#[derive(Debug)]
pub enum LangError {
TooShort {
actual: usize,
},
}
#[derive(Debug, PartialEq, Eq)]
pub enum AudioType {
Undefined,
CleanEffects,
HearingImpaired,
VisualImpairedCommentary,
Reserved(u8),
}
impl From<u8> for AudioType {
fn from(v: u8) -> Self {
match v {
0 => AudioType::Undefined,
1 => AudioType::CleanEffects,
2 => AudioType::HearingImpaired,
3 => AudioType::VisualImpairedCommentary,
_ => AudioType::Reserved(v),
}
}
}
pub struct Language<'buf> {
buf: &'buf [u8],
}
impl<'buf> Language<'buf> {
fn new(buf: &'buf [u8]) -> Language<'buf> {
assert_eq!(buf.len(), 4);
Language { buf }
}
pub fn code(&self) -> Cow<'_, str> {
encoding_rs::mem::decode_latin1(&self.buf[0..3])
}
pub fn audio_type(&self) -> AudioType {
AudioType::from(self.buf[3])
}
}
impl<'buf> fmt::Debug for Language<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("Language")
.field("code", &self.code())
.field("audio_type", &self.audio_type())
.finish()
}
}
struct LangsDebug<'buf>(&'buf Iso639LanguageDescriptor<'buf>);
impl<'buf> fmt::Debug for LangsDebug<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_list().entries(self.0.languages()).finish()
}
}
impl<'buf> fmt::Debug for Iso639LanguageDescriptor<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("Iso639LanguageDescriptor")
.field("languages", &LangsDebug(self))
.finish()
}
}
#[cfg(test)]
mod test {
use super::super::{CoreDescriptors, Descriptor};
use super::*;
use assert_matches::assert_matches;
use hex_literal::*;
#[test]
fn descriptor() {
let data = hex!("0a04656e6700");
let desc = CoreDescriptors::from_bytes(&data).unwrap();
assert_matches!(desc, CoreDescriptors::ISO639Language(iso_639_language) => {
let mut langs = iso_639_language.languages();
let first = langs.next().unwrap().unwrap();
assert_eq!("eng", first.code());
assert_eq!(AudioType::Undefined, first.audio_type());
assert_matches!(langs.next(), None);
});
}
#[test]
fn debug() {
let data = hex!("0a04656e6700");
let desc = CoreDescriptors::from_bytes(&data).unwrap();
assert_matches!(desc, CoreDescriptors::ISO639Language(iso_639_language) => {
assert!(!format!("{:?}", iso_639_language).is_empty());
});
}
#[test]
fn too_short() {
let data = hex!("0a03656e67");
let desc = CoreDescriptors::from_bytes(&data).unwrap();
if let CoreDescriptors::ISO639Language(iso_639_language) = desc {
let mut langs = iso_639_language.languages();
langs.next();
}
}
}