use super::*;
use serde::{
Deserialize, Deserializer,
de::{
IntoDeserializer, Visitor,
value::{Error, MapDeserializer},
},
forward_to_deserialize_any,
};
fn de(num: i32, den: i32) -> Result<Timebase, Error> {
Timebase::deserialize(MapDeserializer::new(
[("numerator", num), ("denominator", den)].into_iter(),
))
}
enum Field {
Integer(i64),
Timebase(i32, i32),
}
impl IntoDeserializer<'_, Error> for Field {
type Deserializer = Self;
fn into_deserializer(self) -> Self {
self
}
}
impl<'de> Deserializer<'de> for Field {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
match self {
Self::Integer(v) => visitor.visit_i64(v),
Self::Timebase(num, den) => visitor.visit_map(MapDeserializer::new(
[("numerator", num), ("denominator", den)].into_iter(),
)),
}
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
fn de_span(ticks: i64, num: i32, den: i32) -> Result<SignedDuration, Error> {
SignedDuration::deserialize(MapDeserializer::new(
[
("ticks", Field::Integer(ticks)),
("timebase", Field::Timebase(num, den)),
]
.into_iter(),
))
}
fn de_range(start: i64, end: i64, num: i32, den: i32) -> Result<TimeRange, Error> {
TimeRange::deserialize(MapDeserializer::new(
[
("start", Field::Integer(start)),
("end", Field::Integer(end)),
("timebase", Field::Timebase(num, den)),
]
.into_iter(),
))
}
#[test]
fn deserialize_accepts_the_values_the_constructor_accepts() {
assert_eq!(de(30_000, 1001).unwrap(), Timebase::new(30_000, nz(1001)));
assert_eq!(de(0, 3).unwrap(), Timebase::new(0, nz(3)));
assert_eq!(
de(i32::MAX, i32::MAX).unwrap(),
Timebase::new(i32::MAX, nz(i32::MAX))
);
}
#[test]
fn deserialize_rejects_what_the_constructor_rejects() {
assert!(de(-1, 1000).is_err());
assert!(de(1, -1000).is_err());
assert!(de(1, 0).is_err());
}
#[test]
fn field_names_are_unchanged() {
let by_wrong_name: Result<Timebase, Error> =
Timebase::deserialize(MapDeserializer::new([("num", 1), ("den", 2)].into_iter()));
assert!(by_wrong_name.is_err());
}
#[test]
fn rate_deserialize_is_its_rational() {
fn de_rate(num: i32, den: i32) -> Result<Rate, Error> {
Rate::deserialize(MapDeserializer::new(
[("numerator", num), ("denominator", den)].into_iter(),
))
}
assert_eq!(de_rate(30_000, 1001).unwrap(), Rate::FPS_29_97);
assert_eq!(de_rate(0, 1).unwrap(), Rate::hz(0));
assert!(de_rate(-1, 1001).is_err());
assert!(de_rate(30_000, 0).is_err());
assert!(de_rate(30_000, -1001).is_err());
}
#[test]
fn signed_duration_deserialize_admits_both_directions() {
let ms = Timebase::new(1, nz(1000));
assert_eq!(
de_span(-1500, 1, 1000).unwrap(),
SignedDuration::new(-1500, ms)
);
assert_eq!(
de_span(1500, 1, 1000).unwrap(),
SignedDuration::new(1500, ms)
);
assert!(de_span(0, -1, 1000).is_err());
assert!(de_span(0, 1, 0).is_err());
assert!(de_span(0, 1, -1000).is_err());
}
#[test]
fn signed_duration_field_names_are_unchanged() {
let renamed: Result<SignedDuration, Error> = SignedDuration::deserialize(MapDeserializer::new(
[
("count", Field::Integer(0)),
("timebase", Field::Timebase(1, 1000)),
]
.into_iter(),
));
assert!(renamed.is_err());
let missing_timebase: Result<SignedDuration, Error> = SignedDuration::deserialize(
MapDeserializer::new([("ticks", Field::Integer(0))].into_iter()),
);
assert!(missing_timebase.is_err());
}
#[test]
fn time_range_deserialize_accepts_what_the_constructor_accepts() {
let ms = Timebase::new(1, nz(1000));
assert_eq!(
de_range(1500, 3250, 1, 1000).unwrap(),
TimeRange::new(1500, 3250, ms)
);
assert_eq!(
de_range(42, 42, 1, 1000).unwrap(),
TimeRange::new(42, 42, ms)
);
assert_eq!(
de_range(-1500, 0, 1, 1000).unwrap(),
TimeRange::new(-1500, 0, ms)
);
}
#[test]
fn time_range_deserialize_rejects_backwards_endpoints() {
assert!(de_range(3250, 1500, 1, 1000).is_err());
assert!(de_range(0, i64::MIN, 1, 1000).is_err());
}
#[test]
fn time_range_deserialize_still_validates_its_timebase() {
assert!(de_range(0, 10, -1, 1000).is_err());
assert!(de_range(0, 10, 1, 0).is_err());
assert!(de_range(0, 10, 1, -1000).is_err());
}
#[test]
fn time_range_field_names_are_unchanged() {
let renamed: Result<TimeRange, Error> = TimeRange::deserialize(MapDeserializer::new(
[
("from", Field::Integer(0)),
("to", Field::Integer(10)),
("timebase", Field::Timebase(1, 1000)),
]
.into_iter(),
));
assert!(renamed.is_err());
let missing_end: Result<TimeRange, Error> = TimeRange::deserialize(MapDeserializer::new(
[
("start", Field::Integer(0)),
("timebase", Field::Timebase(1, 1000)),
]
.into_iter(),
));
assert!(missing_end.is_err());
}
#[test]
fn time_range_decode_preserves_every_field() {
let original = TimeRange::new(1500, 3250, Timebase::new(30_000, nz(1001)));
let decoded = de_range(1500, 3250, 30_000, 1001).expect("decodes");
assert_eq!(format!("{decoded:?}"), format!("{original:?}"));
}
const fn nz(n: i32) -> NonZeroI32 {
match NonZeroI32::new(n) {
Some(v) => v,
None => panic!("zero"),
}
}