1use std::borrow::Borrow;
2
3use crate::*;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct MebxItem {
10 pub local_key_id: FourCC,
11 pub data: Vec<u8>,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq, Default)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub struct MebxSample;
29
30impl MebxSample {
31 pub fn decode<B: Buf>(buf: &mut B) -> Result<Vec<MebxItem>> {
32 let mut items = Vec::new();
33 let mut found_null = false;
34
35 while let Some(header) = Header::decode_maybe(buf)? {
36 let size = header.size.unwrap_or(buf.remaining());
37 if size > buf.remaining() {
38 return Err(Error::OutOfBounds);
39 }
40 let body = buf.slice(size);
41
42 if u32::from(header.kind) == 0 {
43 found_null = true;
44 } else {
45 items.push(MebxItem {
46 local_key_id: header.kind,
47 data: body.to_vec(),
48 });
49 }
50
51 buf.advance(size);
52 }
53
54 if buf.has_remaining() {
55 Err(Error::ShortRead)
56 } else if items.is_empty() && !found_null {
57 Err(Error::UnexpectedEof)
58 } else {
59 Ok(items)
60 }
61 }
62
63 pub fn encode<B: BufMut>(
64 items: impl IntoIterator<Item = impl Borrow<MebxItem>>,
65 buf: &mut B,
66 ) -> Result<()> {
67 let mut wrote_atom = false;
68
69 for item in items {
70 let item = item.borrow();
71 buf.encode_atom(item.local_key_id, |buf| {
72 buf.append_slice(&item.data);
73 Ok(())
74 })?;
75 wrote_atom = true;
76 }
77
78 if wrote_atom {
79 Ok(())
80 } else {
81 buf.encode_atom(0u32, |_| Ok(()))
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_mebx_sample_empty_roundtrip() {
92 let sample = vec![];
93
94 let mut buf = Vec::new();
95 MebxSample::encode(&sample, &mut buf).unwrap();
96 assert_eq!(buf, b"\0\0\0\x08\0\0\0\0");
97
98 let decoded = MebxSample::decode(&mut buf.as_slice()).expect("failed to decode sample");
99 assert_eq!(decoded, sample);
100 }
101
102 #[test]
103 fn test_mebx_sample_roundtrip() {
104 let sample = vec![
105 MebxItem {
106 local_key_id: FourCC::new(b"test"),
107 data: b"example".to_vec(),
108 },
109 MebxItem {
110 local_key_id: FourCC::new(b"othr"),
111 data: b"something".to_vec(),
112 },
113 ];
114
115 let mut buf = Vec::new();
116 MebxSample::encode(&sample, &mut buf).unwrap();
117
118 let decoded = MebxSample::decode(&mut buf.as_slice()).expect("failed to decode sample");
119 assert_eq!(decoded, sample);
120 }
121
122 #[test]
123 fn test_mebx_sample_ignore_null_items() {
124 let mut buf = Vec::new();
127 buf.encode_atom(0u32, |buf| [1, 2].encode(buf)).unwrap();
128 buf.encode_atom(b"test", |buf| [3, 4].encode(buf)).unwrap();
129 buf.encode_atom(0u32, |_| Ok(())).unwrap();
130
131 let decoded = MebxSample::decode(&mut buf.as_slice()).expect("failed to decode sample");
132 assert_eq!(
133 decoded,
134 [MebxItem {
135 local_key_id: FourCC::new(b"test"),
136 data: vec![3, 4],
137 }]
138 );
139 }
140
141 #[test]
142 fn test_mebx_sample_empty_is_error() {
143 let err = MebxSample::decode(&mut [].as_slice()).unwrap_err();
144 assert!(matches!(err, Error::UnexpectedEof));
145 }
146
147 #[test]
148 fn test_mebx_sample_short_read() {
149 let err = MebxSample::decode(&mut [1, 2].as_slice()).unwrap_err();
150 assert!(matches!(err, Error::ShortRead));
151 }
152}