From 761360c0d3ec886e1061ab5a2ad010001053fddd Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Wed, 14 Feb 2018 12:00:19 +0900 Subject: [PATCH] Add `tag/basic` module --- examples/parse.rs | 3 +- src/master_playlist.rs | 2 +- src/media_playlist.rs | 2 +- src/tag/basic.rs | 93 +++++++++++++++++++++++++++++++ src/{tag.rs => tag/mod.rs} | 110 +++++++++---------------------------- 5 files changed, 123 insertions(+), 87 deletions(-) create mode 100644 src/tag/basic.rs rename src/{tag.rs => tag/mod.rs} (95%) diff --git a/examples/parse.rs b/examples/parse.rs index e6bcd8b..10b5f04 100644 --- a/examples/parse.rs +++ b/examples/parse.rs @@ -5,8 +5,7 @@ extern crate trackable; use std::io::{self, Read}; use clap::{App, Arg}; -use hls_m3u8::master_playlist::MasterPlaylist; -use hls_m3u8::media_playlist::MediaPlaylist; +use hls_m3u8::{MasterPlaylist, MediaPlaylist}; use trackable::error::Failure; fn main() { diff --git a/src/master_playlist.rs b/src/master_playlist.rs index 26d35c1..212d099 100644 --- a/src/master_playlist.rs +++ b/src/master_playlist.rs @@ -36,7 +36,7 @@ pub struct MasterPlaylist { impl fmt::Display for MasterPlaylist { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "{}", ExtM3u)?; - if self.version.value() != ProtocolVersion::V1 { + if self.version.version() != ProtocolVersion::V1 { writeln!(f, "{}", self.version)?; } for t in &self.media_tags { diff --git a/src/media_playlist.rs b/src/media_playlist.rs index 2a28d97..1c3071b 100644 --- a/src/media_playlist.rs +++ b/src/media_playlist.rs @@ -43,7 +43,7 @@ pub struct MediaPlaylist { impl fmt::Display for MediaPlaylist { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "{}", ExtM3u)?; - if self.version.value() != ProtocolVersion::V1 { + if self.version.version() != ProtocolVersion::V1 { writeln!(f, "{}", self.version)?; } writeln!(f, "{}", self.target_duration)?; diff --git a/src/tag/basic.rs b/src/tag/basic.rs new file mode 100644 index 0000000..66057ca --- /dev/null +++ b/src/tag/basic.rs @@ -0,0 +1,93 @@ +use std::fmt; +use std::str::FromStr; + +use {Error, ErrorKind, Result}; +use version::ProtocolVersion; + +/// [4.3.1.1. EXTM3U] +/// +/// [4.3.1.1. EXTM3U]: https://tools.ietf.org/html/rfc8216#section-4.3.1.1 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ExtM3u; +impl ExtM3u { + pub(crate) const PREFIX: &'static str = "#EXTM3U"; + + /// Returns the protocol compatibility version that this tag requires. + pub fn requires_version(&self) -> ProtocolVersion { + ProtocolVersion::V1 + } +} +impl fmt::Display for ExtM3u { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Self::PREFIX.fmt(f) + } +} +impl FromStr for ExtM3u { + type Err = Error; + fn from_str(s: &str) -> Result { + track_assert_eq!(s, Self::PREFIX, ErrorKind::InvalidInput); + Ok(ExtM3u) + } +} + +/// [4.3.1.2. EXT-X-VERSION] +/// +/// [4.3.1.2. EXT-X-VERSION]: https://tools.ietf.org/html/rfc8216#section-4.3.1.2 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ExtXVersion { + version: ProtocolVersion, +} +impl ExtXVersion { + pub(crate) const PREFIX: &'static str = "#EXT-X-VERSION:"; + + /// Makes a new `ExtXVersion` instance. + pub fn new(version: ProtocolVersion) -> Self { + ExtXVersion { version } + } + + /// Returns the protocol compatibility version of the playlist containing this tag. + pub fn version(&self) -> ProtocolVersion { + self.version + } + + /// Returns the protocol compatibility version that this tag requires. + pub fn requires_version(&self) -> ProtocolVersion { + ProtocolVersion::V1 + } +} +impl fmt::Display for ExtXVersion { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{}", Self::PREFIX, self.version) + } +} +impl FromStr for ExtXVersion { + type Err = Error; + fn from_str(s: &str) -> Result { + track_assert!(s.starts_with(Self::PREFIX), ErrorKind::InvalidInput); + let suffix = s.split_at(Self::PREFIX.len()).1; + let version = track!(suffix.parse())?; + Ok(ExtXVersion { version }) + } +} + +#[cfg(test)] +mod test { + use version::ProtocolVersion; + use super::*; + + #[test] + fn extm3u() { + assert_eq!("#EXTM3U".parse::().ok(), Some(ExtM3u)); + assert_eq!(ExtM3u.to_string(), "#EXTM3U"); + assert_eq!(ExtM3u.requires_version(), ProtocolVersion::V1); + } + + #[test] + fn ext_x_version() { + let tag = ExtXVersion::new(ProtocolVersion::V6); + assert_eq!("#EXT-X-VERSION::6".parse::().ok(), Some(tag)); + assert_eq!(tag.to_string(), "#EXT-X-VERSION:6"); + assert_eq!(tag.version(), ProtocolVersion::V6); + assert_eq!(tag.requires_version(), ProtocolVersion::V1); + } +} diff --git a/src/tag.rs b/src/tag/mod.rs similarity index 95% rename from src/tag.rs rename to src/tag/mod.rs index b21c7f8..b0bde66 100644 --- a/src/tag.rs +++ b/src/tag/mod.rs @@ -1,3 +1,6 @@ +//! [4.3. Playlist Tags] +//! +//! [4.3. Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3 use std::fmt; use std::str::FromStr; use std::time::Duration; @@ -15,15 +18,32 @@ macro_rules! may_invalid { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TagKind { - Basic, - MediaSegment, - MediaPlaylist, - MasterPlaylist, - MediaOrMasterPlaylist, +macro_rules! impl_from { + ($to:ident, $from:ident) => { + impl From<$from> for $to { + fn from(f: $from) -> Self { + $to::$from(f) + } + } + } } +pub use self::basic::{ExtM3u, ExtXVersion}; + +mod basic; + +/// [4.3.1. Basic Tags] +/// +/// [4.3.1. Basic Tags]: https://tools.ietf.org/html/rfc8216#section-4.3.1 +#[allow(missing_docs)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum BasicTag { + ExtM3u(ExtM3u), + ExtXVersion(ExtXVersion), +} +impl_from!(BasicTag, ExtM3u); +impl_from!(BasicTag, ExtXVersion); + #[derive(Debug, Clone, PartialEq, Eq)] pub enum MediaSegmentTag { ExtInf(ExtInf), @@ -159,32 +179,6 @@ pub enum Tag { ExtXIndependentSegments(ExtXIndependentSegments), ExtXStart(ExtXStart), } -impl Tag { - pub fn kind(&self) -> TagKind { - match *self { - Tag::ExtM3u(_) | Tag::ExtXVersion(_) => TagKind::Basic, - Tag::ExtInf(_) - | Tag::ExtXByteRange(_) - | Tag::ExtXDiscontinuity(_) - | Tag::ExtXKey(_) - | Tag::ExtXMap(_) - | Tag::ExtXProgramDateTime(_) - | Tag::ExtXDateRange(_) => TagKind::MediaSegment, - Tag::ExtXTargetDuration(_) - | Tag::ExtXMediaSequence(_) - | Tag::ExtXDiscontinuitySequence(_) - | Tag::ExtXEndList(_) - | Tag::ExtXPlaylistType(_) - | Tag::ExtXIFramesOnly(_) => TagKind::MediaPlaylist, - Tag::ExtXMedia(_) - | Tag::ExtXStreamInf(_) - | Tag::ExtXIFrameStreamInf(_) - | Tag::ExtXSessionData(_) - | Tag::ExtXSessionKey(_) => TagKind::MasterPlaylist, - Tag::ExtXIndependentSegments(_) | Tag::ExtXStart(_) => TagKind::MediaOrMasterPlaylist, - } - } -} impl fmt::Display for Tag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -267,56 +261,6 @@ impl FromStr for Tag { } } -// TODO: MediaSegmentTag - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExtM3u; -impl ExtM3u { - const PREFIX: &'static str = "#EXTM3U"; -} -impl fmt::Display for ExtM3u { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Self::PREFIX.fmt(f) - } -} -impl FromStr for ExtM3u { - type Err = Error; - fn from_str(s: &str) -> Result { - track_assert_eq!(s, Self::PREFIX, ErrorKind::InvalidInput); - Ok(ExtM3u) - } -} - -// TODO: A Playlist file MUST NOT contain more than one EXT-X-VERSION tag -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExtXVersion { - version: ProtocolVersion, -} -impl ExtXVersion { - const PREFIX: &'static str = "#EXT-X-VERSION:"; - - pub fn new(version: ProtocolVersion) -> Self { - ExtXVersion { version } - } - pub fn value(&self) -> ProtocolVersion { - self.version - } -} -impl fmt::Display for ExtXVersion { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{}", Self::PREFIX, self.version) - } -} -impl FromStr for ExtXVersion { - type Err = Error; - fn from_str(s: &str) -> Result { - track_assert!(s.starts_with(Self::PREFIX), ErrorKind::InvalidInput); - let suffix = s.split_at(Self::PREFIX.len()).1; - let version = track!(suffix.parse())?; - Ok(ExtXVersion { version }) - } -} - // TODO: This tag is REQUIRED for each Media Segment // TODO: if the compatibility version number is less than 3, durations MUST be integers. #[derive(Debug, Clone, PartialEq, Eq)]