use bitflags::bitflags;
bitflags! {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PacketFlags: u8 {
const KEY = 0b001;
const CORRUPT = 0b010;
const DISCARD = 0b100;
}
}
use crate::Timestamp;
pub struct VideoPacket<E, D> {
pts: Option<Timestamp>,
dts: Option<Timestamp>,
duration: Option<Timestamp>,
flags: PacketFlags,
data: D,
extra: E,
}
impl<E, D> VideoPacket<E, D> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(data: D, extra: E) -> Self {
Self {
pts: None,
dts: None,
duration: None,
flags: PacketFlags::empty(),
data,
extra,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pts(&self) -> Option<Timestamp> {
self.pts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn dts(&self) -> Option<Timestamp> {
self.dts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn duration(&self) -> Option<Timestamp> {
self.duration
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn flags(&self) -> PacketFlags {
self.flags
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data(&self) -> &D {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn extra(&self) -> &E {
&self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn extra_mut(&mut self) -> &mut E {
&mut self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_data(self) -> D {
self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_parts(self) -> (D, E) {
(self.data, self.extra)
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_dts(mut self, v: Option<Timestamp>) -> Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_flags(mut self, v: PacketFlags) -> Self {
self.flags = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_dts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
self.flags = v;
self
}
}
pub struct AudioPacket<E, D> {
pts: Option<Timestamp>,
dts: Option<Timestamp>,
duration: Option<Timestamp>,
flags: PacketFlags,
data: D,
extra: E,
}
impl<E, D> AudioPacket<E, D> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(data: D, extra: E) -> Self {
Self {
pts: None,
dts: None,
duration: None,
flags: PacketFlags::empty(),
data,
extra,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pts(&self) -> Option<Timestamp> {
self.pts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn dts(&self) -> Option<Timestamp> {
self.dts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn duration(&self) -> Option<Timestamp> {
self.duration
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn flags(&self) -> PacketFlags {
self.flags
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data(&self) -> &D {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn extra(&self) -> &E {
&self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn extra_mut(&mut self) -> &mut E {
&mut self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_data(self) -> D {
self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_parts(self) -> (D, E) {
(self.data, self.extra)
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_dts(mut self, v: Option<Timestamp>) -> Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_flags(mut self, v: PacketFlags) -> Self {
self.flags = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_dts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
self.flags = v;
self
}
}
pub struct SubtitlePacket<E, D> {
pts: Option<Timestamp>,
duration: Option<Timestamp>,
flags: PacketFlags,
data: D,
extra: E,
}
impl<E, D> SubtitlePacket<E, D> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(data: D, extra: E) -> Self {
Self {
pts: None,
duration: None,
flags: PacketFlags::empty(),
data,
extra,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pts(&self) -> Option<Timestamp> {
self.pts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn duration(&self) -> Option<Timestamp> {
self.duration
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn flags(&self) -> PacketFlags {
self.flags
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data(&self) -> &D {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn extra(&self) -> &E {
&self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn extra_mut(&mut self) -> &mut E {
&mut self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_data(self) -> D {
self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_parts(self) -> (D, E) {
(self.data, self.extra)
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_flags(mut self, v: PacketFlags) -> Self {
self.flags = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
self.flags = v;
self
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
mod serde_impls {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::PacketFlags;
impl Serialize for PacketFlags {
#[cfg_attr(not(tarpaulin), inline(always))]
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_u8(self.bits())
}
}
impl<'de> Deserialize<'de> for PacketFlags {
#[cfg_attr(not(tarpaulin), inline(always))]
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
u8::deserialize(de).map(Self::from_bits_retain)
}
}
}
#[cfg(feature = "arbitrary")]
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
mod arbitrary_impls {
use arbitrary::{Arbitrary, Result, Unstructured};
use super::PacketFlags;
impl<'a> Arbitrary<'a> for PacketFlags {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
Ok(Self::from_bits_retain(u8::arbitrary(u)?))
}
}
}
#[cfg(feature = "quickcheck")]
#[cfg_attr(docsrs, doc(cfg(feature = "quickcheck")))]
mod quickcheck_impls {
use quickcheck::{Arbitrary, Gen};
use super::PacketFlags;
impl Arbitrary for PacketFlags {
fn arbitrary(g: &mut Gen) -> Self {
Self::from_bits_retain(u8::arbitrary(g))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flag_bits_are_stable() {
assert_eq!(PacketFlags::KEY.bits(), 0b001);
assert_eq!(PacketFlags::CORRUPT.bits(), 0b010);
assert_eq!(PacketFlags::DISCARD.bits(), 0b100);
}
#[test]
fn flags_combine() {
let f = PacketFlags::KEY | PacketFlags::CORRUPT;
assert!(f.contains(PacketFlags::KEY));
assert!(f.contains(PacketFlags::CORRUPT));
assert!(!f.contains(PacketFlags::DISCARD));
}
#[test]
fn empty_default() {
assert_eq!(PacketFlags::default(), PacketFlags::empty());
}
use crate::Timebase;
use core::num::NonZeroI32;
fn ms_tb() -> Timebase {
Timebase::new(1, NonZeroI32::new(1000).unwrap())
}
#[test]
fn video_packet_construct_and_access() {
let data: &[u8] = &[1, 2, 3];
let p: VideoPacket<_, &[u8]> = VideoPacket::new(data, ());
assert_eq!(p.pts(), None);
assert_eq!(p.flags(), PacketFlags::empty());
assert_eq!(*p.data(), data);
}
#[test]
fn video_packet_builders_chain() {
let pts = crate::Timestamp::new(1500, ms_tb());
let p: VideoPacket<_, &[u8]> = VideoPacket::new(&[][..], ())
.with_pts(Some(pts))
.with_flags(PacketFlags::KEY);
assert_eq!(p.pts(), Some(pts));
assert!(p.flags().contains(PacketFlags::KEY));
}
#[test]
fn video_packet_into_parts() {
let p: VideoPacket<_, &[u8]> = VideoPacket::new(&[1u8, 2][..], ());
let (data, _extra) = p.into_parts();
assert_eq!(data, &[1, 2]);
}
#[test]
fn audio_packet_round_trip() {
let data: &[u8] = &[7, 8, 9];
let p: AudioPacket<_, &[u8]> = AudioPacket::new(data, ()).with_flags(PacketFlags::KEY);
assert_eq!(*p.data(), data);
assert!(p.flags().contains(PacketFlags::KEY));
let (recovered, _) = p.into_parts();
assert_eq!(recovered, data);
}
#[test]
fn subtitle_packet_round_trip() {
let data: &[u8] = b"hi";
let p: SubtitlePacket<_, &[u8]> = SubtitlePacket::new(data, ());
assert_eq!(*p.data(), data);
}
#[cfg(all(feature = "serde", any(feature = "alloc", feature = "std")))]
mod serde_tests {
extern crate alloc;
use alloc::string::ToString;
use super::*;
#[test]
fn the_wire_is_a_number_not_a_flag_grammar() {
let flags = PacketFlags::KEY | PacketFlags::CORRUPT;
assert_eq!(
serde_json::to_string(&flags).expect("flags always serialize"),
"3"
);
assert_eq!(
serde_json::to_string(&PacketFlags::empty()).expect("flags always serialize"),
"0"
);
}
#[test]
fn a_name_is_not_a_number() {
assert!(serde_json::from_str::<PacketFlags>(r#""KEY""#).is_err());
assert!(serde_json::from_str::<PacketFlags>(r#""key|corrupt""#).is_err());
}
#[test]
fn every_bit_pattern_round_trips_including_the_unnamed_ones() {
for bits in 0..=u8::MAX {
let flags = PacketFlags::from_bits_retain(bits);
let json = serde_json::to_string(&flags).expect("flags always serialize");
assert_eq!(json, bits.to_string());
assert_eq!(
serde_json::from_str::<PacketFlags>(&json).expect("its own output parses"),
flags,
"round-trip failed for {bits:#010b}"
);
}
}
#[test]
fn a_value_no_u8_can_hold_is_refused() {
assert!(serde_json::from_str::<PacketFlags>("256").is_err());
assert!(serde_json::from_str::<PacketFlags>("-1").is_err());
}
}
#[cfg(feature = "arbitrary")]
mod arbitrary_tests {
use arbitrary::{Arbitrary, Unstructured};
use super::*;
#[test]
fn every_bit_pattern_is_reachable() {
let mut seen = [false; 256];
for byte in 0..=u8::MAX {
let data = [byte];
let mut u = Unstructured::new(&data);
let flags = PacketFlags::arbitrary(&mut u).expect("the generator is total");
seen[flags.bits() as usize] = true;
}
assert!(
seen.iter().all(|&s| s),
"a bit pattern the generator never produces"
);
}
}
#[cfg(feature = "quickcheck")]
mod quickcheck_tests {
use quickcheck::{Arbitrary, Gen};
use super::*;
#[test]
fn the_named_flags_and_the_unnamed_bits_are_both_reachable() {
let mut g = Gen::new(16);
let mut union = PacketFlags::empty();
let mut saw_unnamed = false;
for _ in 0..4000 {
let flags = PacketFlags::arbitrary(&mut g);
union |= flags;
saw_unnamed |= !PacketFlags::all().contains(flags);
}
assert_eq!(
union,
PacketFlags::from_bits_retain(u8::MAX),
"a bit the generator never sets"
);
assert!(saw_unnamed, "an unnamed bit is never produced");
}
}
}