forked from mirrors/gstreamer-rs
Caps: serde as an enum
`Caps` can be `any`, `empty` or matching a list of `Structures`.
This commit is contained in:
parent
9f2f684188
commit
64ea419839
2 changed files with 170 additions and 18 deletions
|
@ -7,7 +7,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use serde::de;
|
use serde::de;
|
||||||
use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
|
use serde::de::{Deserialize, Deserializer, EnumAccess, SeqAccess, VariantAccess, Visitor};
|
||||||
use serde::ser::{Serialize, SerializeSeq, SerializeTuple, Serializer};
|
use serde::ser::{Serialize, SerializeSeq, SerializeTuple, Serializer};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -17,6 +17,25 @@ use CapsRef;
|
||||||
use Structure;
|
use Structure;
|
||||||
use StructureRef;
|
use StructureRef;
|
||||||
|
|
||||||
|
enum CapsVariantKinds {
|
||||||
|
Any,
|
||||||
|
Empty,
|
||||||
|
Some,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CAPS_VARIANT_ANY_ID: u32 = 0;
|
||||||
|
const CAPS_VARIANT_ANY_STR: &str = "Any";
|
||||||
|
const CAPS_VARIANT_EMPTY_ID: u32 = 1;
|
||||||
|
const CAPS_VARIANT_EMPTY_STR: &str = "Empty";
|
||||||
|
const CAPS_VARIANT_SOME_ID: u32 = 2;
|
||||||
|
const CAPS_VARIANT_SOME_STR: &str = "Some";
|
||||||
|
|
||||||
|
const CAPS_VARIANT_NAMES: &[&str] = &[
|
||||||
|
&CAPS_VARIANT_ANY_STR,
|
||||||
|
&CAPS_VARIANT_EMPTY_STR,
|
||||||
|
&CAPS_VARIANT_SOME_STR,
|
||||||
|
];
|
||||||
|
|
||||||
// `CapsFeature` is not available in `gstreamer-rs` yet
|
// `CapsFeature` is not available in `gstreamer-rs` yet
|
||||||
struct CapsItemSe<'a>(&'a StructureRef);
|
struct CapsItemSe<'a>(&'a StructureRef);
|
||||||
impl<'a> Serialize for CapsItemSe<'a> {
|
impl<'a> Serialize for CapsItemSe<'a> {
|
||||||
|
@ -30,9 +49,10 @@ impl<'a> Serialize for CapsItemSe<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for CapsRef {
|
struct CapsForIterSe<'a>(&'a CapsRef);
|
||||||
|
impl<'a> Serialize for CapsForIterSe<'a> {
|
||||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
let iter = self.iter();
|
let iter = self.0.iter();
|
||||||
let size = iter.size_hint().0;
|
let size = iter.size_hint().0;
|
||||||
if size > 0 {
|
if size > 0 {
|
||||||
let mut seq = serializer.serialize_seq(Some(size))?;
|
let mut seq = serializer.serialize_seq(Some(size))?;
|
||||||
|
@ -47,6 +67,31 @@ impl Serialize for CapsRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for CapsRef {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
if self.is_any() {
|
||||||
|
serializer.serialize_unit_variant(
|
||||||
|
stringify!(Caps),
|
||||||
|
CAPS_VARIANT_ANY_ID,
|
||||||
|
CAPS_VARIANT_ANY_STR,
|
||||||
|
)
|
||||||
|
} else if self.is_empty() {
|
||||||
|
serializer.serialize_unit_variant(
|
||||||
|
stringify!(Caps),
|
||||||
|
CAPS_VARIANT_EMPTY_ID,
|
||||||
|
CAPS_VARIANT_EMPTY_STR,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
serializer.serialize_newtype_variant(
|
||||||
|
stringify!(Caps),
|
||||||
|
CAPS_VARIANT_SOME_ID,
|
||||||
|
CAPS_VARIANT_SOME_STR,
|
||||||
|
&CapsForIterSe(&self),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Serialize for Caps {
|
impl Serialize for Caps {
|
||||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
self.as_ref().serialize(serializer)
|
self.as_ref().serialize(serializer)
|
||||||
|
@ -96,9 +141,11 @@ impl<'de> Deserialize<'de> for CapsItemDe {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CapsVisitor;
|
struct CapsSome(Caps);
|
||||||
impl<'de> Visitor<'de> for CapsVisitor {
|
|
||||||
type Value = Caps;
|
struct CapsSomeVisitor;
|
||||||
|
impl<'de> Visitor<'de> for CapsSomeVisitor {
|
||||||
|
type Value = CapsSome;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("a sequence of `(Structure, Option<CapsFeature>)`")
|
formatter.write_str("a sequence of `(Structure, Option<CapsFeature>)`")
|
||||||
|
@ -112,13 +159,76 @@ impl<'de> Visitor<'de> for CapsVisitor {
|
||||||
caps.append_structure(caps_item.into());
|
caps.append_structure(caps_item.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(caps)
|
Ok(CapsSome(caps))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for CapsSome {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<CapsSome, D::Error> {
|
||||||
|
deserializer.deserialize_seq(CapsSomeVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CapsVariantKindsVisitor;
|
||||||
|
impl<'de> Visitor<'de> for CapsVariantKindsVisitor {
|
||||||
|
type Value = CapsVariantKinds;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a Caps variant kind (`Any`, `None` or `Some`)")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u32<E: de::Error>(self, value: u32) -> Result<Self::Value, E> {
|
||||||
|
match value {
|
||||||
|
CAPS_VARIANT_ANY_ID => Ok(CapsVariantKinds::Any),
|
||||||
|
CAPS_VARIANT_EMPTY_ID => Ok(CapsVariantKinds::Empty),
|
||||||
|
CAPS_VARIANT_SOME_ID => Ok(CapsVariantKinds::Some),
|
||||||
|
_ => Err(de::Error::invalid_value(
|
||||||
|
de::Unexpected::Unsigned(value as u64),
|
||||||
|
&self,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
|
||||||
|
match value {
|
||||||
|
CAPS_VARIANT_ANY_STR => Ok(CapsVariantKinds::Any),
|
||||||
|
CAPS_VARIANT_EMPTY_STR => Ok(CapsVariantKinds::Empty),
|
||||||
|
CAPS_VARIANT_SOME_STR => Ok(CapsVariantKinds::Some),
|
||||||
|
_ => Err(de::Error::unknown_variant(value, CAPS_VARIANT_NAMES)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for CapsVariantKinds {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
|
deserializer.deserialize_identifier(CapsVariantKindsVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CapsVisitor;
|
||||||
|
impl<'de> Visitor<'de> for CapsVisitor {
|
||||||
|
type Value = Caps;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a Caps enum (`Any`, `None` or `Some()`)")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> {
|
||||||
|
let res = match data.variant()? {
|
||||||
|
(CapsVariantKinds::Any, _v) => Caps::new_any(),
|
||||||
|
(CapsVariantKinds::Empty, _v) => Caps::new_empty(),
|
||||||
|
(CapsVariantKinds::Some, v) => v
|
||||||
|
.newtype_variant::<CapsSome>()
|
||||||
|
.map(|caps_some| caps_some.0)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Caps {
|
impl<'de> Deserialize<'de> for Caps {
|
||||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
deserializer.deserialize_seq(CapsVisitor)
|
deserializer.deserialize_enum(stringify!(Caps), CAPS_VARIANT_NAMES, CapsVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,10 +255,10 @@ mod tests {
|
||||||
let mut pretty_config = ron::ser::PrettyConfig::default();
|
let mut pretty_config = ron::ser::PrettyConfig::default();
|
||||||
pretty_config.new_line = "".to_string();
|
pretty_config.new_line = "".to_string();
|
||||||
|
|
||||||
let res = ron::ser::to_string_pretty(&caps, pretty_config);
|
let res = ron::ser::to_string_pretty(&caps, pretty_config.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok(concat!(
|
Ok(concat!(
|
||||||
"[",
|
"Some([",
|
||||||
" ((\"foo/bar\", [",
|
" ((\"foo/bar\", [",
|
||||||
" (\"int\", \"i32\", 12),",
|
" (\"int\", \"i32\", 12),",
|
||||||
" (\"bool\", \"bool\", true),",
|
" (\"bool\", \"bool\", true),",
|
||||||
|
@ -159,10 +269,18 @@ mod tests {
|
||||||
" (\"i32\", 2),",
|
" (\"i32\", 2),",
|
||||||
" ]),",
|
" ]),",
|
||||||
" ]), None),",
|
" ]), None),",
|
||||||
"]"
|
"])"
|
||||||
).to_owned()),
|
).to_owned()),
|
||||||
res,
|
res,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let caps_any = Caps::new_any();
|
||||||
|
let res = ron::ser::to_string_pretty(&caps_any, pretty_config.clone());
|
||||||
|
assert_eq!(Ok("Any".to_owned()), res);
|
||||||
|
|
||||||
|
let caps_empty = Caps::new_empty();
|
||||||
|
let res = ron::ser::to_string_pretty(&caps_empty, pretty_config.clone());
|
||||||
|
assert_eq!(Ok("Empty".to_owned()), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -171,8 +289,16 @@ mod tests {
|
||||||
|
|
||||||
::init().unwrap();
|
::init().unwrap();
|
||||||
|
|
||||||
|
let caps_ron = "Any";
|
||||||
|
let caps: Caps = ron::de::from_str(caps_ron).unwrap();
|
||||||
|
assert!(caps.is_any());
|
||||||
|
|
||||||
|
let caps_ron = "Empty";
|
||||||
|
let caps: Caps = ron::de::from_str(caps_ron).unwrap();
|
||||||
|
assert!(caps.is_empty());
|
||||||
|
|
||||||
let caps_ron = r#"
|
let caps_ron = r#"
|
||||||
[
|
Some([
|
||||||
(
|
(
|
||||||
("foo/bar", [
|
("foo/bar", [
|
||||||
("int", "i32", 12),
|
("int", "i32", 12),
|
||||||
|
@ -186,7 +312,7 @@ mod tests {
|
||||||
]),
|
]),
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
]"#;
|
])"#;
|
||||||
let caps: Caps = ron::de::from_str(caps_ron).unwrap();
|
let caps: Caps = ron::de::from_str(caps_ron).unwrap();
|
||||||
let s = caps.get_structure(0).unwrap();
|
let s = caps.get_structure(0).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -203,4 +329,30 @@ mod tests {
|
||||||
).as_ref()
|
).as_ref()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serde_roundtrip() {
|
||||||
|
::init().unwrap();
|
||||||
|
|
||||||
|
let caps = Caps::new_any();
|
||||||
|
let caps_ser = ron::ser::to_string(&caps).unwrap();
|
||||||
|
let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap();
|
||||||
|
assert!(caps_de.is_any());
|
||||||
|
|
||||||
|
let caps = Caps::new_empty();
|
||||||
|
let caps_ser = ron::ser::to_string(&caps).unwrap();
|
||||||
|
let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap();
|
||||||
|
assert!(caps_de.is_empty());
|
||||||
|
|
||||||
|
let caps = Caps::builder("foo/bar")
|
||||||
|
.field("int", &12)
|
||||||
|
.field("bool", &true)
|
||||||
|
.field("string", &"bla")
|
||||||
|
.field("fraction", &Fraction::new(1, 2))
|
||||||
|
.field("array", &Array::new(&[&1, &2]))
|
||||||
|
.build();
|
||||||
|
let caps_ser = ron::ser::to_string(&caps).unwrap();
|
||||||
|
let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap();
|
||||||
|
assert!(caps_de.is_strictly_equal(&caps));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ impl From<SampleDe> for Sample {
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Sample {
|
impl<'de> Deserialize<'de> for Sample {
|
||||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
SampleDe::deserialize(deserializer).and_then(|sample_de| Ok(sample_de.into()))
|
SampleDe::deserialize(deserializer).map(|sample_de| sample_de.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,12 +149,12 @@ mod tests {
|
||||||
" buffer: \"AQIDBA==\",",
|
" buffer: \"AQIDBA==\",",
|
||||||
" )),",
|
" )),",
|
||||||
" buffer_list: None,",
|
" buffer_list: None,",
|
||||||
" caps: Some([",
|
" caps: Some(Some([",
|
||||||
" ((\"sample/caps\", [",
|
" ((\"sample/caps\", [",
|
||||||
" (\"int\", \"i32\", 12),",
|
" (\"int\", \"i32\", 12),",
|
||||||
" (\"bool\", \"bool\", true),",
|
" (\"bool\", \"bool\", true),",
|
||||||
" ]), None),",
|
" ]), None),",
|
||||||
" ]),",
|
" ])),",
|
||||||
" segment: Some((",
|
" segment: Some((",
|
||||||
" flags: (",
|
" flags: (",
|
||||||
" bits: 9,",
|
" bits: 9,",
|
||||||
|
@ -249,12 +249,12 @@ mod tests {
|
||||||
buffer: "AQIDBA==",
|
buffer: "AQIDBA==",
|
||||||
)),
|
)),
|
||||||
buffer_list: None,
|
buffer_list: None,
|
||||||
caps: Some([
|
caps: Some(Some([
|
||||||
(("sample/caps", [
|
(("sample/caps", [
|
||||||
("int", "i32", 12),
|
("int", "i32", 12),
|
||||||
("bool", "bool", true),
|
("bool", "bool", true),
|
||||||
]), None),
|
]), None),
|
||||||
]),
|
])),
|
||||||
segment: Some((
|
segment: Some((
|
||||||
flags: (
|
flags: (
|
||||||
bits: 0,
|
bits: 0,
|
||||||
|
|
Loading…
Reference in a new issue