diff --git a/gstreamer/src/structure.rs b/gstreamer/src/structure.rs index 092575b7e..b2835da05 100644 --- a/gstreamer/src/structure.rs +++ b/gstreamer/src/structure.rs @@ -655,6 +655,171 @@ impl Builder { } } +#[cfg(feature = "ser_de")] +pub(crate) mod serde { + use glib; + use glib::ToValue; + + use serde::de; + use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; + use serde::ser; + use serde::ser::{Serialize, Serializer, SerializeSeq, SerializeTuple}; + + use std::fmt; + + use DateTime; + //use Sample; + + use value::*; + use value::serde::*; + + use Structure; + use StructureRef; + + struct FieldSe<'a>(&'a str, &'a glib::SendValue); + impl<'a> Serialize for FieldSe<'a> { + fn serialize(&self, serializer: S) -> Result { + ser_value!(self.1, |type_, value| { + let mut tup = serializer.serialize_tuple(3)?; + tup.serialize_element(self.0)?; + tup.serialize_element(type_)?; + tup.serialize_element(&value)?; + tup.end() + }) + } + } + + struct StructureForIter<'a>(&'a StructureRef); + impl<'a> Serialize for StructureForIter<'a> { + fn serialize(&self, serializer: S) -> Result { + let iter = self.0.iter(); + let size = iter.size_hint().0; + if size > 0 { + let mut seq = serializer.serialize_seq(Some(size))?; + for field in iter { + seq.serialize_element(&FieldSe(field.0, field.1))?; + } + seq.end() + } else { + let seq = serializer.serialize_seq(None)?; + seq.end() + } + } + } + + impl Serialize for StructureRef { + fn serialize(&self, serializer: S) -> Result { + let mut tup = serializer.serialize_tuple(2)?; + tup.serialize_element(self.get_name())?; + tup.serialize_element(&StructureForIter(self))?; + tup.end() + } + } + + impl Serialize for Structure { + fn serialize(&self, serializer: S) -> Result { + self.as_ref().serialize(serializer) + } + } + + struct FieldDe(String, SendValue); + impl From for (String, glib::SendValue) { + fn from(field_de: FieldDe) -> Self { + (field_de.0, field_de.1.into()) + } + } + + struct FieldVisitor; + impl<'de> Visitor<'de> for FieldVisitor { + type Value = FieldDe; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str( + "a tuple of 3 elements (name: `String`, type name: `String`, value: `Value`)" + ) + } + + fn visit_seq>(self, mut seq: A) -> Result { + let name = seq.next_element::()? + .ok_or(de::Error::custom("Expected a value for `Value` name, found `None`"))?; + let type_name = seq.next_element::()? + .ok_or(de::Error::custom("Expected a value for `Value` type, found `None`"))?; + Ok(FieldDe(name, de_send_value!(type_name, seq))) + } + } + + impl<'de> Deserialize<'de> for FieldDe { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_tuple(3, FieldVisitor) + } + } + + // Use `NamelessStructure` to deserialize the `Field`s and + // to add them to the `Structure` at the same time. + struct NamelessStructure(Structure); + impl From for Structure { + fn from(nameless_structure: NamelessStructure) -> Self { + nameless_structure.0 + } + } + + struct NamelessStructureVisitor; + impl<'de> Visitor<'de> for NamelessStructureVisitor { + type Value = NamelessStructure; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a nameless `Structure` consisting of a sequence of `Field`s)") + } + + fn visit_seq>(self, mut seq: A) -> Result { + // Can't build a `Structure` with an empty name + let mut structure = Structure::new_empty("None"); + while let Some(field) = seq.next_element::()? { + let (name, value): (String, glib::SendValue) = field.into(); + structure.as_mut().set_value(name.as_str(), value); + } + + Ok(NamelessStructure(structure)) + } + } + + impl<'de> Deserialize<'de> for NamelessStructure { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_seq(NamelessStructureVisitor) + } + } + + struct StructureVisitor; + impl<'de> Visitor<'de> for StructureVisitor { + type Value = Structure; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a `Structure`: (name: `String`, fields: sequence of `Field`s)") + } + + fn visit_seq>(self, mut seq: A) -> Result { + let name = seq.next_element::()? + .ok_or(de::Error::custom( + "Expected a name for the `Structure`, found `None`" + ))?; + let mut structure: Structure = seq.next_element::()? + .ok_or(de::Error::custom( + "Expected a sequence of `Field`s, found `None`" + ))? + .into(); + structure.set_name(name.as_str()); + + Ok(structure) + } + } + + impl<'de> Deserialize<'de> for Structure { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_tuple(2, StructureVisitor) + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -715,4 +880,82 @@ mod tests { assert_eq!(a, s.to_string()); } + + #[cfg(feature = "ser_de")] + #[test] + fn test_serialize() { + extern crate ron; + + use Array; + + ::init().unwrap(); + + let s = Structure::builder("test") + .field("f1", &"abc") + .field("f2", &String::from("bcd")) + .field("f3", &123i32) + .field("fraction", &Fraction::new(1, 2)) + .field("array", &Array::new(&[&1, &2])) + .build(); + + // don't use newlines + let mut pretty_config = ron::ser::PrettyConfig::default(); + pretty_config.new_line = "".to_string(); + + let res = ron::ser::to_string_pretty(&s, pretty_config); + assert_eq!( + Ok( + concat!( + "(\"test\", [", + " (\"f1\", \"String\", \"abc\"),", + " (\"f2\", \"String\", \"bcd\"),", + " (\"f3\", \"i32\", 123),", + " (\"fraction\", \"Fraction\", (1, 2)),", + " (\"array\", \"Array\", [", + " (\"i32\", 1),", + " (\"i32\", 2),", + " ]),", + "])" + ) + .to_owned() + ), + res, + ); + } + + #[cfg(feature = "ser_de")] + #[test] + fn test_deserialize() { + extern crate ron; + + use Array; + + ::init().unwrap(); + + let s_ron = r#" + ("test", [ + ("f1", "String", "abc"), + ("f2", "String", "bcd"), + ("f3", "i32", 123), + ("fraction", "Fraction", (1, 2)), + ("array", "Array", [ + ("i32", 1), + ("i32", 2), + ]), + ])"#; + let s: Structure = ron::de::from_str(s_ron).unwrap(); + assert_eq!( + s.as_ref(), + Structure::new( + "test", + &[ + ("f1", &"abc"), + ("f2", &"bcd"), + ("f3", &123), + ("fraction", &Fraction::new(1, 2)), + ("array", &Array::new(&[&1, &2])), + ], + ).as_ref() + ); + } }