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};
|
2018-07-17 20:24:41 +00:00
|
|
|
use glib::{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
|
|
|
|
2018-07-22 14:55:24 +00:00
|
|
|
use tags::*;
|
|
|
|
use value_serde::{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
|
|
|
|
|
|
|
macro_rules! ser_tag (
|
2018-07-17 20:24:41 +00:00
|
|
|
($value:ident, $seq:ident, $t:ty) => (
|
2018-07-29 20:03:48 +00:00
|
|
|
ser_value!($value, $t, |_, value| {
|
2018-07-17 20:24:41 +00:00
|
|
|
$seq.serialize_element(&value)
|
2018-07-16 19:46:10 +00:00
|
|
|
})
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
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_() {
|
|
|
|
glib::Type::F64 => ser_tag!(value, seq, f64),
|
|
|
|
glib::Type::String => ser_tag!(value, seq, String),
|
|
|
|
glib::Type::U32 => ser_tag!(value, seq, u32),
|
|
|
|
glib::Type::U64 => ser_tag!(value, seq, u64),
|
|
|
|
glib::Type::Other(type_id) => {
|
|
|
|
if *DATE_TIME_OTHER_TYPE_ID == type_id {
|
|
|
|
ser_tag!(value, seq, DateTime)
|
|
|
|
} else if *SAMPLE_OTHER_TYPE_ID == type_id {
|
|
|
|
ser_tag!(value, seq, Sample)
|
|
|
|
} 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! de_tag_value(
|
|
|
|
($tag_name:expr, $seq:expr, $t:ty) => (
|
2018-07-17 20:24:41 +00:00
|
|
|
de_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 {
|
|
|
|
glib::Type::F64 => de_tag_value!(self.0, seq, f64),
|
|
|
|
glib::Type::String => de_tag_value!(self.0, seq, String),
|
|
|
|
glib::Type::U32 => de_tag_value!(self.0, seq, u32),
|
|
|
|
glib::Type::U64 => de_tag_value!(self.0, seq, u64),
|
2018-07-16 19:46:10 +00:00
|
|
|
glib::Type::Other(type_id) => {
|
|
|
|
if *DATE_TIME_OTHER_TYPE_ID == type_id {
|
2018-07-17 20:24:41 +00:00
|
|
|
de_tag_value!(self.0, seq, DateTime)
|
2018-07-16 19:46:10 +00:00
|
|
|
} else if *SAMPLE_OTHER_TYPE_ID == type_id {
|
2018-07-17 20:24:41 +00:00
|
|
|
de_tag_value!(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 GenericFormattedValue;
|
|
|
|
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
|
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);
|
|
|
|
}
|
2018-07-22 14:55:24 +00:00
|
|
|
Sample::new::<GenericFormattedValue>(Some(&buffer), None, None, None)
|
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-03-19 17:45:26 +00:00
|
|
|
"(",
|
|
|
|
" 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,",
|
|
|
|
" ),",
|
|
|
|
" ]),",
|
|
|
|
" ],",
|
|
|
|
")",
|
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]),
|
|
|
|
("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,
|
|
|
|
),
|
|
|
|
])
|
|
|
|
],
|
|
|
|
)
|
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!(
|
|
|
|
tags.get_index::<Duration>(0).unwrap().get(),
|
|
|
|
Some(::SECOND * 120)
|
|
|
|
);
|
2018-07-16 19:46:10 +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));
|
|
|
|
let datetime = tags.get_index::<DateTime>(0).unwrap().get().unwrap();
|
|
|
|
assert_eq!(datetime.get_year(), 2018);
|
2018-07-29 20:11:25 +00:00
|
|
|
assert_eq!(datetime.get_month(), 5);
|
|
|
|
assert_eq!(datetime.get_day(), 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]],
|
|
|
|
["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")
|
|
|
|
);
|
2018-07-16 19:46:10 +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));
|
|
|
|
let datetime = tags.get_index::<DateTime>(0).unwrap().get().unwrap();
|
2018-07-29 20:11:25 +00:00
|
|
|
assert_eq!(datetime.get_year(), 2018);
|
2018-07-16 19:46:10 +00:00
|
|
|
assert_eq!(datetime.get_month(), 5);
|
2018-07-29 20:11:25 +00:00
|
|
|
assert_eq!(datetime.get_day(), 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
|
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);
|
|
|
|
}
|
|
|
|
Sample::new::<GenericFormattedValue>(Some(&buffer), None, None, None)
|
|
|
|
};
|
|
|
|
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!(
|
|
|
|
tags_de.get_index::<Duration>(0).unwrap().get(),
|
|
|
|
tags.get_index::<Duration>(0).unwrap().get(),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
tags_de.get_index::<Bitrate>(0).unwrap().get(),
|
|
|
|
tags.get_index::<Bitrate>(0).unwrap().get(),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
tags_de.get_index::<TrackGain>(0).unwrap().get(),
|
|
|
|
tags.get_index::<TrackGain>(0).unwrap().get(),
|
|
|
|
);
|
|
|
|
let datetime = tags.get_index::<DateTime>(0).unwrap().get().unwrap();
|
|
|
|
assert_eq!(datetime.get_year(), 2018);
|
2018-07-29 20:11:25 +00:00
|
|
|
assert_eq!(datetime.get_month(), 5);
|
|
|
|
assert_eq!(datetime.get_day(), 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
|
|
|
}
|