mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-11-25 19:11:06 +00:00
TagList: handle scope in serde
These changes break compatibility for the serde representations of `TagList` and `Toc`. Previous representation for the `TagList` was a sequence. We now have to rely on a struct representation in order to add `scope`.
This commit is contained in:
parent
bec3d84627
commit
9a01bd6202
2 changed files with 206 additions and 131 deletions
|
@ -14,7 +14,7 @@ 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 serde::ser::{Serialize, SerializeSeq, SerializeStruct, SerializeTuple, Serializer};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
|
@ -25,6 +25,7 @@ use value_serde::{DATE_TIME_OTHER_TYPE_ID, SAMPLE_OTHER_TYPE_ID};
|
|||
use DateTime;
|
||||
use Sample;
|
||||
use TagMergeMode;
|
||||
use TagScope;
|
||||
|
||||
macro_rules! ser_tag (
|
||||
($value:ident, $seq:ident, $t:ty) => (
|
||||
|
@ -92,12 +93,13 @@ impl<'a> Serialize for TagsSer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for TagListRef {
|
||||
struct TagListSer<'a>(&'a TagListRef);
|
||||
impl<'a> Serialize for TagListSer<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let tag_count = self.n_tags();
|
||||
let tag_count = self.0.n_tags();
|
||||
if tag_count > 0 {
|
||||
let mut seq = serializer.serialize_seq(Some(tag_count as usize))?;
|
||||
let tag_list_iter = self.iter_generic();
|
||||
let tag_list_iter = self.0.iter_generic();
|
||||
for (tag_name, tag_iter) in tag_list_iter {
|
||||
seq.serialize_element(&TagsSer::new(tag_name, tag_iter))?;
|
||||
}
|
||||
|
@ -111,6 +113,15 @@ impl Serialize for TagListRef {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for TagListRef {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut tag_list = serializer.serialize_struct("TagList", 3)?;
|
||||
tag_list.serialize_field("scope", &self.get_scope())?;
|
||||
tag_list.serialize_field("tags", &TagListSer(self))?;
|
||||
tag_list.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TagList {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
self.as_ref().serialize(serializer)
|
||||
|
@ -218,9 +229,11 @@ impl<'de, 'a> DeserializeSeed<'de> for TagValuesTuple<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TagListVisitor;
|
||||
impl<'de> Visitor<'de> for TagListVisitor {
|
||||
type Value = TagList;
|
||||
struct TagsDe(TagList);
|
||||
|
||||
struct TagsVisitor;
|
||||
impl<'de> Visitor<'de> for TagsVisitor {
|
||||
type Value = TagsDe;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a sequence of `Tag`s")
|
||||
|
@ -234,13 +247,34 @@ impl<'de> Visitor<'de> for TagListVisitor {
|
|||
// tags are added in the dedicated deserializers
|
||||
}
|
||||
}
|
||||
Ok(tag_list)
|
||||
Ok(TagsDe(tag_list))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TagsDe {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_seq(TagsVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct TagListDe {
|
||||
scope: TagScope,
|
||||
tags: TagsDe,
|
||||
}
|
||||
|
||||
impl From<TagListDe> for TagList {
|
||||
fn from(tag_list_de: TagListDe) -> Self {
|
||||
let mut tag_list = tag_list_de.tags.0;
|
||||
tag_list.get_mut().unwrap().set_scope(tag_list_de.scope);
|
||||
|
||||
tag_list
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TagList {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_seq(TagListVisitor)
|
||||
TagListDe::deserialize(deserializer).map(|tag_list_de| tag_list_de.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,6 +287,7 @@ mod tests {
|
|||
use GenericFormattedValue;
|
||||
use Sample;
|
||||
use TagMergeMode;
|
||||
use TagScope;
|
||||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
|
@ -287,57 +322,60 @@ mod tests {
|
|||
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,",
|
||||
" ),",
|
||||
" ]),",
|
||||
"]",
|
||||
"(",
|
||||
" scope: Stream,",
|
||||
" tags: [",
|
||||
" (\"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,
|
||||
|
@ -351,39 +389,44 @@ mod tests {
|
|||
::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,
|
||||
),
|
||||
])
|
||||
]
|
||||
(
|
||||
scope: Global,
|
||||
tags: [
|
||||
("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_scope(), TagScope::Global);
|
||||
|
||||
assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title"));
|
||||
assert_eq!(
|
||||
tags.get_index::<Title>(1).unwrap().get(),
|
||||
|
@ -407,16 +450,21 @@ mod tests {
|
|||
}
|
||||
|
||||
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}]]
|
||||
]
|
||||
{
|
||||
"scope":"Global",
|
||||
"tags":[
|
||||
["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_scope(), TagScope::Global);
|
||||
|
||||
assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title"));
|
||||
assert_eq!(
|
||||
tags.get_index::<Title>(1).unwrap().get(),
|
||||
|
@ -444,6 +492,7 @@ mod tests {
|
|||
assert_eq!(tags.to_string(), "taglist;");
|
||||
{
|
||||
let tags = tags.get_mut().unwrap();
|
||||
tags.set_scope(TagScope::Global);
|
||||
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
|
||||
|
@ -465,6 +514,8 @@ mod tests {
|
|||
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_scope(), TagScope::Global);
|
||||
|
||||
assert_eq!(
|
||||
tags_de.get_index::<Title>(0).unwrap().get(),
|
||||
tags.get_index::<Title>(0).unwrap().get(),
|
||||
|
|
|
@ -203,11 +203,14 @@ mod tests {
|
|||
Ok(concat!(
|
||||
"(",
|
||||
" scope: Global,",
|
||||
" tags: Some([",
|
||||
" (\"title\", [",
|
||||
" \"toc\",",
|
||||
" ]),",
|
||||
" ]),",
|
||||
" tags: Some((",
|
||||
" scope: Stream,",
|
||||
" tags: [",
|
||||
" (\"title\", [",
|
||||
" \"toc\",",
|
||||
" ]),",
|
||||
" ],",
|
||||
" )),",
|
||||
" entries: [",
|
||||
" (",
|
||||
" entry_type: Edition,",
|
||||
|
@ -227,11 +230,14 @@ mod tests {
|
|||
" entry_type: Chapter,",
|
||||
" uid: \"chapter1.1\",",
|
||||
" start_stop: Some((0, 4)),",
|
||||
" tags: Some([",
|
||||
" (\"title\", [",
|
||||
" \"chapter 1.1\",",
|
||||
" ]),",
|
||||
" ]),",
|
||||
" tags: Some((",
|
||||
" scope: Stream,",
|
||||
" tags: [",
|
||||
" (\"title\", [",
|
||||
" \"chapter 1.1\",",
|
||||
" ]),",
|
||||
" ],",
|
||||
" )),",
|
||||
" loop: Some((None, 0)),",
|
||||
" sub_entries: [",
|
||||
" ],",
|
||||
|
@ -240,11 +246,14 @@ mod tests {
|
|||
" entry_type: Chapter,",
|
||||
" uid: \"chapter1.2\",",
|
||||
" start_stop: Some((4, 10)),",
|
||||
" tags: Some([",
|
||||
" (\"title\", [",
|
||||
" \"chapter 1.2\",",
|
||||
" ]),",
|
||||
" ]),",
|
||||
" tags: Some((",
|
||||
" scope: Stream,",
|
||||
" tags: [",
|
||||
" (\"title\", [",
|
||||
" \"chapter 1.2\",",
|
||||
" ]),",
|
||||
" ],",
|
||||
" )),",
|
||||
" loop: Some((None, 0)),",
|
||||
" sub_entries: [",
|
||||
" ],",
|
||||
|
@ -255,11 +264,14 @@ mod tests {
|
|||
" entry_type: Chapter,",
|
||||
" uid: \"chapter2\",",
|
||||
" start_stop: Some((10, 15)),",
|
||||
" tags: Some([",
|
||||
" (\"title\", [",
|
||||
" \"chapter 2\",",
|
||||
" ]),",
|
||||
" ]),",
|
||||
" tags: Some((",
|
||||
" scope: Stream,",
|
||||
" tags: [",
|
||||
" (\"title\", [",
|
||||
" \"chapter 2\",",
|
||||
" ]),",
|
||||
" ],",
|
||||
" )),",
|
||||
" loop: Some((None, 0)),",
|
||||
" sub_entries: [",
|
||||
" ],",
|
||||
|
@ -283,9 +295,12 @@ mod tests {
|
|||
let toc_ron = r#"
|
||||
(
|
||||
scope: Global,
|
||||
tags: Some([
|
||||
("title", ["toc"]),
|
||||
]),
|
||||
tags: Some((
|
||||
scope: Stream,
|
||||
tags: [
|
||||
("title", ["toc"]),
|
||||
],
|
||||
)),
|
||||
entries: [
|
||||
(
|
||||
entry_type: Edition,
|
||||
|
@ -305,9 +320,12 @@ mod tests {
|
|||
entry_type: Chapter,
|
||||
uid: "chapter1.1",
|
||||
start_stop: Some((0, 4)),
|
||||
tags: Some([
|
||||
("title", ["chapter 1.1"]),
|
||||
]),
|
||||
tags: Some((
|
||||
scope: Stream,
|
||||
tags: [
|
||||
("title", ["chapter 1.1"]),
|
||||
],
|
||||
)),
|
||||
loop: Some((None, 0)),
|
||||
sub_entries: [
|
||||
],
|
||||
|
@ -316,9 +334,12 @@ mod tests {
|
|||
entry_type: Chapter,
|
||||
uid: "chapter1.2",
|
||||
start_stop: Some((4, 10)),
|
||||
tags: Some([
|
||||
("title", ["chapter 1.2"]),
|
||||
]),
|
||||
tags: Some((
|
||||
scope: Stream,
|
||||
tags: [
|
||||
("title", ["chapter 1.2"]),
|
||||
],
|
||||
)),
|
||||
loop: Some((None, 0)),
|
||||
sub_entries: [
|
||||
],
|
||||
|
@ -329,9 +350,12 @@ mod tests {
|
|||
entry_type: Chapter,
|
||||
uid: "chapter2",
|
||||
start_stop: Some((10, 15)),
|
||||
tags: Some([
|
||||
("title", ["chapter 2"]),
|
||||
]),
|
||||
tags: Some((
|
||||
scope: Stream,
|
||||
tags: [
|
||||
("title", ["chapter 2"]),
|
||||
],
|
||||
)),
|
||||
loop: Some((None, 0)),
|
||||
sub_entries: [
|
||||
],
|
||||
|
|
Loading…
Reference in a new issue