1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use super::DescriptorError;
use encoding::all::ISO_8859_1;
use encoding::types::DecoderTrap;
use encoding::Encoding;
use std::borrow::Cow;
use std::fmt;

pub struct Iso639LanguageDescriptor<'buf> {
    pub 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) -> LanguageIterator<'buf> {
        LanguageIterator::new(self.buf)
    }
}

pub 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 = Language<'buf>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining_data.is_empty() {
            None
        } else {
            let (head, tail) = self.remaining_data.split_at(4);
            self.remaining_data = tail;
            Some(Language::new(head))
        }
    }
}

#[derive(Debug, PartialEq)]
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 }
    }
    fn code(&self, trap: DecoderTrap) -> Result<String, Cow<'static, str>> {
        ISO_8859_1.decode(&self.buf[0..3], trap)
    }
    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(DecoderTrap::Replace).unwrap())
            .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 encoding;

    #[test]
    fn descriptor() {
        let data = hex!("0a04656e6700");
        let desc = CoreDescriptors::from_bytes(&data).unwrap();
        if let CoreDescriptors::ISO639Language(iso_639_language) = desc {
            let mut langs = iso_639_language.languages();
            let first = langs.next().unwrap();
            assert_eq!("eng", first.code(encoding::DecoderTrap::Strict).unwrap());
            assert_eq!(AudioType::Undefined, first.audio_type());
            assert_matches!(langs.next(), None);
        } else {
            panic!("wrong descriptor type {:?}", desc);
        }
    }
}