2018-07-16 19:46:10 +00:00
|
|
|
// Copyright (C) 2018 François Laignel <fengalin@free.fr>
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
use glib;
|
2018-07-22 14:55:24 +00:00
|
|
|
use glib::translate::{from_glib, ToGlibPtr};
|
2019-08-19 13:32:40 +00:00
|
|
|
use glib::{Date, SendValue, ToValue};
|
2019-03-19 07:58:20 +00:00
|
|
|
use gst_sys;
|
2018-07-16 19:46:10 +00:00
|
|
|
|
|
|
|
use serde::de;
|
2018-07-17 20:24:41 +00:00
|
|
|
use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
|
2018-07-16 19:46:10 +00:00
|
|
|
use serde::ser;
|
2019-03-19 17:45:26 +00:00
|
|
|
use serde::ser::{Serialize, SerializeSeq, SerializeStruct, SerializeTuple, Serializer};
|
2018-07-16 19:46:10 +00:00
|
|
|
|
2018-07-17 20:24:41 +00:00
|
|
|
use std::cell::RefCell;
|
2018-07-16 19:46:10 +00:00
|
|
|
use std::fmt;
|
2018-07-17 20:24:41 +00:00
|
|
|
use std::rc::Rc;
|
2018-07-16 19:46:10 +00:00
|
|
|
|
2019-08-19 13:32:40 +00:00
|
|
|
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};
|
2018-07-16 19:46:10 +00:00
|
|
|
use DateTime;
|
|
|
|
use Sample;
|
2018-07-17 20:24:41 +00:00
|
|
|
use TagMergeMode;
|
2019-03-19 17:45:26 +00:00
|
|
|
use TagScope;
|
2018-07-16 19:46:10 +00:00
|
|
|
|
2019-08-16 22:55:09 +00:00
|
|
|
macro_rules! ser_some_tag (
|
2018-07-17 20:24:41 +00:00
|
|
|
($value:ident, $seq:ident, $t:ty) => (
|
2019-08-16 22:55:09 +00:00
|
|
|
ser_some_value!($value, $t, |_, value| {
|
2018-07-17 20:24:41 +00:00
|
|
|
$seq.serialize_element(&value)
|
2018-07-16 19:46:10 +00:00
|
|
|
})
|
|
|
|
);
|
|
|
|
);
|
2019-08-16 22:55:09 +00:00
|
|
|
macro_rules! ser_opt_tag (
|
|
|
|
($value:ident, $seq:ident, $t:ty) => (
|
|
|
|
ser_opt_value!($value, $t, |_, value| {
|
|
|
|
$seq.serialize_element(&value)
|
|
|
|
})
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
// Note: unlike `Value`s, `Tag`s with optional `Type` `String` & `Date` values are guarenteed
|
|
|
|
// 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
|
|
|
|
|
2018-07-17 20:24:41 +00:00
|
|
|
// serialize trait is only available for `&self`, but we need to mutate the iterator
|
2018-10-28 17:48:42 +00:00
|
|
|
struct TagValuesSer<'a>(Rc<RefCell<GenericTagIter<'a>>>);
|
2018-07-17 20:24:41 +00:00
|
|
|
impl<'a> TagValuesSer<'a> {
|
|
|
|
fn from(tags_ser: &TagsSer<'a>) -> Self {
|
|
|
|
TagValuesSer(Rc::clone(&tags_ser.1))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Serialize for TagValuesSer<'a> {
|
2018-07-16 19:46:10 +00:00
|
|
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
2018-10-11 08:25:28 +00:00
|
|
|
use std::ops::DerefMut;
|
|
|
|
|
2018-07-17 20:24:41 +00:00
|
|
|
let mut tag_iter = self.0.borrow_mut();
|
|
|
|
let mut seq = serializer.serialize_seq(tag_iter.size_hint().1)?;
|
2018-10-11 08:25:28 +00:00
|
|
|
for value in tag_iter.deref_mut() {
|
2018-07-17 20:24:41 +00:00
|
|
|
match value.type_() {
|
2019-08-16 22:55:09 +00:00
|
|
|
glib::Type::F64 => ser_some_tag!(value, seq, f64),
|
|
|
|
glib::Type::String => {
|
|
|
|
// See above comment about `Tag`s with `String` values
|
|
|
|
ser_opt_value!(value, String, |_, value: Option<String>| {
|
2019-08-19 13:32:40 +00:00
|
|
|
seq.serialize_element(&value.expect("String tag ser"))
|
2019-08-16 22:55:09 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
glib::Type::U32 => ser_some_tag!(value, seq, u32),
|
|
|
|
glib::Type::U64 => ser_some_tag!(value, seq, u64),
|
2018-07-17 20:24:41 +00:00
|
|
|
glib::Type::Other(type_id) => {
|
2019-08-19 13:32:40 +00:00
|
|
|
if *DATE_OTHER_TYPE_ID == type_id {
|
|
|
|
// See above comment about `Tag`s with `Date` values
|
|
|
|
ser_opt_value!(value, Date, |_, value: Option<Date>| {
|
|
|
|
// 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 {
|
2019-08-16 22:55:09 +00:00
|
|
|
ser_opt_tag!(value, seq, DateTime)
|
2018-07-17 20:24:41 +00:00
|
|
|
} else if *SAMPLE_OTHER_TYPE_ID == type_id {
|
2019-08-16 22:55:09 +00:00
|
|
|
ser_opt_tag!(value, seq, Sample)
|
2018-07-17 20:24:41 +00:00
|
|
|
} else {
|
2018-07-22 14:55:24 +00:00
|
|
|
Err(ser::Error::custom(format!(
|
|
|
|
"unimplemented `Tag` serialization for type {}",
|
|
|
|
glib::Type::Other(type_id),
|
|
|
|
)))
|
2018-07-17 20:24:41 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-22 14:55:24 +00:00
|
|
|
type_ => Err(ser::Error::custom(format!(
|
|
|
|
"unimplemented `Tag` serialization for type {}",
|
|
|
|
type_
|
|
|
|
))),
|
2018-07-17 20:24:41 +00:00
|
|
|
}?;
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
2018-07-17 20:24:41 +00:00
|
|
|
seq.end()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-28 17:48:42 +00:00
|
|
|
struct TagsSer<'a>(&'a str, Rc<RefCell<GenericTagIter<'a>>>);
|
2018-07-17 20:24:41 +00:00
|
|
|
impl<'a> TagsSer<'a> {
|
2018-10-28 17:48:42 +00:00
|
|
|
fn new(name: &'a str, tag_iter: GenericTagIter<'a>) -> Self {
|
2018-07-17 20:24:41 +00:00
|
|
|
TagsSer(name, Rc::new(RefCell::new(tag_iter)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Serialize for TagsSer<'a> {
|
|
|
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
|
|
let mut tup = serializer.serialize_tuple(2)?;
|
|
|
|
tup.serialize_element(self.0)?;
|
|
|
|
tup.serialize_element(&TagValuesSer::from(&self))?;
|
|
|
|
tup.end()
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 17:45:26 +00:00
|
|
|
struct TagListSer<'a>(&'a TagListRef);
|
|
|
|
impl<'a> Serialize for TagListSer<'a> {
|
2018-07-16 19:46:10 +00:00
|
|
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
2019-03-19 17:45:26 +00:00
|
|
|
let tag_count = self.0.n_tags();
|
2018-07-16 19:46:10 +00:00
|
|
|
if tag_count > 0 {
|
|
|
|
let mut seq = serializer.serialize_seq(Some(tag_count as usize))?;
|
2019-03-19 17:45:26 +00:00
|
|
|
let tag_list_iter = self.0.iter_generic();
|
2018-07-17 20:24:41 +00:00
|
|
|
for (tag_name, tag_iter) in tag_list_iter {
|
|
|
|
seq.serialize_element(&TagsSer::new(tag_name, tag_iter))?;
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
seq.end()
|
|
|
|
} else if tag_count == 0 {
|
|
|
|
let seq = serializer.serialize_seq(None)?;
|
|
|
|
seq.end()
|
|
|
|
} else {
|
|
|
|
Err(ser::Error::custom("tag count < 0"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 17:45:26 +00:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-16 19:46:10 +00:00
|
|
|
impl Serialize for TagList {
|
|
|
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
|
|
self.as_ref().serialize(serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-16 22:55:09 +00:00
|
|
|
macro_rules! de_some_tag(
|
|
|
|
($tag_name:expr, $seq:expr, $t:ty) => (
|
|
|
|
de_some_send_value!("Tag", $tag_name, $seq, $t)
|
|
|
|
);
|
|
|
|
);
|
|
|
|
macro_rules! de_opt_tag(
|
2018-07-16 19:46:10 +00:00
|
|
|
($tag_name:expr, $seq:expr, $t:ty) => (
|
2019-08-16 22:55:09 +00:00
|
|
|
de_opt_send_value!("Tag", $tag_name, $seq, $t)
|
2018-07-16 19:46:10 +00:00
|
|
|
);
|
|
|
|
);
|
|
|
|
|
2018-07-17 20:24:41 +00:00
|
|
|
struct TagValues<'a>(&'a str, &'a mut TagListRef);
|
|
|
|
|
|
|
|
struct TagValuesVisitor<'a>(&'a str, &'a mut TagListRef);
|
|
|
|
impl<'de, 'a> Visitor<'de> for TagValuesVisitor<'a> {
|
|
|
|
type Value = ();
|
2018-07-16 19:46:10 +00:00
|
|
|
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
2018-07-17 20:24:41 +00:00
|
|
|
formatter.write_str("a sequence of `Tag` values with the same type")
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
|
2018-07-17 20:24:41 +00:00
|
|
|
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> {
|
|
|
|
let tag_type: glib::Type = unsafe {
|
|
|
|
let tag_name = self.0.to_glib_none();
|
2019-03-19 07:58:20 +00:00
|
|
|
from_glib(gst_sys::gst_tag_get_type(tag_name.0))
|
2018-07-17 20:24:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let tag_value = match tag_type {
|
2019-08-16 22:55:09 +00:00
|
|
|
glib::Type::F64 => de_some_tag!(self.0, seq, f64),
|
|
|
|
glib::Type::String => {
|
|
|
|
// See comment above `TagValuesSer` definition about `Tag`s with `String` values
|
|
|
|
de_some_tag!(self.0, seq, String)
|
|
|
|
}
|
|
|
|
glib::Type::U32 => de_some_tag!(self.0, seq, u32),
|
|
|
|
glib::Type::U64 => de_some_tag!(self.0, seq, u64),
|
2018-07-16 19:46:10 +00:00
|
|
|
glib::Type::Other(type_id) => {
|
2019-08-19 13:32:40 +00:00
|
|
|
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 {
|
2019-08-16 22:55:09 +00:00
|
|
|
de_opt_tag!(self.0, seq, DateTime)
|
2018-07-16 19:46:10 +00:00
|
|
|
} else if *SAMPLE_OTHER_TYPE_ID == type_id {
|
2019-08-16 22:55:09 +00:00
|
|
|
de_opt_tag!(self.0, seq, Sample)
|
2018-07-16 19:46:10 +00:00
|
|
|
} else {
|
2018-07-22 14:55:24 +00:00
|
|
|
return Err(de::Error::custom(format!(
|
|
|
|
"unimplemented deserialization for `Tag` {} with type `{}`",
|
|
|
|
self.0,
|
|
|
|
glib::Type::Other(type_id),
|
|
|
|
)));
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
type_ => {
|
2018-07-22 14:55:24 +00:00
|
|
|
return Err(de::Error::custom(format!(
|
|
|
|
"unimplemented deserialization for `Tag` {} with type `{}`",
|
|
|
|
self.0, type_,
|
|
|
|
)));
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
2018-07-17 20:24:41 +00:00
|
|
|
}?;
|
|
|
|
|
|
|
|
match tag_value {
|
2018-07-22 14:55:24 +00:00
|
|
|
Some(tag_value) => self
|
|
|
|
.1
|
|
|
|
.add_generic(self.0, &tag_value, TagMergeMode::Append)
|
|
|
|
.map_err(|_| {
|
|
|
|
de::Error::custom(format!("wrong value type for `Tag` {}", self.0))
|
|
|
|
})?,
|
2018-07-17 20:24:41 +00:00
|
|
|
None => break,
|
|
|
|
}
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
2018-07-17 20:24:41 +00:00
|
|
|
|
|
|
|
Ok(())
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-17 20:24:41 +00:00
|
|
|
impl<'de, 'a> DeserializeSeed<'de> for TagValues<'a> {
|
|
|
|
type Value = ();
|
|
|
|
|
|
|
|
fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> {
|
|
|
|
deserializer.deserialize_seq(TagValuesVisitor(self.0, self.1))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TagValuesTuple<'a>(&'a mut TagListRef);
|
|
|
|
|
|
|
|
struct TagValuesTupleVisitor<'a>(&'a mut TagListRef);
|
|
|
|
impl<'de, 'a> Visitor<'de> for TagValuesTupleVisitor<'a> {
|
|
|
|
type Value = ();
|
|
|
|
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
2018-07-22 14:55:24 +00:00
|
|
|
formatter
|
|
|
|
.write_str("a tuple (`Tag` name: `String`, seq. of `Tag` values with the same type)")
|
2018-07-17 20:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<(), A::Error> {
|
|
|
|
let name = seq
|
|
|
|
.next_element::<String>()
|
2018-07-22 14:55:24 +00:00
|
|
|
.map_err(|err| de::Error::custom(format!("Error reading Tag name. {:?}", err)))?
|
2018-10-11 08:25:28 +00:00
|
|
|
.ok_or_else(|| de::Error::custom("Expected a name for the `Tag` name"))?;
|
2018-07-17 20:24:41 +00:00
|
|
|
seq.next_element_seed(TagValues(name.as_str(), self.0))?
|
2018-10-11 08:25:28 +00:00
|
|
|
.ok_or_else(|| de::Error::custom("Expected a seq of values for the `Tag`"))
|
2018-07-17 20:24:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de, 'a> DeserializeSeed<'de> for TagValuesTuple<'a> {
|
|
|
|
type Value = ();
|
|
|
|
|
|
|
|
fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<(), D::Error> {
|
|
|
|
deserializer.deserialize_tuple(2, TagValuesTupleVisitor(self.0))
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 17:45:26 +00:00
|
|
|
struct TagsDe(TagList);
|
|
|
|
|
|
|
|
struct TagsVisitor;
|
|
|
|
impl<'de> Visitor<'de> for TagsVisitor {
|
|
|
|
type Value = TagsDe;
|
2018-07-16 19:46:10 +00:00
|
|
|
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
2018-07-17 20:24:41 +00:00
|
|
|
formatter.write_str("a sequence of `Tag`s")
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
|
2018-07-17 20:24:41 +00:00
|
|
|
let mut tag_list = TagList::new();
|
|
|
|
{
|
|
|
|
let tag_list = tag_list.get_mut().unwrap();
|
|
|
|
while seq.next_element_seed(TagValuesTuple(tag_list))?.is_some() {
|
|
|
|
// tags are added in the dedicated deserializers
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-19 17:45:26 +00:00
|
|
|
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
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for TagList {
|
|
|
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
2019-03-19 17:45:26 +00:00
|
|
|
TagListDe::deserialize(deserializer).map(|tag_list_de| tag_list_de.into())
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
extern crate ron;
|
|
|
|
|
|
|
|
use tags::*;
|
2018-07-29 16:18:24 +00:00
|
|
|
use Buffer;
|
|
|
|
use Sample;
|
|
|
|
use TagMergeMode;
|
2019-03-19 17:45:26 +00:00
|
|
|
use TagScope;
|
2018-07-16 19:46:10 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_serialize() {
|
|
|
|
::init().unwrap();
|
|
|
|
|
|
|
|
let mut tags = TagList::new();
|
|
|
|
assert_eq!(tags.to_string(), "taglist;");
|
|
|
|
{
|
|
|
|
let tags = tags.get_mut().unwrap();
|
|
|
|
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
|
|
|
|
tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32
|
|
|
|
tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64
|
2019-08-19 13:32:40 +00:00
|
|
|
tags.add::<Date>(
|
|
|
|
&glib::Date::new_dmy(28, glib::DateMonth::May, 2018),
|
|
|
|
TagMergeMode::Append,
|
|
|
|
);
|
2018-07-29 20:11:25 +00:00
|
|
|
tags.add::<DateTime>(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append);
|
2018-07-16 19:46:10 +00:00
|
|
|
|
|
|
|
let sample = {
|
2018-12-26 07:50:44 +00:00
|
|
|
let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]);
|
2018-07-16 19:46:10 +00:00
|
|
|
{
|
|
|
|
let buffer = buffer.get_mut().unwrap();
|
|
|
|
buffer.set_offset(0);
|
|
|
|
buffer.set_offset_end(0);
|
|
|
|
}
|
2019-10-22 20:32:39 +00:00
|
|
|
Sample::new().buffer(&buffer).build()
|
2018-07-16 19:46:10 +00:00
|
|
|
};
|
|
|
|
tags.add::<Image>(&sample, TagMergeMode::Append); // Sample
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut pretty_config = ron::ser::PrettyConfig::default();
|
|
|
|
pretty_config.new_line = "".to_string();
|
|
|
|
|
|
|
|
let res = ron::ser::to_string_pretty(&tags, pretty_config);
|
|
|
|
assert_eq!(
|
2018-07-22 14:55:24 +00:00
|
|
|
Ok(concat!(
|
2019-08-19 13:32:40 +00:00
|
|
|
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#")"#,
|
2018-10-08 12:02:23 +00:00
|
|
|
)
|
|
|
|
.to_owned()),
|
2018-07-16 19:46:10 +00:00
|
|
|
res,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deserialize() {
|
|
|
|
extern crate serde_json;
|
|
|
|
|
|
|
|
::init().unwrap();
|
|
|
|
|
|
|
|
let tag_list_ron = r#"
|
2019-03-19 17:45:26 +00:00
|
|
|
(
|
|
|
|
scope: Global,
|
|
|
|
tags: [
|
|
|
|
("title", [
|
|
|
|
"a title",
|
|
|
|
"another title",
|
|
|
|
]),
|
|
|
|
("duration", [120000000000]),
|
|
|
|
("bitrate", [96000]),
|
|
|
|
("replaygain-track-gain", [1]),
|
2019-08-19 13:32:40 +00:00
|
|
|
("date", [
|
|
|
|
YMD(2018, 5, 28),
|
|
|
|
]),
|
2019-03-19 17:45:26 +00:00
|
|
|
("datetime", [
|
2019-08-16 22:55:09 +00:00
|
|
|
Some(YMD(2018, 5, 28)),
|
2019-03-19 17:45:26 +00:00
|
|
|
]),
|
|
|
|
("image", [
|
2019-08-16 22:55:09 +00:00
|
|
|
Some((
|
2019-03-19 17:45:26 +00:00
|
|
|
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,
|
2019-08-16 22:55:09 +00:00
|
|
|
)),
|
2019-03-19 17:45:26 +00:00
|
|
|
])
|
|
|
|
],
|
|
|
|
)
|
2018-07-16 19:46:10 +00:00
|
|
|
"#;
|
|
|
|
let tags: TagList = ron::de::from_str(tag_list_ron).unwrap();
|
2019-03-19 17:45:26 +00:00
|
|
|
assert_eq!(tags.get_scope(), TagScope::Global);
|
|
|
|
|
2018-07-16 19:46:10 +00:00
|
|
|
assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title"));
|
2018-07-22 14:55:24 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags.get_index::<Title>(1).unwrap().get(),
|
|
|
|
Some("another title")
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2019-08-16 22:55:09 +00:00
|
|
|
tags.get_index::<Duration>(0).unwrap().get_some(),
|
|
|
|
::SECOND * 120
|
2018-07-22 14:55:24 +00:00
|
|
|
);
|
2019-08-16 22:55:09 +00:00
|
|
|
assert_eq!(tags.get_index::<Bitrate>(0).unwrap().get_some(), 96_000);
|
|
|
|
assert_eq!(tags.get_index::<TrackGain>(0).unwrap().get_some(), 1f64);
|
2019-08-19 13:32:40 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags.get_index::<Date>(0).unwrap().get().unwrap(),
|
|
|
|
glib::Date::new_dmy(28, glib::DateMonth::May, 2018)
|
|
|
|
);
|
2019-08-21 09:06:03 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags.get_index::<DateTime>(0).unwrap().get().unwrap(),
|
|
|
|
::DateTime::new_ymd(2018, 5, 28)
|
|
|
|
);
|
2018-07-16 19:46:10 +00:00
|
|
|
let sample = tags.get_index::<Image>(0).unwrap().get().unwrap();
|
|
|
|
let buffer = sample.get_buffer().unwrap();
|
|
|
|
{
|
|
|
|
let data = buffer.map_readable().unwrap();
|
|
|
|
assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
|
|
|
|
}
|
|
|
|
|
|
|
|
let tag_json = r#"
|
2019-03-19 17:45:26 +00:00
|
|
|
{
|
|
|
|
"scope":"Global",
|
|
|
|
"tags":[
|
|
|
|
["title", ["a title", "another title"]],
|
|
|
|
["duration", [120000000000]],
|
|
|
|
["bitrate", [96000]],
|
|
|
|
["replaygain-track-gain", [1.0]],
|
2019-08-19 13:32:40 +00:00
|
|
|
["date",[{"YMD":[2018,5,28]}]],
|
2019-03-19 17:45:26 +00:00
|
|
|
["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}]]
|
|
|
|
]
|
|
|
|
}
|
2018-07-16 19:46:10 +00:00
|
|
|
"#;
|
|
|
|
let tags: TagList = serde_json::from_str(tag_json).unwrap();
|
2019-03-19 17:45:26 +00:00
|
|
|
assert_eq!(tags.get_scope(), TagScope::Global);
|
|
|
|
|
2018-07-16 19:46:10 +00:00
|
|
|
assert_eq!(tags.get_index::<Title>(0).unwrap().get(), Some("a title"));
|
2018-07-22 14:55:24 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags.get_index::<Title>(1).unwrap().get(),
|
|
|
|
Some("another title")
|
|
|
|
);
|
2019-08-16 22:55:09 +00:00
|
|
|
assert_eq!(tags.get_index::<Bitrate>(0).unwrap().get_some(), 96_000);
|
|
|
|
assert_eq!(tags.get_index::<TrackGain>(0).unwrap().get_some(), 1f64);
|
2019-08-19 13:32:40 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags.get_index::<Date>(0).unwrap().get().unwrap(),
|
|
|
|
glib::Date::new_dmy(28, glib::DateMonth::May, 2018)
|
|
|
|
);
|
2019-08-21 09:06:03 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags.get_index::<DateTime>(0).unwrap().get().unwrap(),
|
|
|
|
::DateTime::new_ymd(2018, 5, 28)
|
|
|
|
);
|
2018-07-16 19:46:10 +00:00
|
|
|
let sample = tags.get_index::<Image>(0).unwrap().get().unwrap();
|
|
|
|
let buffer = sample.get_buffer().unwrap();
|
|
|
|
{
|
|
|
|
let data = buffer.map_readable().unwrap();
|
|
|
|
assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
|
|
|
|
}
|
|
|
|
}
|
2018-07-29 16:18:24 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_serde_roundtrip() {
|
|
|
|
::init().unwrap();
|
|
|
|
|
|
|
|
let mut tags = TagList::new();
|
|
|
|
assert_eq!(tags.to_string(), "taglist;");
|
|
|
|
{
|
|
|
|
let tags = tags.get_mut().unwrap();
|
2019-03-19 17:45:26 +00:00
|
|
|
tags.set_scope(TagScope::Global);
|
2018-07-29 16:18:24 +00:00
|
|
|
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
|
|
|
|
tags.add::<Bitrate>(&96_000, TagMergeMode::Append); // u32
|
|
|
|
tags.add::<TrackGain>(&1f64, TagMergeMode::Append); // f64
|
2019-08-19 13:32:40 +00:00
|
|
|
tags.add::<Date>(
|
|
|
|
&glib::Date::new_dmy(28, glib::DateMonth::May, 2018),
|
|
|
|
TagMergeMode::Append,
|
|
|
|
);
|
2018-07-29 20:11:25 +00:00
|
|
|
tags.add::<DateTime>(&::DateTime::new_ymd(2018, 5, 28), TagMergeMode::Append);
|
2018-07-29 16:18:24 +00:00
|
|
|
|
|
|
|
let sample = {
|
2018-12-26 07:50:44 +00:00
|
|
|
let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]);
|
2018-07-29 16:18:24 +00:00
|
|
|
{
|
|
|
|
let buffer = buffer.get_mut().unwrap();
|
|
|
|
buffer.set_offset(0);
|
|
|
|
buffer.set_offset_end(0);
|
|
|
|
}
|
2019-10-22 20:32:39 +00:00
|
|
|
Sample::new().buffer(&buffer).build()
|
2018-07-29 16:18:24 +00:00
|
|
|
};
|
|
|
|
tags.add::<Image>(&sample, TagMergeMode::Append); // Sample
|
|
|
|
}
|
|
|
|
let tags_ser = ron::ser::to_string(&tags).unwrap();
|
|
|
|
|
|
|
|
let tags_de: TagList = ron::de::from_str(tags_ser.as_str()).unwrap();
|
2019-03-19 17:45:26 +00:00
|
|
|
assert_eq!(tags_de.get_scope(), TagScope::Global);
|
|
|
|
|
2018-07-29 16:18:24 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags_de.get_index::<Title>(0).unwrap().get(),
|
|
|
|
tags.get_index::<Title>(0).unwrap().get(),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
tags_de.get_index::<Title>(1).unwrap().get(),
|
|
|
|
tags.get_index::<Title>(1).unwrap().get(),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2019-08-16 22:55:09 +00:00
|
|
|
tags_de.get_index::<Duration>(0).unwrap().get_some(),
|
|
|
|
tags.get_index::<Duration>(0).unwrap().get_some(),
|
2018-07-29 16:18:24 +00:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2019-08-16 22:55:09 +00:00
|
|
|
tags_de.get_index::<Bitrate>(0).unwrap().get_some(),
|
|
|
|
tags.get_index::<Bitrate>(0).unwrap().get_some(),
|
2018-07-29 16:18:24 +00:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2019-08-16 22:55:09 +00:00
|
|
|
tags_de.get_index::<TrackGain>(0).unwrap().get_some(),
|
|
|
|
tags.get_index::<TrackGain>(0).unwrap().get_some(),
|
2018-07-29 16:18:24 +00:00
|
|
|
);
|
2019-08-19 13:32:40 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags_de.get_index::<Date>(0).unwrap().get(),
|
|
|
|
tags.get_index::<Date>(0).unwrap().get(),
|
|
|
|
);
|
2019-08-21 09:06:03 +00:00
|
|
|
assert_eq!(
|
|
|
|
tags.get_index::<DateTime>(0).unwrap().get().unwrap(),
|
|
|
|
::DateTime::new_ymd(2018, 5, 28)
|
|
|
|
);
|
2018-07-29 16:18:24 +00:00
|
|
|
let sample = tags.get_index::<Image>(0).unwrap().get().unwrap();
|
|
|
|
let buffer = sample.get_buffer().unwrap();
|
|
|
|
{
|
|
|
|
let data = buffer.map_readable().unwrap();
|
|
|
|
assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice());
|
|
|
|
}
|
|
|
|
}
|
2018-07-16 19:46:10 +00:00
|
|
|
}
|