From ced522ed088a2280f0828419a0366ce960b68964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= Date: Mon, 19 Aug 2019 15:32:40 +0200 Subject: [PATCH] Implement ser / de for Date Values, Structure fields and Tags --- gstreamer/src/date_time_serde.rs | 85 +++++++++++++++- gstreamer/src/structure_serde.rs | 45 +++++++-- gstreamer/src/tags_serde.rs | 168 +++++++++++++++++++------------ gstreamer/src/value_serde.rs | 158 ++++++++++++++++++++++++----- 4 files changed, 355 insertions(+), 101 deletions(-) diff --git a/gstreamer/src/date_time_serde.rs b/gstreamer/src/date_time_serde.rs index 24a68a3b7..ce5af5d1b 100644 --- a/gstreamer/src/date_time_serde.rs +++ b/gstreamer/src/date_time_serde.rs @@ -6,7 +6,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use serde::de::{Deserialize, Deserializer}; +use std::convert::{TryFrom, TryInto}; + +use glib::translate::{FromGlib, ToGlib}; +use glib::value::{SetValue, SetValueOptional}; +use glib::StaticType; + +use serde::de::{Deserialize, Deserializer, Error}; use serde::ser; use serde::ser::{Serialize, Serializer}; use DateTime; @@ -20,6 +26,47 @@ enum DateTimeVariants { YMDhmsTz(i32, i32, i32, i32, i32, f64, f32), } +// Note: ser / de for `glib::Date` should be implemented in the `glib` crate +// However, there is no `ser_de` feature in `glib` right now. The limitation is that +// `Date` fields can only be ser / de when they are used in `Value`s (which implies +// `Array`s, `List`s, `Structure` fields and `Tag`s) +pub(crate) struct Date(glib::Date); + +impl From for Date { + fn from(glib_date: glib::Date) -> Self { + Date(glib_date) + } +} + +impl SetValue for Date { + unsafe fn set_value(value: &mut glib::Value, this: &Self) { + glib::value::SetValue::set_value(value, &this.0); + } +} + +impl SetValueOptional for Date { + unsafe fn set_value_optional(value: &mut glib::Value, this: Option<&Self>) { + glib::value::SetValueOptional::set_value_optional(value, this.map(|this| &this.0)); + } +} + +impl StaticType for Date { + fn static_type() -> glib::Type { + glib::Date::static_type() + } +} + +impl<'a> Serialize for Date { + fn serialize(&self, serializer: S) -> Result { + DateTimeVariants::YMD( + self.0.get_year() as i32, + self.0.get_month().to_glib() as i32, + self.0.get_day() as i32, + ) + .serialize(serializer) + } +} + impl<'a> Serialize for DateTime { fn serialize(&self, serializer: S) -> Result { let variant = if self.has_second() { @@ -58,6 +105,35 @@ impl<'a> Serialize for DateTime { } } +impl TryFrom for Date { + type Error = &'static str; + + fn try_from(dt_variant: DateTimeVariants) -> Result { + match dt_variant { + DateTimeVariants::YMD(y, m, d) => { + let month = glib::DateMonth::from_glib(m); + if let glib::DateMonth::__Unknown(_) = month { + return Err("Out of range `month` for `Date`"); + } + + Ok(Date(glib::Date::new_dmy( + d.try_into().map_err(|_| "Out of range `day` for `Date`")?, + month, + y.try_into().map_err(|_| "Out of range `year` for `Date`")?, + ))) + } + _ => Err("Incompatible variant for `Date` (expecting \"YMD\")"), + } + } +} + +impl<'de> Deserialize<'de> for Date { + fn deserialize>(deserializer: D) -> Result { + DateTimeVariants::deserialize(deserializer) + .and_then(|dt_variant| dt_variant.try_into().map_err(|err| D::Error::custom(err))) + } +} + #[allow(clippy::many_single_char_names)] impl From for DateTime { fn from(dt_variant: DateTimeVariants) -> Self { @@ -104,7 +180,7 @@ mod tests { let res = serde_json::to_string(&datetime).unwrap(); assert_eq!( - "{\"YMDhmsTz\":[2018,5,28,16,6,42.123456,2.0]}".to_owned(), + r#"{"YMDhmsTz":[2018,5,28,16,6,42.123456,2.0]}"#.to_owned(), res ); @@ -129,6 +205,9 @@ mod tests { fn test_deserialize() { ::init().unwrap(); + // FIXME: compare `DateTime`s instances + // See https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/217 + let datetime_ron = "YMDhmsTz(2018, 5, 28, 16, 6, 42.123456, 2)"; let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); assert_eq!(datetime_de.get_time_zone_offset(), 2f32); @@ -140,7 +219,7 @@ mod tests { assert_eq!(datetime_de.get_second(), 42); assert_eq!(datetime_de.get_microsecond(), 123_456); - let datetime_json = "{\"YMDhmsTz\":[2018,5,28,16,6,42.123456,2.0]}"; + let datetime_json = r#"{"YMDhmsTz":[2018,5,28,16,6,42.123456,2.0]}"#; let datetime_de: DateTime = serde_json::from_str(datetime_json).unwrap(); assert_eq!(datetime_de.get_time_zone_offset(), 2f32); assert_eq!(datetime_de.get_year(), 2018); diff --git a/gstreamer/src/structure_serde.rs b/gstreamer/src/structure_serde.rs index 052bff0c0..654820c26 100644 --- a/gstreamer/src/structure_serde.rs +++ b/gstreamer/src/structure_serde.rs @@ -7,7 +7,7 @@ // except according to those terms. use glib; -use glib::ToValue; +use glib::{Date, ToValue}; use serde::de; use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; @@ -20,6 +20,7 @@ use Buffer; use DateTime; use Sample; +use date_time_serde; use value::*; use value_serde::*; @@ -166,7 +167,10 @@ impl<'de> Deserialize<'de> for Structure { mod tests { extern crate ron; + use glib::{Date, DateMonth}; + use Array; + use DateTime; use Fraction; use Structure; @@ -179,6 +183,11 @@ mod tests { .field("f2", &String::from("bcd")) .field("f3", &123i32) .field("fraction", &Fraction::new(1, 2)) + .field("date", &Date::new_dmy(19, DateMonth::August, 2019)) + .field( + "date_time", + &DateTime::new(2f32, 2019, 8, 19, 13, 34, 42f64), + ) .field("array", &Array::new(&[&1, &2])) .build(); @@ -188,16 +197,18 @@ mod tests { let res = ron::ser::to_string_pretty(&s, pretty_config); assert_eq!( Ok(concat!( - "(\"test\", [", - " (\"f1\", \"String\", Some(\"abc\")),", - " (\"f2\", \"String\", Some(\"bcd\")),", - " (\"f3\", \"i32\", 123),", - " (\"fraction\", \"Fraction\", (1, 2)),", - " (\"array\", \"Array\", [", - " (\"i32\", 1),", - " (\"i32\", 2),", - " ]),", - "])" + r#"("test", ["#, + r#" ("f1", "String", Some("abc")),"#, + r#" ("f2", "String", Some("bcd")),"#, + r#" ("f3", "i32", 123),"#, + r#" ("fraction", "Fraction", (1, 2)),"#, + r#" ("date", "Date", Some(YMD(2019, 8, 19))),"#, + r#" ("date_time", "DateTime", Some(YMDhmsTz(2019, 8, 19, 13, 34, 42, 2))),"#, + r#" ("array", "Array", ["#, + r#" ("i32", 1),"#, + r#" ("i32", 2),"#, + r#" ]),"#, + r#"])"#, ) .to_owned()), res, @@ -214,6 +225,8 @@ mod tests { ("f2", "String", Some("bcd")), ("f3", "i32", 123), ("fraction", "Fraction", (1, 2)), + ("date", "Date", Some(YMD(2019, 8, 19))), + ("date_time", "DateTime", Some(YMDhmsTz(2019, 8, 19, 13, 34, 42, 2))), ("array", "Array", [ ("i32", 1), ("i32", 2), @@ -228,6 +241,11 @@ mod tests { ("f1", &"abc"), ("f2", &"bcd"), ("f3", &123), + ("date", &Date::new_dmy(19, DateMonth::August, 2019)), + ( + "date_time", + &DateTime::new(2f32, 2019, 8, 19, 13, 34, 42f64) + ), ("fraction", &Fraction::new(1, 2)), ("array", &Array::new(&[&1, &2])), ], @@ -245,6 +263,11 @@ mod tests { .field("f2", &"bcd".to_owned()) .field("f3", &123i32) .field("fraction", &Fraction::new(1, 2)) + .field("date", &Date::new_dmy(19, DateMonth::August, 2019)) + .field( + "date_time", + &DateTime::new(2f32, 2019, 8, 19, 13, 34, 42f64), + ) .field("array", &Array::new(&[&1, &2])) .build(); let s_ser = ron::ser::to_string(&s).unwrap(); diff --git a/gstreamer/src/tags_serde.rs b/gstreamer/src/tags_serde.rs index 8f065a987..dd3beec03 100644 --- a/gstreamer/src/tags_serde.rs +++ b/gstreamer/src/tags_serde.rs @@ -8,7 +8,7 @@ use glib; use glib::translate::{from_glib, ToGlibPtr}; -use glib::{SendValue, ToValue}; +use glib::{Date, SendValue, ToValue}; use gst_sys; use serde::de; @@ -20,8 +20,9 @@ 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 date_time_serde; +use tags::{GenericTagIter, TagList, TagListRef}; +use value_serde::{DATE_OTHER_TYPE_ID, DATE_TIME_OTHER_TYPE_ID, SAMPLE_OTHER_TYPE_ID}; use DateTime; use Sample; use TagMergeMode; @@ -46,8 +47,6 @@ macro_rules! ser_opt_tag ( // to be Non-null and non-empty in the C API. See: // https://gitlab.freedesktop.org/gstreamer/gstreamer/blob/d90d771a9a512381315f7694c3a50b152035f3cb/gst/gststructure.c#L810-853 -// FIXME: implement serde for type `Date` - // serialize trait is only available for `&self`, but we need to mutate the iterator struct TagValuesSer<'a>(Rc>>); impl<'a> TagValuesSer<'a> { @@ -68,13 +67,22 @@ impl<'a> Serialize for TagValuesSer<'a> { glib::Type::String => { // See above comment about `Tag`s with `String` values ser_opt_value!(value, String, |_, value: Option| { - seq.serialize_element(&value.expect("string tag ser")) + seq.serialize_element(&value.expect("String tag ser")) }) } glib::Type::U32 => ser_some_tag!(value, seq, u32), glib::Type::U64 => ser_some_tag!(value, seq, u64), glib::Type::Other(type_id) => { - if *DATE_TIME_OTHER_TYPE_ID == type_id { + if *DATE_OTHER_TYPE_ID == type_id { + // See above comment about `Tag`s with `Date` values + ser_opt_value!(value, Date, |_, value: Option| { + // Need to wrap the `glib::Date` in new type `date_time_serde::Date` first + // See comment in `date_time_serde.rs` + seq.serialize_element(&date_time_serde::Date::from( + value.expect("Date tag ser"), + )) + }) + } else if *DATE_TIME_OTHER_TYPE_ID == type_id { ser_opt_tag!(value, seq, DateTime) } else if *SAMPLE_OTHER_TYPE_ID == type_id { ser_opt_tag!(value, seq, Sample) @@ -183,7 +191,12 @@ impl<'de, 'a> Visitor<'de> for TagValuesVisitor<'a> { glib::Type::U32 => de_some_tag!(self.0, seq, u32), glib::Type::U64 => de_some_tag!(self.0, seq, u64), glib::Type::Other(type_id) => { - if *DATE_TIME_OTHER_TYPE_ID == type_id { + if *DATE_OTHER_TYPE_ID == type_id { + // See comment above `TagValuesSer` definition about `Tag`s with `Date` values + // Need to deserialize as `date_time_serde::Date` new type + // See comment in `date_time_serde.rs` + de_send_value!("Tag", self.0, seq, date_time_serde::Date, Date) + } else if *DATE_TIME_OTHER_TYPE_ID == type_id { de_opt_tag!(self.0, seq, DateTime) } else if *SAMPLE_OTHER_TYPE_ID == type_id { de_opt_tag!(self.0, seq, Sample) @@ -328,6 +341,10 @@ mod tests { tags.add::(&(::SECOND * 120).into(), TagMergeMode::Append); // u64 tags.add::(&96_000, TagMergeMode::Append); // u32 tags.add::(&1f64, TagMergeMode::Append); // f64 + tags.add::( + &glib::Date::new_dmy(28, glib::DateMonth::May, 2018), + TagMergeMode::Append, + ); tags.add::(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append); let sample = { @@ -348,60 +365,63 @@ mod tests { let res = ron::ser::to_string_pretty(&tags, pretty_config); assert_eq!( Ok(concat!( - "(", - " scope: Stream,", - " tags: [", - " (\"title\", [", - " \"a title\",", - " \"another title\",", - " ]),", - " (\"duration\", [", - " 120000000000,", - " ]),", - " (\"bitrate\", [", - " 96000,", - " ]),", - " (\"replaygain-track-gain\", [", - " 1,", - " ]),", - " (\"datetime\", [", - " Some(YMD(2018, 5, 28)),", - " ]),", - " (\"image\", [", - " Some((", - " 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,", - " )),", - " ]),", - " ],", - ")", + r#"("#, + r#" scope: Stream,"#, + r#" tags: ["#, + r#" ("title", ["#, + r#" "a title","#, + r#" "another title","#, + r#" ]),"#, + r#" ("duration", ["#, + r#" 120000000000,"#, + r#" ]),"#, + r#" ("bitrate", ["#, + r#" 96000,"#, + r#" ]),"#, + r#" ("replaygain-track-gain", ["#, + r#" 1,"#, + r#" ]),"#, + r#" ("date", ["#, + r#" YMD(2018, 5, 28),"#, + r#" ]),"#, + r#" ("datetime", ["#, + r#" Some(YMD(2018, 5, 28)),"#, + r#" ]),"#, + r#" ("image", ["#, + r#" Some(("#, + r#" buffer: Some(("#, + r#" pts: None,"#, + r#" dts: None,"#, + r#" duration: None,"#, + r#" offset: 0,"#, + r#" offset_end: 0,"#, + r#" flags: ("#, + r#" bits: 0,"#, + r#" ),"#, + r#" buffer: "AQIDBA==","#, + r#" )),"#, + r#" buffer_list: None,"#, + r#" caps: None,"#, + r#" segment: Some(("#, + r#" flags: ("#, + r#" bits: 0,"#, + r#" ),"#, + r#" rate: 1,"#, + r#" applied_rate: 1,"#, + r#" format: Time,"#, + r#" base: 0,"#, + r#" offset: 0,"#, + r#" start: 0,"#, + r#" stop: -1,"#, + r#" time: 0,"#, + r#" position: 0,"#, + r#" duration: -1,"#, + r#" )),"#, + r#" info: None,"#, + r#" )),"#, + r#" ]),"#, + r#" ],"#, + r#")"#, ) .to_owned()), res, @@ -425,6 +445,9 @@ mod tests { ("duration", [120000000000]), ("bitrate", [96000]), ("replaygain-track-gain", [1]), + ("date", [ + YMD(2018, 5, 28), + ]), ("datetime", [ Some(YMD(2018, 5, 28)), ]), @@ -464,6 +487,12 @@ mod tests { ); assert_eq!(tags.get_index::(0).unwrap().get_some(), 96_000); assert_eq!(tags.get_index::(0).unwrap().get_some(), 1f64); + assert_eq!( + tags.get_index::(0).unwrap().get().unwrap(), + glib::Date::new_dmy(28, glib::DateMonth::May, 2018) + ); + // FIXME: compare `DateTime` instances + // See https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/217 let datetime = tags.get_index::(0).unwrap().get().unwrap(); assert_eq!(datetime.get_year(), 2018); assert_eq!(datetime.get_month(), 5); @@ -483,6 +512,7 @@ mod tests { ["duration", [120000000000]], ["bitrate", [96000]], ["replaygain-track-gain", [1.0]], + ["date",[{"YMD":[2018,5,28]}]], ["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}]] ] @@ -498,6 +528,12 @@ mod tests { ); assert_eq!(tags.get_index::(0).unwrap().get_some(), 96_000); assert_eq!(tags.get_index::(0).unwrap().get_some(), 1f64); + assert_eq!( + tags.get_index::(0).unwrap().get().unwrap(), + glib::Date::new_dmy(28, glib::DateMonth::May, 2018) + ); + // FIXME: compare `DateTime` instances + // See https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/217 let datetime = tags.get_index::(0).unwrap().get().unwrap(); assert_eq!(datetime.get_year(), 2018); assert_eq!(datetime.get_month(), 5); @@ -524,6 +560,10 @@ mod tests { tags.add::(&(::SECOND * 120).into(), TagMergeMode::Append); // u64 tags.add::(&96_000, TagMergeMode::Append); // u32 tags.add::(&1f64, TagMergeMode::Append); // f64 + tags.add::( + &glib::Date::new_dmy(28, glib::DateMonth::May, 2018), + TagMergeMode::Append, + ); tags.add::(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append); let sample = { @@ -562,6 +602,10 @@ mod tests { tags_de.get_index::(0).unwrap().get_some(), tags.get_index::(0).unwrap().get_some(), ); + assert_eq!( + tags_de.get_index::(0).unwrap().get(), + tags.get_index::(0).unwrap().get(), + ); let datetime = tags.get_index::(0).unwrap().get().unwrap(); assert_eq!(datetime.get_year(), 2018); assert_eq!(datetime.get_month(), 5); diff --git a/gstreamer/src/value_serde.rs b/gstreamer/src/value_serde.rs index 7ec114ce9..d5783982e 100644 --- a/gstreamer/src/value_serde.rs +++ b/gstreamer/src/value_serde.rs @@ -7,7 +7,7 @@ // except according to those terms. use glib; -use glib::{StaticType, ToValue}; +use glib::{Date, StaticType, ToValue}; use num_rational::Rational32; @@ -22,6 +22,7 @@ use Buffer; use DateTime; use Sample; +use date_time_serde; use value::*; fn get_other_type_id() -> usize { @@ -31,11 +32,10 @@ fn get_other_type_id() -> usize { } } -// FIXME: implement serde for type `Date` - 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_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 = @@ -94,6 +94,12 @@ macro_rules! ser_value ( ser_some_value!($value, Array, $ser_closure) } else if *BITMASK_OTHER_TYPE_ID == type_id { ser_some_value!($value, Bitmask, $ser_closure) + } else if *DATE_OTHER_TYPE_ID == type_id { + ser_opt_value!($value, Date, |type_, value: Option| { + // Need to wrap the `glib::Date` in new type `date_time_serde::Date` first + // See comment in `date_time_serde.rs` + $ser_closure(type_, value.map(date_time_serde::Date::from)) + }) } else if *DATE_TIME_OTHER_TYPE_ID == type_id { ser_opt_value!($value, DateTime, $ser_closure) } else if *FRACTION_OTHER_TYPE_ID == type_id { @@ -221,6 +227,17 @@ macro_rules! de_send_value( "String" => de_opt_send_value!($type_name, $seq, String), "Array" => de_some_send_value!($type_name, $seq, Array), "Bitmask" => de_some_send_value!($type_name, $seq, Bitmask), + "Date" => { + // Need to deserialize as `date_time_serde::Date` new type + // See comment in `date_time_serde.rs` + de_send_value!( + "Value", + $type_name, + $seq, + Option, + Date + ) + } "DateTime" => de_opt_send_value!($type_name, $seq, DateTime), "Fraction" => de_some_send_value!($type_name, $seq, Fraction), "FractionRange" => de_some_send_value!($type_name, $seq, FractionRange), @@ -287,11 +304,14 @@ mod tests { use Array; use Bitmask; + use DateTime; use Fraction; use FractionRange; use IntRange; use List; + use glib::{Date, DateMonth}; + #[test] fn test_serialize_simple() { ::init().unwrap(); @@ -315,7 +335,7 @@ mod tests { assert_eq!(Ok("( 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); + assert_eq!(r#"{"min":[1,3],"max":[1,2]}"#.to_owned(), res); // IntRange let int_range = IntRange::::new_with_step(0, 42, 21); @@ -323,7 +343,7 @@ mod tests { assert_eq!(Ok("( 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); + assert_eq!(r#"{"min":0,"max":42,"step":21}"#.to_owned(), res); // Bitmask let bitmask = Bitmask::new(1024 + 128 + 32); @@ -361,22 +381,33 @@ mod tests { let value_str_none = str_none.to_value(); let send_value_str_none = value_str_none.try_into_send_value::().unwrap(); + let value_date = Date::new_dmy(19, DateMonth::August, 2019).to_value(); + let send_value_date = value_date.try_into_send_value::().unwrap(); + + let date_none: Option = None; + let value_date_none = date_none.to_value(); + let send_value_date_none = value_date_none.try_into_send_value::().unwrap(); + let array = Array::new(&[ &send_value_13, &send_value_12, &send_value_str, &send_value_str_none, + &send_value_date, + &send_value_date_none, ]); let res = ron::ser::to_string_pretty(&array, pretty_config.clone()); assert_eq!( Ok(concat!( - "[", - " (\"Fraction\", (1, 3)),", - " (\"Fraction\", (1, 2)),", - " (\"String\", Some(\"test str\")),", - " (\"String\", None),", - "]" + r#"["#, + r#" ("Fraction", (1, 3)),"#, + r#" ("Fraction", (1, 2)),"#, + r#" ("String", Some("test str")),"#, + r#" ("String", None),"#, + r#" ("Date", Some(YMD(2019, 8, 19))),"#, + r#" ("Date", None),"#, + r#"]"# ) .to_owned()), res, @@ -384,7 +415,7 @@ mod tests { let res = serde_json::to_string(&array).unwrap(); assert_eq!( - "[[\"Fraction\",[1,3]],[\"Fraction\",[1,2]],[\"String\",\"test str\"],[\"String\",null]]" + r#"[["Fraction",[1,3]],["Fraction",[1,2]],["String","test str"],["String",null],["Date",{"YMD":[2019,8,19]}],["Date",null]]"# .to_owned(), res ); @@ -400,16 +431,33 @@ mod tests { let value_str_none = str_none.to_value(); let send_value_str_none = value_str_none.try_into_send_value::().unwrap(); - let list = List::new(&[&send_value_12, &send_value_str, &send_value_str_none]); + let value_date_time = DateTime::new(2f32, 2019, 8, 19, 13, 34, 42f64).to_value(); + let send_value_date_time = value_date_time.try_into_send_value::().unwrap(); + + let date_time_none: Option = None; + let value_date_time_none = date_time_none.to_value(); + let send_value_date_time_none = value_date_time_none + .try_into_send_value::() + .unwrap(); + + let list = List::new(&[ + &send_value_12, + &send_value_str, + &send_value_str_none, + &send_value_date_time, + &send_value_date_time_none, + ]); let res = ron::ser::to_string_pretty(&list, pretty_config.clone()); assert_eq!( Ok(concat!( - "[", - " (\"Fraction\", (1, 2)),", - " (\"String\", Some(\"test str\")),", - " (\"String\", None),", - "]" + r#"["#, + r#" ("Fraction", (1, 2)),"#, + r#" ("String", Some("test str")),"#, + r#" ("String", None),"#, + r#" ("DateTime", Some(YMDhmsTz(2019, 8, 19, 13, 34, 42, 2))),"#, + r#" ("DateTime", None),"#, + r#"]"# ) .to_owned()), res, @@ -437,7 +485,7 @@ mod tests { 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_json = r#"{"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); @@ -449,7 +497,7 @@ mod tests { 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_json = r#"{"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); @@ -517,10 +565,12 @@ mod tests { ("Fraction", (1, 2)), ("String", Some("test str")), ("String", None), + ("Date", Some(YMD(2019, 8, 19))), + ("Date", None), ]"#; let array: Array = ron::de::from_str(array_ron).unwrap(); let slice = array.as_slice(); - assert_eq!(4, slice.len()); + assert_eq!(6, slice.len()); let fraction = slice[0].get::().expect("slice[0]").unwrap(); assert_eq!(fraction.0.numer(), &1); @@ -537,11 +587,18 @@ mod tests { assert!(slice[3].get::().expect("slice[3]").is_none()); + assert_eq!( + Date::new_dmy(19, DateMonth::August, 2019), + slice[4].get::().expect("slice[4]").unwrap() + ); + + assert!(slice[5].get::().expect("slice[5]").is_none()); + let array_json = - r#"[["Fraction",[1,3]],["Fraction",[1,2]],["String","test str"],["String",null]]"#; + r#"[["Fraction",[1,3]],["Fraction",[1,2]],["String","test str"],["String",null],["Date",{"YMD":[2019,8,19]}],["Date",null]]"#; let array: Array = serde_json::from_str(array_json).unwrap(); let slice = array.as_slice(); - assert_eq!(4, slice.len()); + assert_eq!(6, slice.len()); let fraction = slice[0].get::().expect("slice[0]").unwrap(); assert_eq!(fraction.0.numer(), &1); @@ -558,15 +615,24 @@ mod tests { assert!(slice[3].get::().expect("slice[3]").is_none()); + assert_eq!( + Date::new_dmy(19, DateMonth::August, 2019), + slice[4].get::().expect("slice[4]").unwrap() + ); + + assert!(slice[5].get::().expect("slice[5]").is_none()); + // List let list_ron = r#"[ ("Fraction", (1, 2)), ("String", Some("test str")), ("String", None), + ("DateTime", Some(YMDhmsTz(2019, 8, 19, 13, 34, 42, 2))), + ("DateTime", None), ]"#; let list: List = ron::de::from_str(list_ron).unwrap(); let slice = list.as_slice(); - assert_eq!(3, slice.len()); + assert_eq!(5, slice.len()); let fraction = slice[0].get::().expect("slice[0]").unwrap(); assert_eq!(fraction.0.numer(), &1); @@ -578,6 +644,12 @@ mod tests { ); assert!(slice[2].get::().expect("slice[2]").is_none()); + + // FIXME: compare `DateTime` instances + // See https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/217 + assert!(slice[3].get::().expect("slice[3]").is_some()); + + assert!(slice[4].get::().expect("slice[4]").is_none()); } #[test] @@ -596,11 +668,18 @@ mod tests { let str_none: Option<&str> = None; let value_str_none = str_none.to_value(); let send_value_str_none = value_str_none.try_into_send_value::().unwrap(); + let value_date = Date::new_dmy(19, DateMonth::August, 2019).to_value(); + let send_value_date = value_date.try_into_send_value::().unwrap(); + let date_none: Option = None; + let value_date_none = date_none.to_value(); + let send_value_date_none = value_date_none.try_into_send_value::().unwrap(); let array = Array::new(&[ &send_value_13, &send_value_12, &send_value_str, &send_value_str_none, + &send_value_date, + &send_value_date_none, ]); let array_ser = ron::ser::to_string(&array).unwrap(); @@ -626,6 +705,13 @@ mod tests { assert!(slice[3].get::().expect("slice[3]").is_none()); + assert_eq!( + slice_de[4].get::().expect("slice_de[4]").unwrap(), + slice[4].get::().expect("slice[4]").unwrap() + ); + + assert!(slice[5].get::().expect("slice[5]").is_none()); + // List let value_12 = Fraction::new(1, 2).to_value(); let send_value_12 = value_12.try_into_send_value::().unwrap(); @@ -634,7 +720,20 @@ mod tests { let str_none: Option<&str> = None; let value_str_none = str_none.to_value(); let send_value_str_none = value_str_none.try_into_send_value::().unwrap(); - let list = List::new(&[&send_value_12, &send_value_str, &send_value_str_none]); + let value_date_time = DateTime::new(2f32, 2019, 8, 19, 13, 34, 42f64).to_value(); + let send_value_date_time = value_date_time.try_into_send_value::().unwrap(); + let date_time_none: Option = None; + let value_date_time_none = date_time_none.to_value(); + let send_value_date_time_none = value_date_time_none + .try_into_send_value::() + .unwrap(); + let list = List::new(&[ + &send_value_12, + &send_value_str, + &send_value_str_none, + &send_value_date_time, + &send_value_date_time_none, + ]); let list_ser = ron::ser::to_string(&list).unwrap(); let list_de: List = ron::de::from_str(list_ser.as_str()).unwrap(); @@ -653,5 +752,14 @@ mod tests { ); assert!(slice[2].get::().expect("slice[2]").is_none()); + + // FIXME: compare `DateTime` instances + // See https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/217 + assert!(slice_de[3] + .get::() + .expect("slice_de[3]") + .is_some()); + + assert!(slice[4].get::().expect("slice[4]").is_none()); } }