1use super::*;
7
8trait DataEntry<'a>: std::convert::TryFrom<&'a [u32]> {
9 fn raw_length(&self) -> usize;
10}
11
12#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum DbRangeEntryData {
15 DbScale(DbScale),
16 DbInterval(DbInterval),
17 DbRange(DbRange),
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct DbRangeEntry {
23 pub min_val: i32,
24 pub max_val: i32,
25 pub data: DbRangeEntryData,
27}
28
29impl<'a> DataEntry<'a> for DbRangeEntry {
30 fn raw_length(&self) -> usize {
31 let data_value_length = match &self.data {
32 DbRangeEntryData::DbScale(d) => d.value_length(),
33 DbRangeEntryData::DbInterval(d) => d.value_length(),
34 DbRangeEntryData::DbRange(d) => d.value_length(),
35 };
36 let data_length = 2 + data_value_length;
37 2 + data_length
38 }
39}
40
41const TYPES_FOR_DB_RANGE_ENTRY: &'static [u32] = &[
42 SNDRV_CTL_TLVT_DB_SCALE,
43 SNDRV_CTL_TLVT_DB_RANGE,
44 SNDRV_CTL_TLVT_DB_LINEAR,
45 SNDRV_CTL_TLVT_DB_MINMAX,
46 SNDRV_CTL_TLVT_DB_MINMAX_MUTE,
47];
48
49impl std::convert::TryFrom<&[u32]> for DbRangeEntry {
50 type Error = TlvDecodeError;
51
52 fn try_from(raw: &[u32]) -> Result<Self, Self::Error> {
53 if raw.len() < 4 {
54 Err(Self::Error::new(TlvDecodeErrorCtx::Length(raw.len(), 4), 0))
55 } else {
56 let min_val = raw[0] as i32;
57 let max_val = raw[1] as i32;
58
59 let entry_data = &raw[2..];
60 match entry_data[0] {
61 SNDRV_CTL_TLVT_DB_SCALE => DbScale::try_from(entry_data).map(|d| Self {
62 min_val,
63 max_val,
64 data: DbRangeEntryData::DbScale(d),
65 }),
66 SNDRV_CTL_TLVT_DB_RANGE => DbRange::try_from(entry_data).map(|d| Self {
67 min_val,
68 max_val,
69 data: DbRangeEntryData::DbRange(d),
70 }),
71 SNDRV_CTL_TLVT_DB_LINEAR
72 | SNDRV_CTL_TLVT_DB_MINMAX
73 | SNDRV_CTL_TLVT_DB_MINMAX_MUTE => DbInterval::try_from(entry_data).map(|d| Self {
74 min_val,
75 max_val,
76 data: DbRangeEntryData::DbInterval(d),
77 }),
78 _ => Err(Self::Error::new(
79 TlvDecodeErrorCtx::ValueType(entry_data[0], TYPES_FOR_DB_RANGE_ENTRY),
80 0,
81 )),
82 }
83 .map_err(|e| Self::Error::new(TlvDecodeErrorCtx::ValueContent(Box::new(e)), 2))
84 }
85 }
86}
87
88impl From<&DbRangeEntry> for Vec<u32> {
89 fn from(entry: &DbRangeEntry) -> Self {
90 let mut raw = Vec::new();
91 raw.push(entry.min_val as u32);
92 raw.push(entry.max_val as u32);
93 let mut data_raw = match &entry.data {
94 DbRangeEntryData::DbScale(d) => Vec::<u32>::from(d),
95 DbRangeEntryData::DbRange(d) => Vec::<u32>::from(d),
96 DbRangeEntryData::DbInterval(d) => Vec::<u32>::from(d),
97 };
98 raw.append(&mut data_raw);
99 raw
100 }
101}
102
103impl From<DbRangeEntry> for Vec<u32> {
104 fn from(entry: DbRangeEntry) -> Self {
105 (&entry).into()
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct DbRange {
114 pub entries: Vec<DbRangeEntry>,
116}
117
118impl<'a> TlvData<'a> for DbRange {
119 fn value_type(&self) -> u32 {
120 SNDRV_CTL_TLVT_DB_RANGE
121 }
122
123 fn value_length(&self) -> usize {
124 self.entries
125 .iter()
126 .fold(0, |length, entry| length + entry.raw_length())
127 }
128
129 fn value(&self) -> Vec<u32> {
130 let mut raw = Vec::new();
131 self.entries.iter().for_each(|entry| {
132 let mut entry_raw = Vec::<u32>::from(entry);
133 raw.append(&mut entry_raw);
134 });
135 raw
136 }
137}
138
139const TYPES_FOR_DB_RANGE: &'static [u32] = &[SNDRV_CTL_TLVT_DB_RANGE];
140
141impl std::convert::TryFrom<&[u32]> for DbRange {
142 type Error = TlvDecodeError;
143
144 fn try_from(raw: &[u32]) -> Result<Self, Self::Error> {
145 if raw.len() < 2 {
147 Err(Self::Error::new(TlvDecodeErrorCtx::Length(raw.len(), 2), 0))
148 } else if raw[0] != SNDRV_CTL_TLVT_DB_RANGE {
150 Err(Self::Error::new(
151 TlvDecodeErrorCtx::ValueType(raw[0], TYPES_FOR_DB_RANGE),
152 0,
153 ))
154 } else {
155 let value_length = (raw[1] / 4) as usize;
157 let value = &raw[2..];
158 if value.len() < value_length {
159 Err(Self::Error::new(
160 TlvDecodeErrorCtx::ValueLength(value_length, value.len()),
161 1,
162 ))
163 } else {
164 let mut pos = 0;
166
167 let mut entries = Vec::new();
168 while pos < value_length {
169 DbRangeEntry::try_from(&value[pos..])
170 .map(|entry| {
171 entries.push(entry);
172 pos += 4 + (value[pos + 3] / 4) as usize;
173 })
174 .map_err(|e| {
175 Self::Error::new(TlvDecodeErrorCtx::ValueContent(Box::new(e)), pos + 2)
176 })?;
177 }
178
179 Ok(Self { entries })
180 }
181 }
182 }
183}
184
185impl From<&DbRange> for Vec<u32> {
186 fn from(data: &DbRange) -> Self {
187 let mut raw = Vec::new();
188 raw.push(data.value_type());
189 raw.push(4 * data.value_length() as u32);
190 raw.append(&mut data.value());
191 raw
192 }
193}
194
195impl From<DbRange> for Vec<u32> {
196 fn from(data: DbRange) -> Self {
197 (&data).into()
198 }
199}
200
201impl<'a> DataEntry<'a> for TlvItem {
202 fn raw_length(&self) -> usize {
203 let entry_value_length = match self {
204 TlvItem::Container(d) => d.value_length(),
205 TlvItem::DbRange(d) => d.value_length(),
206 TlvItem::DbScale(d) => d.value_length(),
207 TlvItem::DbInterval(d) => d.value_length(),
208 TlvItem::Chmap(d) => d.value_length(),
209 TlvItem::Unknown(d) => d.len(),
210 };
211 2 + entry_value_length
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
221pub struct Container {
222 pub entries: Vec<TlvItem>,
224}
225
226impl<'a> TlvData<'a> for Container {
227 fn value_type(&self) -> u32 {
228 SNDRV_CTL_TLVT_CONTAINER
229 }
230
231 fn value_length(&self) -> usize {
232 self.entries
233 .iter()
234 .fold(0, |length, entry| length + entry.raw_length())
235 }
236
237 fn value(&self) -> Vec<u32> {
238 let mut raw = Vec::new();
239 self.entries.iter().for_each(|entry| {
240 raw.append(&mut entry.into());
241 });
242 raw
243 }
244}
245
246const TYPES_FOR_CONTAINER: &'static [u32] = &[SNDRV_CTL_TLVT_CONTAINER];
247
248impl std::convert::TryFrom<&[u32]> for Container {
249 type Error = TlvDecodeError;
250
251 fn try_from(raw: &[u32]) -> Result<Self, Self::Error> {
252 if raw.len() < 2 {
254 Err(Self::Error::new(TlvDecodeErrorCtx::Length(raw.len(), 2), 0))
255 } else if raw[0] != SNDRV_CTL_TLVT_CONTAINER {
257 Err(Self::Error::new(
258 TlvDecodeErrorCtx::ValueType(raw[0], TYPES_FOR_CONTAINER),
259 0,
260 ))
261 } else {
262 let value_length = (raw[1] / 4) as usize;
264 let value = &raw[2..];
265 if value.len() < value_length {
266 Err(Self::Error::new(
267 TlvDecodeErrorCtx::ValueLength(value_length, value.len()),
268 1,
269 ))
270 } else {
271 let mut pos = 0;
273
274 let mut entries = Vec::new();
275 while pos < value_length {
276 TlvItem::try_from(&value[pos..])
277 .map(|entry| {
278 entries.push(entry);
279 pos += 2 + (value[pos + 1] / 4) as usize;
280 })
281 .map_err(|e| {
282 Self::Error::new(TlvDecodeErrorCtx::ValueContent(Box::new(e)), pos + 2)
283 })?;
284 }
285
286 Ok(Self { entries })
287 }
288 }
289 }
290}
291
292impl From<&Container> for Vec<u32> {
293 fn from(data: &Container) -> Self {
294 let mut raw = Vec::new();
295 raw.push(data.value_type());
296 raw.push(4 * data.value_length() as u32);
297 raw.append(&mut data.value());
298 raw
299 }
300}
301
302impl From<Container> for Vec<u32> {
303 fn from(data: Container) -> Self {
304 (&data).into()
305 }
306}
307
308#[cfg(test)]
309mod test {
310 use super::{Container, TlvItem};
311 use super::{DbInterval, DbScale};
312 use super::{DbRange, DbRangeEntry, DbRangeEntryData};
313 use std::convert::TryFrom;
314
315 #[test]
316 fn test_dbrangeentry_dbscale() {
317 let raw = [-9i32 as u32, 100, 1, 8, 0, 10];
318 let entry = DbRangeEntry::try_from(&raw[..]).unwrap();
319 assert_eq!(entry.min_val, -9);
320 assert_eq!(entry.max_val, 100);
321 assert_eq!(
322 entry.data,
323 DbRangeEntryData::DbScale(DbScale {
324 min: 0,
325 step: 10,
326 mute_avail: false
327 })
328 );
329 assert_eq!(&Vec::<u32>::from(entry)[..], &raw[..]);
330 }
331
332 #[test]
333 fn test_dbrangeentry_dbinterval_linear() {
334 let raw = [-9i32 as u32, 100, 2, 8, 0, 10];
335 let entry = DbRangeEntry::try_from(&raw[..]).unwrap();
336 assert_eq!(entry.min_val, -9);
337 assert_eq!(entry.max_val, 100);
338 assert_eq!(
339 entry.data,
340 DbRangeEntryData::DbInterval(DbInterval {
341 min: 0,
342 max: 10,
343 linear: true,
344 mute_avail: true
345 })
346 );
347 assert_eq!(&Vec::<u32>::from(entry)[..], &raw[..]);
348 }
349
350 #[test]
351 fn test_dbrange() {
352 let raw = [
353 3u32,
354 72,
355 0,
356 10,
357 2,
358 8,
359 -110i32 as u32,
360 10,
361 10,
362 20,
363 4,
364 8,
365 -10i32 as u32,
366 0,
367 20,
368 30,
369 5,
370 8,
371 0,
372 20,
373 ];
374 let range = DbRange::try_from(&raw[..]).unwrap();
375 assert_eq!(
376 range.entries[0],
377 DbRangeEntry {
378 min_val: 0,
379 max_val: 10,
380 data: DbRangeEntryData::DbInterval(DbInterval {
381 min: -110,
382 max: 10,
383 linear: true,
384 mute_avail: true
385 }),
386 }
387 );
388 assert_eq!(
389 range.entries[1],
390 DbRangeEntry {
391 min_val: 10,
392 max_val: 20,
393 data: DbRangeEntryData::DbInterval(DbInterval {
394 min: -10,
395 max: 0,
396 linear: false,
397 mute_avail: false
398 }),
399 }
400 );
401 assert_eq!(
402 range.entries[2],
403 DbRangeEntry {
404 min_val: 20,
405 max_val: 30,
406 data: DbRangeEntryData::DbInterval(DbInterval {
407 min: 0,
408 max: 20,
409 linear: false,
410 mute_avail: true
411 }),
412 }
413 );
414 assert_eq!(&Vec::<u32>::from(range)[..], &raw[..]);
415 }
416
417 #[test]
418 fn test_containerentry_dbscale() {
419 let raw = [0u32, 32, 1, 8, 0, 5, 1, 8, 5, 5];
420 let cntr = Container::try_from(&raw[..]).unwrap();
421 assert_eq!(
422 cntr.entries[0],
423 TlvItem::DbScale(DbScale {
424 min: 0,
425 step: 5,
426 mute_avail: false
427 })
428 );
429 assert_eq!(
430 cntr.entries[1],
431 TlvItem::DbScale(DbScale {
432 min: 5,
433 step: 5,
434 mute_avail: false
435 })
436 );
437 assert_eq!(&Vec::<u32>::from(cntr)[..], &raw);
438 }
439
440 #[test]
441 fn test_containerentry_dbrange() {
442 let raw = [
443 0u32, 136, 3, 48, 0, 10, 4, 8, 0, 5, 10, 20, 4, 8, 0, 10, 3, 72, 0, 10, 4, 8, 0, 5, 10,
444 20, 4, 8, 5, 10, 20, 40, 4, 8, 10, 20,
445 ];
446 let cntr = Container::try_from(&raw[..]).unwrap();
447 assert_eq!(
448 cntr.entries[0],
449 TlvItem::DbRange(DbRange {
450 entries: vec![
451 DbRangeEntry {
452 min_val: 0,
453 max_val: 10,
454 data: DbRangeEntryData::DbInterval(DbInterval {
455 min: 0,
456 max: 5,
457 linear: false,
458 mute_avail: false
459 }),
460 },
461 DbRangeEntry {
462 min_val: 10,
463 max_val: 20,
464 data: DbRangeEntryData::DbInterval(DbInterval {
465 min: 0,
466 max: 10,
467 linear: false,
468 mute_avail: false
469 }),
470 },
471 ],
472 })
473 );
474 assert_eq!(
475 cntr.entries[1],
476 TlvItem::DbRange(DbRange {
477 entries: vec![
478 DbRangeEntry {
479 min_val: 0,
480 max_val: 10,
481 data: DbRangeEntryData::DbInterval(DbInterval {
482 min: 0,
483 max: 5,
484 linear: false,
485 mute_avail: false
486 }),
487 },
488 DbRangeEntry {
489 min_val: 10,
490 max_val: 20,
491 data: DbRangeEntryData::DbInterval(DbInterval {
492 min: 5,
493 max: 10,
494 linear: false,
495 mute_avail: false
496 }),
497 },
498 DbRangeEntry {
499 min_val: 20,
500 max_val: 40,
501 data: DbRangeEntryData::DbInterval(DbInterval {
502 min: 10,
503 max: 20,
504 linear: false,
505 mute_avail: false
506 }),
507 },
508 ],
509 })
510 );
511 assert_eq!(&Vec::<u32>::from(cntr)[..], &raw[..]);
512 }
513}