diff --git a/gstreamer/Cargo.toml b/gstreamer/Cargo.toml index 40da955f3..11dab9cd2 100644 --- a/gstreamer/Cargo.toml +++ b/gstreamer/Cargo.toml @@ -43,7 +43,7 @@ embed-lgpl-docs = ["rustdoc-stripper"] purge-lgpl-docs = ["rustdoc-stripper"] dox = ["gstreamer-sys/dox", "glib/dox", "futures", "ser_de"] futures = ["futures-core-preview"] -ser_de = ["serde", "serde_derive"] +ser_de = ["num-rational/serde", "serde", "serde_derive"] default-features = [] [badges] diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 6f43bef24..4b624c287 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -73,6 +73,9 @@ pub mod miniobject; pub use miniobject::{GstRc, MiniObject}; pub mod message; pub use message::{Message, MessageErrorDomain, MessageRef, MessageView}; +#[macro_use] +mod value; +pub use value::*; pub mod structure; pub use structure::{Structure, StructureRef}; pub mod caps; @@ -184,9 +187,6 @@ pub use typefind::*; pub mod format; pub use format::{FormattedValue, GenericFormattedValue, SpecificFormattedValue}; -mod value; -pub use value::*; - mod segment; pub use segment::*; diff --git a/gstreamer/src/value.rs b/gstreamer/src/value.rs index 41d004476..18bffb71b 100644 --- a/gstreamer/src/value.rs +++ b/gstreamer/src/value.rs @@ -217,6 +217,7 @@ impl SetValue for Fraction { } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "ser_de", derive(Serialize, Deserialize))] pub struct IntRange { min: T, max: T, @@ -354,6 +355,7 @@ impl SetValue for IntRange { } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "ser_de", derive(Serialize, Deserialize))] pub struct FractionRange { min: Fraction, max: Fraction, @@ -427,6 +429,7 @@ impl SetValue for FractionRange { } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "ser_de", derive(Serialize, Deserialize))] pub struct Bitmask(pub u64); impl Bitmask { @@ -854,3 +857,540 @@ impl GstValueExt for glib::Value { } } } + +#[cfg(feature = "ser_de")] +#[macro_use] +pub(crate) mod serde { + use glib; + use glib::{StaticType, ToValue}; + + use num_rational::Rational32; + + use serde::de; + use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; + use serde::ser; + use serde::ser::{Serialize, Serializer, SerializeTuple}; + + use std::mem; + + use DateTime; + //use Sample; + + use super::*; + + pub const ARRAY_TYPE_NAME: &'static str = "Array"; + pub const LIST_TYPE_NAME: &'static str = "List"; + + fn get_other_type_id() -> usize { + match T::static_type() { + glib::Type::Other(type_id) => type_id, + type_ => panic!("Expecting `Other` variant, found `{}`", type_), + } + } + + lazy_static! { + pub(crate) static ref ARRAY_OTHER_TYPE_ID: usize = get_other_type_id::(); + pub(crate) static ref BITMASK_OTHER_TYPE_ID: usize = get_other_type_id::(); + pub(crate) static ref DATE_TIME_OTHER_TYPE_ID: usize = get_other_type_id::(); + pub(crate) static ref FRACTION_OTHER_TYPE_ID: usize = get_other_type_id::(); + pub(crate) static ref FRACTION_RANGE_OTHER_TYPE_ID: usize = + get_other_type_id::(); + pub(crate) static ref INT_RANGE_I32_OTHER_TYPE_ID: usize = + get_other_type_id::>(); + pub(crate) static ref INT_RANGE_I64_OTHER_TYPE_ID: usize = + get_other_type_id::>(); + pub(crate) static ref LIST_OTHER_TYPE_ID: usize = get_other_type_id::(); + //pub(crate) static ref SAMPLE_OTHER_TYPE_ID: usize = get_other_type_id::(); + } + + impl<'a> Serialize for Fraction { + fn serialize(&self, serializer: S) -> Result { + self.0.serialize(serializer) + } + } + + impl<'de> Deserialize<'de> for Fraction { + fn deserialize>(deserializer: D) -> Result { + Rational32::deserialize(deserializer) + .and_then(|rational| Ok(Fraction::new(*rational.numer(), *rational.denom()))) + } + } + + macro_rules! ser_value ( + ($value:expr, $t_str:expr, $t:ty, $ser_closure:expr) => ( + { + let value = $value.get::<$t>().unwrap(); + $ser_closure($t_str, value) + } + ); + ($value:expr, $ser_closure:expr) => ( + match $value.type_() { + glib::Type::I8 => ser_value!($value, "i8", i8, $ser_closure), + glib::Type::U8 => ser_value!($value, "ui8", u8, $ser_closure), + glib::Type::Bool => ser_value!($value, "bool", bool, $ser_closure), + glib::Type::I32 => ser_value!($value, "i32", i32, $ser_closure), + glib::Type::U32 => ser_value!($value, "u32", u32, $ser_closure), + glib::Type::ILong => ser_value!($value, "ilong", i32, $ser_closure), + glib::Type::ULong => ser_value!($value, "ulong", u32, $ser_closure), + glib::Type::I64 => ser_value!($value, "i64", i64, $ser_closure), + glib::Type::U64 => ser_value!($value, "u64", u64, $ser_closure), + glib::Type::F32 => ser_value!($value, "f32", f32, $ser_closure), + glib::Type::F64 => ser_value!($value, "f64", f64, $ser_closure), + glib::Type::String => ser_value!($value, "String", String, $ser_closure), + glib::Type::Other(type_id) => { + if *ARRAY_OTHER_TYPE_ID == type_id { + ser_value!($value, ARRAY_TYPE_NAME, Array, $ser_closure) + } else if *BITMASK_OTHER_TYPE_ID == type_id { + ser_value!($value, "Bitmask", Bitmask, $ser_closure) + } else if *DATE_TIME_OTHER_TYPE_ID == type_id { + ser_value!($value, "DateTime", DateTime, $ser_closure) + } else if *FRACTION_OTHER_TYPE_ID == type_id { + ser_value!($value, "Fraction", Fraction, $ser_closure) + } else if *FRACTION_RANGE_OTHER_TYPE_ID == type_id { + ser_value!($value, "FractionRange", FractionRange, $ser_closure) + } else if *INT_RANGE_I32_OTHER_TYPE_ID == type_id { + ser_value!($value, "IntRange", IntRange, $ser_closure) + } else if *INT_RANGE_I64_OTHER_TYPE_ID == type_id { + ser_value!($value, "IntRange", IntRange, $ser_closure) + } else if *LIST_OTHER_TYPE_ID == type_id { + ser_value!($value, LIST_TYPE_NAME, List, $ser_closure) + /*} else if *SAMPLE_OTHER_TYPE_ID == type_id { + ser_value!($value, "Sample", Sample, $ser_closure)*/ + } else { + Err( + ser::Error::custom( + format!("unimplemented `Value` serialization for type {}", + glib::Type::Other(type_id), + ) + ) + ) + } + } + type_ => { + Err( + ser::Error::custom( + format!("unimplemented `Value` serialization for type {}", type_) + ) + ) + } + } + ) + ); + + pub(crate) struct SendValue(glib::SendValue); + impl SendValue { + pub(crate) fn from(send_value: glib::SendValue) -> Self { + SendValue(send_value) + } + } + + impl From for glib::SendValue { + fn from(send_value: SendValue) -> Self { + send_value.0 + } + } + + impl Serialize for SendValue { + fn serialize(&self, serializer: S) -> Result { + ser_value!(self.0, |type_, value| { + let mut tup = serializer.serialize_tuple(2)?; + tup.serialize_element(type_)?; + tup.serialize_element(&value)?; + tup.end() + }) + } + } + + macro_rules! impl_ser_send_value_collection ( + ($t:ident) => ( + impl<'a> Serialize for $t<'a> { + fn serialize(&self, serializer: S) -> Result { + let send_value_vec = unsafe { + mem::transmute::<&[glib::SendValue], &[SendValue]>( + self.as_slice() + ) + }; + send_value_vec.serialize(serializer) + } + } + ); + ); + + impl_ser_send_value_collection!(Array); + impl_ser_send_value_collection!(List); + + macro_rules! de_value( + ($outer_type:expr, $type_name:expr, $seq:expr, $t:ty) => ( + $seq + .next_element::<$t>()? + .ok_or_else(|| + de::Error::custom(format!( + "Expected a value for `{}` with type {:?}, found `None`", + $outer_type, + $type_name, + )) + )? + .to_value() + ); + ); + + macro_rules! de_send_value( + ($type_name:expr, $seq:expr, $t:ty) => ( + SendValue::from( + de_value!("Value", $type_name, $seq, $t) + .try_into_send_value::<$t>() + .map_err(|_| + de::Error::custom(format!( + "Failed to convert `Value` with type {:?} to `SendValue`", + $type_name, + )) + )? + ) + ); + ($type_name:expr, $seq:expr) => ( + match $type_name.as_str() { + "i8" => de_send_value!($type_name, $seq, i8), + "u8" => de_send_value!($type_name, $seq, u8), + "bool" => de_send_value!($type_name, $seq, bool), + "i32" => de_send_value!($type_name, $seq, i32), + "u32" => de_send_value!($type_name, $seq, u32), + "ilong" => de_send_value!($type_name, $seq, i32), + "ulong" => de_send_value!($type_name, $seq, u32), + "i64" => de_send_value!($type_name, $seq, i64), + "u64" => de_send_value!($type_name, $seq, u64), + "f32" => de_send_value!($type_name, $seq, f32), + "f64" => de_send_value!($type_name, $seq, f64), + "String" => de_send_value!($type_name, $seq, String), + "Array" => de_send_value!($type_name, $seq, Array), + "Bitmask" => de_send_value!($type_name, $seq, Bitmask), + "DateTime" => de_send_value!($type_name, $seq, DateTime), + "Fraction" => de_send_value!($type_name, $seq, Fraction), + "FractionRange" => de_send_value!($type_name, $seq, FractionRange), + "IntRange" => de_send_value!($type_name, $seq, IntRange), + "IntRange" => de_send_value!($type_name, $seq, IntRange), + //"Sample" => de_send_value!($type_name, $seq, Sample), + _ => return Err( + de::Error::custom( + format!( + "unimplemented deserialization for `Value` with type `{}`", + $type_name, + ), + ) + ), + } + ); + ); + + struct SendValueVisitor; + impl<'de> Visitor<'de> for SendValueVisitor { + type Value = SendValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a tuple of 2 elements (type name: String, value: Value type)") + } + + fn visit_seq>(self, mut seq: A) -> Result { + let type_name = seq.next_element::()? + .ok_or(de::Error::custom("Expected a value for `Value` type, found `None`"))?; + Ok(de_send_value!(type_name, seq)) + } + } + + impl<'de> Deserialize<'de> for SendValue { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_tuple(2, SendValueVisitor{}) + } + } + + macro_rules! impl_de_send_value_collection ( + ($t:ident) => { + impl<'a, 'de> Deserialize<'de> for $t<'a> { + fn deserialize>(deserializer: D) -> Result { + let send_value_vec = Vec::::deserialize(deserializer)?; + Ok($t(Cow::Owned(unsafe{ + mem::transmute::, Vec>(send_value_vec) + }))) + } + } + } + ); + + impl_de_send_value_collection!(Array); + impl_de_send_value_collection!(List); +} + +#[cfg(test)] +mod tests { + #[cfg(feature = "ser_de")] + #[test] + fn test_serialize_simple() { + extern crate ron; + extern crate serde_json; + + use Fraction; + use FractionRange; + use IntRange; + use Bitmask; + + ::init().unwrap(); + + let mut pretty_config = ron::ser::PrettyConfig::default(); + pretty_config.new_line = "".to_string(); + + // Fraction + let fraction = Fraction::new(1, 3); + + let res = ron::ser::to_string_pretty(&fraction, pretty_config.clone()); + assert_eq!(Ok("(1, 3)".to_owned()), res); + + let res = serde_json::to_string(&fraction).unwrap(); + assert_eq!("[1,3]".to_owned(), res); + + // FractionRange + let fraction_range = FractionRange::new(Fraction::new(1, 3), Fraction::new(1, 2)); + + let res = ron::ser::to_string_pretty(&fraction_range, pretty_config.clone()); + assert_eq!( + Ok( + concat!( + "(", + " min: (1, 3),", + " max: (1, 2),", + ")" + ) + .to_owned() + ), + res, + ); + + let res = serde_json::to_string(&fraction_range).unwrap(); + assert_eq!("{\"min\":[1,3],\"max\":[1,2]}".to_owned(), res); + + // IntRange + let int_range = IntRange::::new_with_step(0, 42, 21); + let res = ron::ser::to_string_pretty(&int_range, pretty_config.clone()); + assert_eq!( + Ok( + concat!( + "(", + " min: 0,", + " max: 42,", + " step: 21,", + ")" + ) + .to_owned() + ), + res, + ); + + let res = serde_json::to_string(&int_range).unwrap(); + assert_eq!("{\"min\":0,\"max\":42,\"step\":21}".to_owned(), res); + + // Bitmask + let bitmask = Bitmask::new(1024 + 128 + 32); + + let res = ron::ser::to_string_pretty(&bitmask, pretty_config.clone()); + assert_eq!(Ok("(1184)".to_owned()), res); + + let res = serde_json::to_string(&bitmask).unwrap(); + assert_eq!("1184".to_owned(), res); + } + + #[cfg(feature = "ser_de")] + #[test] + fn test_serialize_collections() { + extern crate ron; + extern crate serde_json; + + use glib::value::ToValue; + + use Array; + use Fraction; + use List; + + ::init().unwrap(); + + let mut pretty_config = ron::ser::PrettyConfig::default(); + pretty_config.new_line = "".to_string(); + + // Array + let value_13 = Fraction::new(1, 3).to_value(); + let send_value_13 = value_13.try_into_send_value::().unwrap(); + + let value_12 = Fraction::new(1, 2).to_value(); + let send_value_12 = value_12.try_into_send_value::().unwrap(); + + let value_str = "test str".to_value(); + let send_value_str = value_str.try_into_send_value::().unwrap(); + + let array = Array::new(&[&send_value_13, &send_value_12, &send_value_str]); + + let res = ron::ser::to_string_pretty(&array, pretty_config.clone()); + assert_eq!( + Ok( + concat!( + "[", + " (\"Fraction\", (1, 3)),", + " (\"Fraction\", (1, 2)),", + " (\"String\", \"test str\"),", + "]" + ) + .to_owned() + ), + res, + ); + + let res = serde_json::to_string(&array).unwrap(); + assert_eq!( + "[[\"Fraction\",[1,3]],[\"Fraction\",[1,2]],[\"String\",\"test str\"]]" + .to_owned(), + res + ); + + // List + let value_12 = Fraction::new(1, 2).to_value(); + let send_value_12 = value_12.try_into_send_value::().unwrap(); + + let value_str = "test str".to_value(); + let send_value_str = value_str.try_into_send_value::().unwrap(); + + let list = List::new(&[&send_value_12, &send_value_str]); + + let res = ron::ser::to_string_pretty(&list, pretty_config.clone()); + assert_eq!( + Ok( + concat!( + "[", + " (\"Fraction\", (1, 2)),", + " (\"String\", \"test str\"),", + "]" + ) + .to_owned() + ), + res, + ); + } + + #[cfg(feature = "ser_de")] + #[test] + fn test_deserialize_simple() { + extern crate ron; + extern crate serde_json; + + use Fraction; + use FractionRange; + use IntRange; + use Bitmask; + + ::init().unwrap(); + + // Fraction + let fraction_ron = "(1, 3)"; + let fraction: Fraction = ron::de::from_str(fraction_ron).unwrap(); + assert_eq!(fraction.0.numer(), &1); + assert_eq!(fraction.0.denom(), &3); + + let fraction_json = "[1,3]"; + let fraction: Fraction = serde_json::from_str(fraction_json).unwrap(); + assert_eq!(fraction.0.numer(), &1); + assert_eq!(fraction.0.denom(), &3); + + // FractionRange + let fraction_range_ron = "(min: (1, 3), max: (1, 2))"; + let fraction_range: FractionRange = ron::de::from_str(fraction_range_ron).unwrap(); + assert_eq!(fraction_range.min().0.denom(), &3); + assert_eq!(fraction_range.max().0.denom(), &2); + + let fraction_range_json = "{\"min\":[1,3],\"max\":[1,2]}"; + let fraction_range: FractionRange = serde_json::from_str(fraction_range_json).unwrap(); + assert_eq!(fraction_range.min().0.denom(), &3); + assert_eq!(fraction_range.max().0.denom(), &2); + + // IntRange + let int_range_ron = "(min: 0, max: 42, step: 21)"; + let int_range: IntRange = ron::de::from_str(int_range_ron).unwrap(); + assert_eq!(int_range.min(), 0); + assert_eq!(int_range.max(), 42); + assert_eq!(int_range.step(), 21); + + let int_range_json = "{\"min\":0,\"max\":42,\"step\":21}"; + let int_range: IntRange = serde_json::from_str(int_range_json).unwrap(); + assert_eq!(int_range.min(), 0); + assert_eq!(int_range.max(), 42); + assert_eq!(int_range.step(), 21); + + // Bitmask + let bitmask_ref = Bitmask::new(1024 + 128 + 32); + + let bitmask_ron = "(1184)"; + let bitmask: Bitmask = ron::de::from_str(bitmask_ron).unwrap(); + assert_eq!(bitmask_ref, bitmask); + + let bitmask_json = "1184"; + let bitmask: Bitmask = serde_json::from_str(bitmask_json).unwrap(); + assert_eq!(bitmask_ref, bitmask); + } + + #[cfg(feature = "ser_de")] + #[test] + fn test_deserialize_collections() { + extern crate ron; + extern crate serde_json; + + use Array; + use Fraction; + use List; + + ::init().unwrap(); + + // Array + let array_ron = + r#"[ + ("Fraction", (1, 3)), + ("Fraction", (1, 2)), + ("String", "test str"), + ]"#; + let array: Array = ron::de::from_str(array_ron).unwrap(); + assert_eq!(3, array.0.len()); + + let fraction = array.0[0].get::().unwrap(); + assert_eq!(fraction.0.numer(), &1); + assert_eq!(fraction.0.denom(), &3); + + let fraction = array.0[1].get::().unwrap(); + assert_eq!(fraction.0.numer(), &1); + assert_eq!(fraction.0.denom(), &2); + + assert_eq!("test str".to_owned(), array.0[2].get::().unwrap()); + + let array_json = + r#"[["Fraction",[1,3]],["Fraction",[1,2]],["String","test str"]]"#; + let array: Array = serde_json::from_str(array_json).unwrap(); + assert_eq!(3, array.0.len()); + + let fraction = array.0[0].get::().unwrap(); + assert_eq!(fraction.0.numer(), &1); + assert_eq!(fraction.0.denom(), &3); + + let fraction = array.0[1].get::().unwrap(); + assert_eq!(fraction.0.numer(), &1); + assert_eq!(fraction.0.denom(), &2); + + assert_eq!("test str".to_owned(), array.0[2].get::().unwrap()); + + // List + let list_ron = + r#"[ + ("Fraction", (1, 2)), + ("String", "test str"), + ]"#; + let list: List = ron::de::from_str(list_ron).unwrap(); + assert_eq!(2, list.0.len()); + + let fraction = list.0[0].get::().unwrap(); + assert_eq!(fraction.0.numer(), &1); + assert_eq!(fraction.0.denom(), &2); + + assert_eq!("test str".to_owned(), list.0[1].get::().unwrap()); + } +}