// Copyright (C) 2018 François Laignel // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use ffi; use glib; use glib::translate::{from_glib, ToGlibPtr}; use glib::{SendValue, ToValue}; use serde::de; use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; use serde::ser; use serde::ser::{Serialize, SerializeSeq, SerializeTuple, Serializer}; use std::cell::RefCell; use std::fmt; use std::rc::Rc; use tags::*; use value_serde::{DATE_TIME_OTHER_TYPE_ID, SAMPLE_OTHER_TYPE_ID}; use DateTime; use Sample; use TagMergeMode; macro_rules! ser_tag ( ($value:ident, $seq:ident, $t:ty) => ( ser_value!($value, $t, |_, value| { $seq.serialize_element(&value) }) ); ); // serialize trait is only available for `&self`, but we need to mutate the iterator struct TagValuesSer<'a>(Rc>>); impl<'a> TagValuesSer<'a> { fn from(tags_ser: &TagsSer<'a>) -> Self { TagValuesSer(Rc::clone(&tags_ser.1)) } } impl<'a> Serialize for TagValuesSer<'a> { fn serialize(&self, serializer: S) -> Result { use std::ops::DerefMut; let mut tag_iter = self.0.borrow_mut(); let mut seq = serializer.serialize_seq(tag_iter.size_hint().1)?; for value in tag_iter.deref_mut() { match value.type_() { glib::Type::F64 => ser_tag!(value, seq, f64), glib::Type::String => ser_tag!(value, seq, String), glib::Type::U32 => ser_tag!(value, seq, u32), glib::Type::U64 => ser_tag!(value, seq, u64), glib::Type::Other(type_id) => { if *DATE_TIME_OTHER_TYPE_ID == type_id { ser_tag!(value, seq, DateTime) } else if *SAMPLE_OTHER_TYPE_ID == type_id { ser_tag!(value, seq, Sample) } else { Err(ser::Error::custom(format!( "unimplemented `Tag` serialization for type {}", glib::Type::Other(type_id), ))) } } type_ => Err(ser::Error::custom(format!( "unimplemented `Tag` serialization for type {}", type_ ))), }?; } seq.end() } } struct TagsSer<'a>(&'a str, Rc>>); impl<'a> TagsSer<'a> { fn new(name: &'a str, tag_iter: GenericTagIterator<'a>) -> Self { TagsSer(name, Rc::new(RefCell::new(tag_iter))) } } impl<'a> Serialize for TagsSer<'a> { fn serialize(&self, serializer: S) -> Result { let mut tup = serializer.serialize_tuple(2)?; tup.serialize_element(self.0)?; tup.serialize_element(&TagValuesSer::from(&self))?; tup.end() } } impl Serialize for TagListRef { fn serialize(&self, serializer: S) -> Result { let tag_count = self.n_tags(); if tag_count > 0 { let mut seq = serializer.serialize_seq(Some(tag_count as usize))?; let tag_list_iter = self.iter_generic(); for (tag_name, tag_iter) in tag_list_iter { seq.serialize_element(&TagsSer::new(tag_name, tag_iter))?; } seq.end() } else if tag_count == 0 { let seq = serializer.serialize_seq(None)?; seq.end() } else { Err(ser::Error::custom("tag count < 0")) } } } impl Serialize for TagList { fn serialize(&self, serializer: S) -> Result { self.as_ref().serialize(serializer) } } macro_rules! de_tag_value( ($tag_name:expr, $seq:expr, $t:ty) => ( de_send_value!("Tag", $tag_name, $seq, $t) ); ); struct TagValues<'a>(&'a str, &'a mut TagListRef); struct TagValuesVisitor<'a>(&'a str, &'a mut TagListRef); impl<'de, 'a> Visitor<'de> for TagValuesVisitor<'a> { type Value = (); fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence of `Tag` values with the same type") } fn visit_seq>(self, mut seq: A) -> Result<(), A::Error> { let tag_type: glib::Type = unsafe { let tag_name = self.0.to_glib_none(); from_glib(ffi::gst_tag_get_type(tag_name.0)) }; loop { let tag_value = match tag_type { glib::Type::F64 => de_tag_value!(self.0, seq, f64), glib::Type::String => de_tag_value!(self.0, seq, String), glib::Type::U32 => de_tag_value!(self.0, seq, u32), glib::Type::U64 => de_tag_value!(self.0, seq, u64), glib::Type::Other(type_id) => { if *DATE_TIME_OTHER_TYPE_ID == type_id { de_tag_value!(self.0, seq, DateTime) } else if *SAMPLE_OTHER_TYPE_ID == type_id { de_tag_value!(self.0, seq, Sample) } else { return Err(de::Error::custom(format!( "unimplemented deserialization for `Tag` {} with type `{}`", self.0, glib::Type::Other(type_id), ))); } } type_ => { return Err(de::Error::custom(format!( "unimplemented deserialization for `Tag` {} with type `{}`", self.0, type_, ))); } }?; match tag_value { Some(tag_value) => self .1 .add_generic(self.0, &tag_value, TagMergeMode::Append) .map_err(|_| { de::Error::custom(format!("wrong value type for `Tag` {}", self.0)) })?, None => break, } } Ok(()) } } impl<'de, 'a> DeserializeSeed<'de> for TagValues<'a> { type Value = (); fn deserialize>(self, deserializer: D) -> Result<(), D::Error> { deserializer.deserialize_seq(TagValuesVisitor(self.0, self.1)) } } struct TagValuesTuple<'a>(&'a mut TagListRef); struct TagValuesTupleVisitor<'a>(&'a mut TagListRef); impl<'de, 'a> Visitor<'de> for TagValuesTupleVisitor<'a> { type Value = (); fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter .write_str("a tuple (`Tag` name: `String`, seq. of `Tag` values with the same type)") } fn visit_seq>(self, mut seq: A) -> Result<(), A::Error> { let name = seq .next_element::() .map_err(|err| de::Error::custom(format!("Error reading Tag name. {:?}", err)))? .ok_or_else(|| de::Error::custom("Expected a name for the `Tag` name"))?; seq.next_element_seed(TagValues(name.as_str(), self.0))? .ok_or_else(|| de::Error::custom("Expected a seq of values for the `Tag`")) } } impl<'de, 'a> DeserializeSeed<'de> for TagValuesTuple<'a> { type Value = (); fn deserialize>(self, deserializer: D) -> Result<(), D::Error> { deserializer.deserialize_tuple(2, TagValuesTupleVisitor(self.0)) } } struct TagListVisitor; impl<'de> Visitor<'de> for TagListVisitor { type Value = TagList; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence of `Tag`s") } fn visit_seq>(self, mut seq: A) -> Result { let mut tag_list = TagList::new(); { let tag_list = tag_list.get_mut().unwrap(); while seq.next_element_seed(TagValuesTuple(tag_list))?.is_some() { // tags are added in the dedicated deserializers } } Ok(tag_list) } } impl<'de> Deserialize<'de> for TagList { fn deserialize>(deserializer: D) -> Result { deserializer.deserialize_seq(TagListVisitor) } } #[cfg(test)] mod tests { extern crate ron; use tags::*; use Buffer; use GenericFormattedValue; use Sample; use TagMergeMode; #[test] fn test_serialize() { ::init().unwrap(); let mut tags = TagList::new(); assert_eq!(tags.to_string(), "taglist;"); { let tags = tags.get_mut().unwrap(); tags.add::(&"a title", TagMergeMode::Append); // String tags.add::<Title>(&"another title", TagMergeMode::Append); // String tags.add::<Duration>(&(::SECOND * 120).into(), TagMergeMode::Append); // u64 tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32 tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64 tags.add::<DateTime>(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append); let sample = { let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]).unwrap(); { let buffer = buffer.get_mut().unwrap(); buffer.set_offset(0); buffer.set_offset_end(0); } Sample::new::<GenericFormattedValue>(Some(&buffer), None, None, None) }; tags.add::<Image>(&sample, TagMergeMode::Append); // Sample } let mut pretty_config = ron::ser::PrettyConfig::default(); pretty_config.new_line = "".to_string(); let res = ron::ser::to_string_pretty(&tags, pretty_config); assert_eq!( Ok(concat!( "[", " (\"title\", [", " \"a title\",", " \"another title\",", " ]),", " (\"duration\", [", " 120000000000,", " ]),", " (\"bitrate\", [", " 96000,", " ]),", " (\"replaygain-track-gain\", [", " 1,", " ]),", " (\"datetime\", [", " YMD(2018, 5, 28),", " ]),", " (\"image\", [", " (", " buffer: Some((", " pts: None,", " dts: None,", " duration: None,", " offset: 0,", " offset_end: 0,", " flags: (", " bits: 0,", " ),", " buffer: \"AQIDBA==\",", " )),", " buffer_list: None,", " caps: None,", " segment: Some((", " flags: (", " bits: 0,", " ),", " rate: 1,", " applied_rate: 1,", " format: Time,", " base: 0,", " offset: 0,", " start: 0,", " stop: -1,", " time: 0,", " position: 0,", " duration: -1,", " )),", " info: None,", " ),", " ]),", "]", ) .to_owned()), res, ); } #[test] fn test_deserialize() { extern crate serde_json; ::init().unwrap(); let tag_list_ron = r#" [ ("title", [ "a title", "another title", ]), ("duration", [120000000000]), ("bitrate", [96000]), ("replaygain-track-gain", [1]), ("datetime", [ YMD(2018, 5, 28), ]), ("image", [ ( buffer: Some(( pts: None, dts: None, duration: None, offset: 0, offset_end: 0, flags: ( bits: 0, ), buffer: "AQIDBA==", )), buffer_list: None, caps: None, segment: None, info: None, ), ]) ] "#; let tags: TagList = ron::de::from_str(tag_list_ron).unwrap(); assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title")); assert_eq!( tags.get_index::<Title>(1).unwrap().get(), Some("another title") ); assert_eq!( tags.get_index::<Duration>(0).unwrap().get(), Some(::SECOND * 120) ); assert_eq!(tags.get_index::<Bitrate>(0).unwrap().get(), Some(96_000)); assert_eq!(tags.get_index::<TrackGain>(0).unwrap().get(), Some(1f64)); let datetime = tags.get_index::<DateTime>(0).unwrap().get().unwrap(); assert_eq!(datetime.get_year(), 2018); assert_eq!(datetime.get_month(), 5); assert_eq!(datetime.get_day(), 28); let sample = tags.get_index::<Image>(0).unwrap().get().unwrap(); let buffer = sample.get_buffer().unwrap(); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } let tag_json = r#" [ ["title", ["a title", "another title"]], ["duration", [120000000000]], ["bitrate", [96000]], ["replaygain-track-gain", [1.0]], ["datetime",[{"YMD":[2018,5,28]}]], ["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}]] ] "#; let tags: TagList = serde_json::from_str(tag_json).unwrap(); assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title")); assert_eq!( tags.get_index::<Title>(1).unwrap().get(), Some("another title") ); assert_eq!(tags.get_index::<Bitrate>(0).unwrap().get(), Some(96_000)); assert_eq!(tags.get_index::<TrackGain>(0).unwrap().get(), Some(1f64)); let datetime = tags.get_index::<DateTime>(0).unwrap().get().unwrap(); assert_eq!(datetime.get_year(), 2018); assert_eq!(datetime.get_month(), 5); assert_eq!(datetime.get_day(), 28); let sample = tags.get_index::<Image>(0).unwrap().get().unwrap(); let buffer = sample.get_buffer().unwrap(); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } } #[test] fn test_serde_roundtrip() { ::init().unwrap(); let mut tags = TagList::new(); assert_eq!(tags.to_string(), "taglist;"); { let tags = tags.get_mut().unwrap(); tags.add::<Title>(&"a title", TagMergeMode::Append); // String tags.add::<Title>(&"another title", TagMergeMode::Append); // String tags.add::<Duration>(&(::SECOND * 120).into(), TagMergeMode::Append); // u64 tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32 tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64 tags.add::<DateTime>(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append); let sample = { let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]).unwrap(); { let buffer = buffer.get_mut().unwrap(); buffer.set_offset(0); buffer.set_offset_end(0); } Sample::new::<GenericFormattedValue>(Some(&buffer), None, None, None) }; tags.add::<Image>(&sample, TagMergeMode::Append); // Sample } let tags_ser = ron::ser::to_string(&tags).unwrap(); let tags_de: TagList = ron::de::from_str(tags_ser.as_str()).unwrap(); assert_eq!( tags_de.get_index::<Title>(0).unwrap().get(), tags.get_index::<Title>(0).unwrap().get(), ); assert_eq!( tags_de.get_index::<Title>(1).unwrap().get(), tags.get_index::<Title>(1).unwrap().get(), ); assert_eq!( tags_de.get_index::<Duration>(0).unwrap().get(), tags.get_index::<Duration>(0).unwrap().get(), ); assert_eq!( tags_de.get_index::<Bitrate>(0).unwrap().get(), tags.get_index::<Bitrate>(0).unwrap().get(), ); assert_eq!( tags_de.get_index::<TrackGain>(0).unwrap().get(), tags.get_index::<TrackGain>(0).unwrap().get(), ); let datetime = tags.get_index::<DateTime>(0).unwrap().get().unwrap(); assert_eq!(datetime.get_year(), 2018); assert_eq!(datetime.get_month(), 5); assert_eq!(datetime.get_day(), 28); let sample = tags.get_index::<Image>(0).unwrap().get().unwrap(); let buffer = sample.get_buffer().unwrap(); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } } }