1 // Copyright (C) 2018 François Laignel <fengalin@free.fr> 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 use glib; 10 use glib::translate::{from_glib, ToGlibPtr}; 11 use glib::{Date, SendValue, ToValue}; 12 use gst_sys; 13 14 use serde::de; 15 use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; 16 use serde::ser; 17 use serde::ser::{Serialize, SerializeSeq, SerializeStruct, SerializeTuple, Serializer}; 18 19 use std::cell::RefCell; 20 use std::cmp; 21 use std::fmt; 22 use std::rc::Rc; 23 24 use date_time_serde; 25 use tags::{GenericTagIter, TagList, TagListRef}; 26 use value_serde::{DATE_OTHER_TYPE_ID, DATE_TIME_OTHER_TYPE_ID, SAMPLE_OTHER_TYPE_ID}; 27 use DateTime; 28 use Sample; 29 use TagMergeMode; 30 use TagScope; 31 32 macro_rules! ser_some_tag ( 33 ($value:ident, $seq:ident, $t:ty) => ( 34 ser_some_value!($value, $t, |_, value| { 35 $seq.serialize_element(&value) 36 }) 37 ); 38 ); 39 macro_rules! ser_opt_tag ( 40 ($value:ident, $seq:ident, $t:ty) => ( 41 ser_opt_value!($value, $t, |_, value| { 42 $seq.serialize_element(&value) 43 }) 44 ); 45 ); 46 47 // Note: unlike `Value`s, `Tag`s with optional `Type` `String` & `Date` values are guarenteed 48 // to be Non-null and non-empty in the C API. See: 49 // https://gitlab.freedesktop.org/gstreamer/gstreamer/blob/d90d771a9a512381315f7694c3a50b152035f3cb/gst/gststructure.c#L810-853 50 51 // serialize trait is only available for `&self`, but we need to mutate the iterator 52 struct TagValuesSer<'a>(Rc<RefCell<GenericTagIter<'a>>>); 53 impl<'a> TagValuesSer<'a> { from(tags_ser: &TagsSer<'a>) -> Self54 fn from(tags_ser: &TagsSer<'a>) -> Self { 55 TagValuesSer(Rc::clone(&tags_ser.1)) 56 } 57 } 58 59 impl<'a> Serialize for TagValuesSer<'a> { serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>60 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 61 use std::ops::DerefMut; 62 63 let mut tag_iter = self.0.borrow_mut(); 64 let mut seq = serializer.serialize_seq(tag_iter.size_hint().1)?; 65 for value in tag_iter.deref_mut() { 66 match value.type_() { 67 glib::Type::F64 => ser_some_tag!(value, seq, f64), 68 glib::Type::String => { 69 // See above comment about `Tag`s with `String` values 70 ser_opt_value!(value, String, |_, value: Option<String>| { 71 seq.serialize_element(&value.expect("String tag ser")) 72 }) 73 } 74 glib::Type::U32 => ser_some_tag!(value, seq, u32), 75 glib::Type::U64 => ser_some_tag!(value, seq, u64), 76 glib::Type::Other(type_id) => { 77 if *DATE_OTHER_TYPE_ID == type_id { 78 // See above comment about `Tag`s with `Date` values 79 ser_opt_value!(value, Date, |_, value: Option<Date>| { 80 // Need to wrap the `glib::Date` in new type `date_time_serde::Date` first 81 // See comment in `date_time_serde.rs` 82 seq.serialize_element(&date_time_serde::Date::from( 83 value.expect("Date tag ser"), 84 )) 85 }) 86 } else if *DATE_TIME_OTHER_TYPE_ID == type_id { 87 ser_opt_tag!(value, seq, DateTime) 88 } else if *SAMPLE_OTHER_TYPE_ID == type_id { 89 ser_opt_tag!(value, seq, Sample) 90 } else { 91 Err(ser::Error::custom(format!( 92 "unimplemented `Tag` serialization for type {}", 93 glib::Type::Other(type_id), 94 ))) 95 } 96 } 97 type_ => Err(ser::Error::custom(format!( 98 "unimplemented `Tag` serialization for type {}", 99 type_ 100 ))), 101 }?; 102 } 103 seq.end() 104 } 105 } 106 107 struct TagsSer<'a>(&'a str, Rc<RefCell<GenericTagIter<'a>>>); 108 impl<'a> TagsSer<'a> { new(name: &'a str, tag_iter: GenericTagIter<'a>) -> Self109 fn new(name: &'a str, tag_iter: GenericTagIter<'a>) -> Self { 110 TagsSer(name, Rc::new(RefCell::new(tag_iter))) 111 } 112 } 113 114 impl<'a> Serialize for TagsSer<'a> { serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>115 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 116 let mut tup = serializer.serialize_tuple(2)?; 117 tup.serialize_element(self.0)?; 118 tup.serialize_element(&TagValuesSer::from(&self))?; 119 tup.end() 120 } 121 } 122 123 struct TagListSer<'a>(&'a TagListRef); 124 impl<'a> Serialize for TagListSer<'a> { serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>125 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 126 let tag_count = self.0.n_tags(); 127 match tag_count.cmp(&0) { 128 cmp::Ordering::Greater => { 129 let mut seq = serializer.serialize_seq(Some(tag_count as usize))?; 130 let tag_list_iter = self.0.iter_generic(); 131 for (tag_name, tag_iter) in tag_list_iter { 132 seq.serialize_element(&TagsSer::new(tag_name, tag_iter))?; 133 } 134 seq.end() 135 } 136 cmp::Ordering::Equal => { 137 let seq = serializer.serialize_seq(None)?; 138 seq.end() 139 } 140 cmp::Ordering::Less => Err(ser::Error::custom("tag count < 0")), 141 } 142 } 143 } 144 145 impl Serialize for TagListRef { serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>146 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 147 let mut tag_list = serializer.serialize_struct("TagList", 3)?; 148 tag_list.serialize_field("scope", &self.get_scope())?; 149 tag_list.serialize_field("tags", &TagListSer(self))?; 150 tag_list.end() 151 } 152 } 153 154 impl Serialize for TagList { serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>155 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 156 self.as_ref().serialize(serializer) 157 } 158 } 159 160 macro_rules! de_some_tag( 161 ($tag_name:expr, $seq:expr, $t:ty) => ( 162 de_some_send_value!("Tag", $tag_name, $seq, $t) 163 ); 164 ); 165 macro_rules! de_opt_tag( 166 ($tag_name:expr, $seq:expr, $t:ty) => ( 167 de_opt_send_value!("Tag", $tag_name, $seq, $t) 168 ); 169 ); 170 171 struct TagValues<'a>(&'a str, &'a mut TagListRef); 172 173 struct TagValuesVisitor<'a>(&'a str, &'a mut TagListRef); 174 impl<'de, 'a> Visitor<'de> for TagValuesVisitor<'a> { 175 type Value = (); 176 expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result177 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 178 formatter.write_str("a sequence of `Tag` values with the same type") 179 } 180 visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error>181 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> { 182 let tag_type: glib::Type = unsafe { 183 let tag_name = self.0.to_glib_none(); 184 from_glib(gst_sys::gst_tag_get_type(tag_name.0)) 185 }; 186 187 loop { 188 let tag_value = match tag_type { 189 glib::Type::F64 => de_some_tag!(self.0, seq, f64), 190 glib::Type::String => { 191 // See comment above `TagValuesSer` definition about `Tag`s with `String` values 192 de_some_tag!(self.0, seq, String) 193 } 194 glib::Type::U32 => de_some_tag!(self.0, seq, u32), 195 glib::Type::U64 => de_some_tag!(self.0, seq, u64), 196 glib::Type::Other(type_id) => { 197 if *DATE_OTHER_TYPE_ID == type_id { 198 // See comment above `TagValuesSer` definition about `Tag`s with `Date` values 199 // Need to deserialize as `date_time_serde::Date` new type 200 // See comment in `date_time_serde.rs` 201 de_send_value!("Tag", self.0, seq, date_time_serde::Date, Date) 202 } else if *DATE_TIME_OTHER_TYPE_ID == type_id { 203 de_opt_tag!(self.0, seq, DateTime) 204 } else if *SAMPLE_OTHER_TYPE_ID == type_id { 205 de_opt_tag!(self.0, seq, Sample) 206 } else { 207 return Err(de::Error::custom(format!( 208 "unimplemented deserialization for `Tag` {} with type `{}`", 209 self.0, 210 glib::Type::Other(type_id), 211 ))); 212 } 213 } 214 type_ => { 215 return Err(de::Error::custom(format!( 216 "unimplemented deserialization for `Tag` {} with type `{}`", 217 self.0, type_, 218 ))); 219 } 220 }?; 221 222 match tag_value { 223 Some(tag_value) => self 224 .1 225 .add_generic(self.0, &tag_value, TagMergeMode::Append) 226 .map_err(|_| { 227 de::Error::custom(format!("wrong value type for `Tag` {}", self.0)) 228 })?, 229 None => break, 230 } 231 } 232 233 Ok(()) 234 } 235 } 236 237 impl<'de, 'a> DeserializeSeed<'de> for TagValues<'a> { 238 type Value = (); 239 deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error>240 fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> { 241 deserializer.deserialize_seq(TagValuesVisitor(self.0, self.1)) 242 } 243 } 244 245 struct TagValuesTuple<'a>(&'a mut TagListRef); 246 247 struct TagValuesTupleVisitor<'a>(&'a mut TagListRef); 248 impl<'de, 'a> Visitor<'de> for TagValuesTupleVisitor<'a> { 249 type Value = (); 250 expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result251 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 252 formatter 253 .write_str("a tuple (`Tag` name: `String`, seq. of `Tag` values with the same type)") 254 } 255 visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error>256 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> { 257 let name = seq 258 .next_element::<String>() 259 .map_err(|err| de::Error::custom(format!("Error reading Tag name. {:?}", err)))? 260 .ok_or_else(|| de::Error::custom("Expected a name for the `Tag` name"))?; 261 seq.next_element_seed(TagValues(name.as_str(), self.0))? 262 .ok_or_else(|| de::Error::custom("Expected a seq of values for the `Tag`")) 263 } 264 } 265 266 impl<'de, 'a> DeserializeSeed<'de> for TagValuesTuple<'a> { 267 type Value = (); 268 deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error>269 fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> { 270 deserializer.deserialize_tuple(2, TagValuesTupleVisitor(self.0)) 271 } 272 } 273 274 struct TagsDe(TagList); 275 276 struct TagsVisitor; 277 impl<'de> Visitor<'de> for TagsVisitor { 278 type Value = TagsDe; 279 expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result280 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 281 formatter.write_str("a sequence of `Tag`s") 282 } 283 visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error>284 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> { 285 let mut tag_list = TagList::new(); 286 { 287 let tag_list = tag_list.get_mut().unwrap(); 288 while seq.next_element_seed(TagValuesTuple(tag_list))?.is_some() { 289 // tags are added in the dedicated deserializers 290 } 291 } 292 Ok(TagsDe(tag_list)) 293 } 294 } 295 296 impl<'de> Deserialize<'de> for TagsDe { deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>297 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { 298 deserializer.deserialize_seq(TagsVisitor) 299 } 300 } 301 302 #[derive(Deserialize)] 303 struct TagListDe { 304 scope: TagScope, 305 tags: TagsDe, 306 } 307 308 impl From<TagListDe> for TagList { from(tag_list_de: TagListDe) -> Self309 fn from(tag_list_de: TagListDe) -> Self { 310 let mut tag_list = tag_list_de.tags.0; 311 tag_list.get_mut().unwrap().set_scope(tag_list_de.scope); 312 313 tag_list 314 } 315 } 316 317 impl<'de> Deserialize<'de> for TagList { deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>318 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { 319 TagListDe::deserialize(deserializer).map(|tag_list_de| tag_list_de.into()) 320 } 321 } 322 323 #[cfg(test)] 324 mod tests { 325 extern crate ron; 326 327 use tags::*; 328 use Buffer; 329 use Sample; 330 use TagMergeMode; 331 use TagScope; 332 333 #[test] test_serialize()334 fn test_serialize() { 335 ::init().unwrap(); 336 337 let mut tags = TagList::new(); 338 assert_eq!(tags.to_string(), "taglist;"); 339 { 340 let tags = tags.get_mut().unwrap(); 341 tags.add::<Title>(&"a title", TagMergeMode::Append); // String 342 tags.add::<Title>(&"another title", TagMergeMode::Append); // String 343 tags.add::<Duration>(&(::SECOND * 120), TagMergeMode::Append); // u64 344 tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32 345 tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64 346 tags.add::<Date>( 347 &glib::Date::new_dmy(28, glib::DateMonth::May, 2018), 348 TagMergeMode::Append, 349 ); 350 tags.add::<DateTime>(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append); 351 352 let sample = { 353 let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); 354 { 355 let buffer = buffer.get_mut().unwrap(); 356 buffer.set_offset(0); 357 buffer.set_offset_end(0); 358 } 359 Sample::new().buffer(&buffer).build() 360 }; 361 tags.add::<Image>(&sample, TagMergeMode::Append); // Sample 362 } 363 364 let mut pretty_config = ron::ser::PrettyConfig::default(); 365 pretty_config.new_line = "".to_string(); 366 367 let res = ron::ser::to_string_pretty(&tags, pretty_config); 368 assert_eq!( 369 Ok(concat!( 370 r#"("#, 371 r#" scope: Stream,"#, 372 r#" tags: ["#, 373 r#" ("title", ["#, 374 r#" "a title","#, 375 r#" "another title","#, 376 r#" ]),"#, 377 r#" ("duration", ["#, 378 r#" 120000000000,"#, 379 r#" ]),"#, 380 r#" ("bitrate", ["#, 381 r#" 96000,"#, 382 r#" ]),"#, 383 r#" ("replaygain-track-gain", ["#, 384 r#" 1,"#, 385 r#" ]),"#, 386 r#" ("date", ["#, 387 r#" YMD(2018, 5, 28),"#, 388 r#" ]),"#, 389 r#" ("datetime", ["#, 390 r#" Some(YMD(2018, 5, 28)),"#, 391 r#" ]),"#, 392 r#" ("image", ["#, 393 r#" Some(("#, 394 r#" buffer: Some(("#, 395 r#" pts: None,"#, 396 r#" dts: None,"#, 397 r#" duration: None,"#, 398 r#" offset: 0,"#, 399 r#" offset_end: 0,"#, 400 r#" flags: ("#, 401 r#" bits: 0,"#, 402 r#" ),"#, 403 r#" buffer: "AQIDBA==","#, 404 r#" )),"#, 405 r#" buffer_list: None,"#, 406 r#" caps: None,"#, 407 r#" segment: Some(("#, 408 r#" flags: ("#, 409 r#" bits: 0,"#, 410 r#" ),"#, 411 r#" rate: 1,"#, 412 r#" applied_rate: 1,"#, 413 r#" format: Time,"#, 414 r#" base: 0,"#, 415 r#" offset: 0,"#, 416 r#" start: 0,"#, 417 r#" stop: -1,"#, 418 r#" time: 0,"#, 419 r#" position: 0,"#, 420 r#" duration: -1,"#, 421 r#" )),"#, 422 r#" info: None,"#, 423 r#" )),"#, 424 r#" ]),"#, 425 r#" ],"#, 426 r#")"#, 427 ) 428 .to_owned()), 429 res, 430 ); 431 } 432 433 #[test] test_deserialize()434 fn test_deserialize() { 435 extern crate serde_json; 436 437 ::init().unwrap(); 438 439 let tag_list_ron = r#" 440 ( 441 scope: Global, 442 tags: [ 443 ("title", [ 444 "a title", 445 "another title", 446 ]), 447 ("duration", [120000000000]), 448 ("bitrate", [96000]), 449 ("replaygain-track-gain", [1]), 450 ("date", [ 451 YMD(2018, 5, 28), 452 ]), 453 ("datetime", [ 454 Some(YMD(2018, 5, 28)), 455 ]), 456 ("image", [ 457 Some(( 458 buffer: Some(( 459 pts: None, 460 dts: None, 461 duration: None, 462 offset: 0, 463 offset_end: 0, 464 flags: ( 465 bits: 0, 466 ), 467 buffer: "AQIDBA==", 468 )), 469 buffer_list: None, 470 caps: None, 471 segment: None, 472 info: None, 473 )), 474 ]) 475 ], 476 ) 477 "#; 478 let tags: TagList = ron::de::from_str(tag_list_ron).unwrap(); 479 assert_eq!(tags.get_scope(), TagScope::Global); 480 481 assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title")); 482 assert_eq!( 483 tags.get_index::<Title>(1).unwrap().get(), 484 Some("another title") 485 ); 486 assert_eq!( 487 tags.get_index::<Duration>(0).unwrap().get_some(), 488 ::SECOND * 120 489 ); 490 assert_eq!(tags.get_index::<Bitrate>(0).unwrap().get_some(), 96_000); 491 assert!( 492 (tags.get_index::<TrackGain>(0).unwrap().get_some() - 1f64).abs() < std::f64::EPSILON 493 ); 494 assert_eq!( 495 tags.get_index::<Date>(0).unwrap().get().unwrap(), 496 glib::Date::new_dmy(28, glib::DateMonth::May, 2018) 497 ); 498 assert_eq!( 499 tags.get_index::<DateTime>(0).unwrap().get().unwrap(), 500 ::DateTime::new_ymd(2018, 5, 28) 501 ); 502 let sample = tags.get_index::<Image>(0).unwrap().get().unwrap(); 503 let buffer = sample.get_buffer().unwrap(); 504 { 505 let data = buffer.map_readable().unwrap(); 506 assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); 507 } 508 509 let tag_json = r#" 510 { 511 "scope":"Global", 512 "tags":[ 513 ["title", ["a title", "another title"]], 514 ["duration", [120000000000]], 515 ["bitrate", [96000]], 516 ["replaygain-track-gain", [1.0]], 517 ["date",[{"YMD":[2018,5,28]}]], 518 ["datetime",[{"YMD":[2018,5,28]}]], 519 ["image",[{"buffer":{"pts":null,"dts":null,"duration":null,"offset":0,"offset_end":0,"flags":{"bits":0},"buffer":[1,2,3,4]},"buffer_list":null,"caps":null,"segment":null,"info":null}]] 520 ] 521 } 522 "#; 523 let tags: TagList = serde_json::from_str(tag_json).unwrap(); 524 assert_eq!(tags.get_scope(), TagScope::Global); 525 526 assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title")); 527 assert_eq!( 528 tags.get_index::<Title>(1).unwrap().get(), 529 Some("another title") 530 ); 531 assert_eq!(tags.get_index::<Bitrate>(0).unwrap().get_some(), 96_000); 532 assert!( 533 (tags.get_index::<TrackGain>(0).unwrap().get_some() - 1f64).abs() < std::f64::EPSILON 534 ); 535 assert_eq!( 536 tags.get_index::<Date>(0).unwrap().get().unwrap(), 537 glib::Date::new_dmy(28, glib::DateMonth::May, 2018) 538 ); 539 assert_eq!( 540 tags.get_index::<DateTime>(0).unwrap().get().unwrap(), 541 ::DateTime::new_ymd(2018, 5, 28) 542 ); 543 let sample = tags.get_index::<Image>(0).unwrap().get().unwrap(); 544 let buffer = sample.get_buffer().unwrap(); 545 { 546 let data = buffer.map_readable().unwrap(); 547 assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); 548 } 549 } 550 551 #[test] test_serde_roundtrip()552 fn test_serde_roundtrip() { 553 ::init().unwrap(); 554 555 let mut tags = TagList::new(); 556 assert_eq!(tags.to_string(), "taglist;"); 557 { 558 let tags = tags.get_mut().unwrap(); 559 tags.set_scope(TagScope::Global); 560 tags.add::<Title>(&"a title", TagMergeMode::Append); // String 561 tags.add::<Title>(&"another title", TagMergeMode::Append); // String 562 tags.add::<Duration>(&(::SECOND * 120), TagMergeMode::Append); // u64 563 tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32 564 tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64 565 tags.add::<Date>( 566 &glib::Date::new_dmy(28, glib::DateMonth::May, 2018), 567 TagMergeMode::Append, 568 ); 569 tags.add::<DateTime>(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append); 570 571 let sample = { 572 let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); 573 { 574 let buffer = buffer.get_mut().unwrap(); 575 buffer.set_offset(0); 576 buffer.set_offset_end(0); 577 } 578 Sample::new().buffer(&buffer).build() 579 }; 580 tags.add::<Image>(&sample, TagMergeMode::Append); // Sample 581 } 582 let tags_ser = ron::ser::to_string(&tags).unwrap(); 583 584 let tags_de: TagList = ron::de::from_str(tags_ser.as_str()).unwrap(); 585 assert_eq!(tags_de.get_scope(), TagScope::Global); 586 587 assert_eq!( 588 tags_de.get_index::<Title>(0).unwrap().get(), 589 tags.get_index::<Title>(0).unwrap().get(), 590 ); 591 assert_eq!( 592 tags_de.get_index::<Title>(1).unwrap().get(), 593 tags.get_index::<Title>(1).unwrap().get(), 594 ); 595 assert_eq!( 596 tags_de.get_index::<Duration>(0).unwrap().get_some(), 597 tags.get_index::<Duration>(0).unwrap().get_some(), 598 ); 599 assert_eq!( 600 tags_de.get_index::<Bitrate>(0).unwrap().get_some(), 601 tags.get_index::<Bitrate>(0).unwrap().get_some(), 602 ); 603 assert!( 604 (tags_de.get_index::<TrackGain>(0).unwrap().get_some() 605 - tags.get_index::<TrackGain>(0).unwrap().get_some()) 606 .abs() 607 < std::f64::EPSILON 608 ); 609 assert_eq!( 610 tags_de.get_index::<Date>(0).unwrap().get(), 611 tags.get_index::<Date>(0).unwrap().get(), 612 ); 613 assert_eq!( 614 tags.get_index::<DateTime>(0).unwrap().get().unwrap(), 615 ::DateTime::new_ymd(2018, 5, 28) 616 ); 617 let sample = tags.get_index::<Image>(0).unwrap().get().unwrap(); 618 let buffer = sample.get_buffer().unwrap(); 619 { 620 let data = buffer.map_readable().unwrap(); 621 assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); 622 } 623 } 624 } 625