mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-12-23 20:40:29 +00:00
Refactor line
module
This commit is contained in:
parent
32b262713e
commit
0fdcf41732
6 changed files with 146 additions and 163 deletions
161
src/line.rs
161
src/line.rs
|
@ -1,19 +1,10 @@
|
||||||
use {ErrorKind, Result};
|
use std::fmt;
|
||||||
use tag::Tag;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use {Error, ErrorKind, Result};
|
||||||
|
use tag;
|
||||||
|
use types::SingleLineString;
|
||||||
|
|
||||||
// [rfc8216#section-4.1]
|
|
||||||
// > Playlist files MUST be encoded in UTF-8 [RFC3629]. They MUST NOT
|
|
||||||
// > contain any Byte Order Mark (BOM); clients SHOULD fail to parse
|
|
||||||
// > Playlists that contain a BOM or do not parse as UTF-8. Playlist
|
|
||||||
// > files MUST NOT contain UTF-8 control characters (U+0000 to U+001F and
|
|
||||||
// > U+007F to U+009F), with the exceptions of CR (U+000D) and LF
|
|
||||||
// > (U+000A). All character sequences MUST be normalized according to
|
|
||||||
// > Unicode normalization form "NFC" [UNICODE]. Note that US-ASCII
|
|
||||||
// > [US_ASCII] conforms to these rules.
|
|
||||||
// >
|
|
||||||
// > Lines in a Playlist file are terminated by either a single line feed
|
|
||||||
// > character or a carriage return character followed by a line feed
|
|
||||||
// > character.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Lines<'a> {
|
pub struct Lines<'a> {
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
|
@ -27,9 +18,17 @@ impl<'a> Lines<'a> {
|
||||||
let mut end = self.input.len();
|
let mut end = self.input.len();
|
||||||
let mut next_start = self.input.len();
|
let mut next_start = self.input.len();
|
||||||
let mut adjust = 0;
|
let mut adjust = 0;
|
||||||
|
let mut next_line_of_ext_x_stream_inf = false;
|
||||||
for (i, c) in self.input.char_indices() {
|
for (i, c) in self.input.char_indices() {
|
||||||
match c {
|
match c {
|
||||||
'\n' => {
|
'\n' => {
|
||||||
|
if !next_line_of_ext_x_stream_inf
|
||||||
|
&& self.input.starts_with(tag::ExtXStreamInf::PREFIX)
|
||||||
|
{
|
||||||
|
next_line_of_ext_x_stream_inf = true;
|
||||||
|
adjust = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
next_start = i + 1;
|
next_start = i + 1;
|
||||||
end = i - adjust;
|
end = i - adjust;
|
||||||
break;
|
break;
|
||||||
|
@ -37,10 +36,8 @@ impl<'a> Lines<'a> {
|
||||||
'\r' => {
|
'\r' => {
|
||||||
adjust = 1;
|
adjust = 1;
|
||||||
}
|
}
|
||||||
'\u{00}'...'\u{1F}' | '\u{7F}'...'\u{9f}' => {
|
|
||||||
track_panic!(ErrorKind::InvalidInput);
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
|
track_assert!(!c.is_control(), ErrorKind::InvalidInput);
|
||||||
adjust = 0;
|
adjust = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +50,8 @@ impl<'a> Lines<'a> {
|
||||||
} else if raw_line.starts_with("#") {
|
} else if raw_line.starts_with("#") {
|
||||||
Line::Comment(raw_line)
|
Line::Comment(raw_line)
|
||||||
} else {
|
} else {
|
||||||
Line::Uri(raw_line)
|
let uri = track!(SingleLineString::new(raw_line))?;
|
||||||
|
Line::Uri(uri)
|
||||||
};
|
};
|
||||||
self.input = &self.input[next_start..];
|
self.input = &self.input[next_start..];
|
||||||
Ok(line)
|
Ok(line)
|
||||||
|
@ -77,22 +75,113 @@ pub enum Line<'a> {
|
||||||
Blank,
|
Blank,
|
||||||
Comment(&'a str),
|
Comment(&'a str),
|
||||||
Tag(Tag),
|
Tag(Tag),
|
||||||
|
Uri(SingleLineString),
|
||||||
// TODO:
|
|
||||||
Uri(&'a str),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
// #[cfg(test)]
|
pub enum Tag {
|
||||||
// mod test {
|
ExtM3u(tag::ExtM3u),
|
||||||
// use super::*;
|
ExtXVersion(tag::ExtXVersion),
|
||||||
|
ExtInf(tag::ExtInf),
|
||||||
// #[test]
|
ExtXByteRange(tag::ExtXByteRange),
|
||||||
// fn it_works() {
|
ExtXDiscontinuity(tag::ExtXDiscontinuity),
|
||||||
// let mut lines = Lines::new("foo\nbar\r\nbaz");
|
ExtXKey(tag::ExtXKey),
|
||||||
// assert_eq!(lines.next().and_then(|x| x.ok()), Some("foo"));
|
ExtXMap(tag::ExtXMap),
|
||||||
// assert_eq!(lines.next().and_then(|x| x.ok()), Some("bar"));
|
ExtXProgramDateTime(tag::ExtXProgramDateTime),
|
||||||
// assert_eq!(lines.next().and_then(|x| x.ok()), Some("baz"));
|
ExtXDateRange(tag::ExtXDateRange),
|
||||||
// assert_eq!(lines.next().and_then(|x| x.ok()), None);
|
ExtXTargetDuration(tag::ExtXTargetDuration),
|
||||||
// }
|
ExtXMediaSequence(tag::ExtXMediaSequence),
|
||||||
// }
|
ExtXDiscontinuitySequence(tag::ExtXDiscontinuitySequence),
|
||||||
|
ExtXEndList(tag::ExtXEndList),
|
||||||
|
ExtXPlaylistType(tag::ExtXPlaylistType),
|
||||||
|
ExtXIFramesOnly(tag::ExtXIFramesOnly),
|
||||||
|
ExtXMedia(tag::ExtXMedia),
|
||||||
|
ExtXStreamInf(tag::ExtXStreamInf),
|
||||||
|
ExtXIFrameStreamInf(tag::ExtXIFrameStreamInf),
|
||||||
|
ExtXSessionData(tag::ExtXSessionData),
|
||||||
|
ExtXSessionKey(tag::ExtXSessionKey),
|
||||||
|
ExtXIndependentSegments(tag::ExtXIndependentSegments),
|
||||||
|
ExtXStart(tag::ExtXStart),
|
||||||
|
Unknown(SingleLineString),
|
||||||
|
}
|
||||||
|
impl fmt::Display for Tag {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Tag::ExtM3u(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXVersion(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtInf(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXByteRange(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXDiscontinuity(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXKey(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXMap(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXProgramDateTime(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXDateRange(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXTargetDuration(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXMediaSequence(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXDiscontinuitySequence(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXEndList(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXPlaylistType(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXIFramesOnly(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXMedia(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXStreamInf(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXIFrameStreamInf(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXSessionData(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXSessionKey(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXIndependentSegments(ref t) => t.fmt(f),
|
||||||
|
Tag::ExtXStart(ref t) => t.fmt(f),
|
||||||
|
Tag::Unknown(ref t) => t.fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromStr for Tag {
|
||||||
|
type Err = Error;
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
if s.starts_with(tag::ExtM3u::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtM3u))
|
||||||
|
} else if s.starts_with(tag::ExtXVersion::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXVersion))
|
||||||
|
} else if s.starts_with(tag::ExtInf::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtInf))
|
||||||
|
} else if s.starts_with(tag::ExtXByteRange::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXByteRange))
|
||||||
|
} else if s.starts_with(tag::ExtXDiscontinuity::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXDiscontinuity))
|
||||||
|
} else if s.starts_with(tag::ExtXKey::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXKey))
|
||||||
|
} else if s.starts_with(tag::ExtXMap::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXMap))
|
||||||
|
} else if s.starts_with(tag::ExtXProgramDateTime::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXProgramDateTime))
|
||||||
|
} else if s.starts_with(tag::ExtXTargetDuration::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXTargetDuration))
|
||||||
|
} else if s.starts_with(tag::ExtXDateRange::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXDateRange))
|
||||||
|
} else if s.starts_with(tag::ExtXMediaSequence::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXMediaSequence))
|
||||||
|
} else if s.starts_with(tag::ExtXDiscontinuitySequence::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXDiscontinuitySequence))
|
||||||
|
} else if s.starts_with(tag::ExtXEndList::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXEndList))
|
||||||
|
} else if s.starts_with(tag::ExtXPlaylistType::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXPlaylistType))
|
||||||
|
} else if s.starts_with(tag::ExtXIFramesOnly::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXIFramesOnly))
|
||||||
|
} else if s.starts_with(tag::ExtXMedia::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXMedia))
|
||||||
|
} else if s.starts_with(tag::ExtXStreamInf::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXStreamInf))
|
||||||
|
} else if s.starts_with(tag::ExtXIFrameStreamInf::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXIFrameStreamInf))
|
||||||
|
} else if s.starts_with(tag::ExtXSessionData::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXSessionData))
|
||||||
|
} else if s.starts_with(tag::ExtXSessionKey::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXSessionKey))
|
||||||
|
} else if s.starts_with(tag::ExtXIndependentSegments::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXIndependentSegments))
|
||||||
|
} else if s.starts_with(tag::ExtXStart::PREFIX) {
|
||||||
|
track!(s.parse().map(Tag::ExtXStart))
|
||||||
|
} else {
|
||||||
|
track!(SingleLineString::new(s)).map(Tag::Unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use {Error, ErrorKind, Result};
|
use {Error, ErrorKind, Result};
|
||||||
use line::{Line, Lines};
|
use line::{Line, Lines, Tag};
|
||||||
use tag::{ExtM3u, ExtXIFrameStreamInf, ExtXIndependentSegments, ExtXMedia, ExtXSessionData,
|
use tag::{ExtM3u, ExtXIFrameStreamInf, ExtXIndependentSegments, ExtXMedia, ExtXSessionData,
|
||||||
ExtXSessionKey, ExtXStart, ExtXStreamInf, ExtXVersion, Tag};
|
ExtXSessionKey, ExtXStart, ExtXStreamInf, ExtXVersion};
|
||||||
use types::ProtocolVersion;
|
use types::ProtocolVersion;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -132,16 +132,14 @@ impl FromStr for MasterPlaylist {
|
||||||
track_assert_eq!(start, None, ErrorKind::InvalidInput);
|
track_assert_eq!(start, None, ErrorKind::InvalidInput);
|
||||||
start = Some(t);
|
start = Some(t);
|
||||||
}
|
}
|
||||||
|
Tag::Unknown(_) => {
|
||||||
|
// [6.3.1. General Client Responsibilities]
|
||||||
|
// > ignore any unrecognized tags.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Line::Uri(uri) => {
|
Line::Uri(uri) => {
|
||||||
let (line, inf) = track_assert_some!(last_stream_inf, ErrorKind::InvalidInput);
|
track_panic!(ErrorKind::InvalidInput, "Unexpected URI: {:?}", uri);
|
||||||
track_assert_eq!(line + 1, i, ErrorKind::InvalidInput);
|
|
||||||
stream_infs.push(ExtXStreamInfWithUri {
|
|
||||||
inf,
|
|
||||||
uri: uri.to_owned(),
|
|
||||||
});
|
|
||||||
last_stream_inf = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@ use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use {Error, ErrorKind, Result};
|
use {Error, ErrorKind, Result};
|
||||||
use line::{Line, Lines};
|
use line::{Line, Lines, Tag};
|
||||||
use media_segment::{MediaSegment, MediaSegmentBuilder};
|
use media_segment::{MediaSegment, MediaSegmentBuilder};
|
||||||
use tag::{ExtM3u, ExtXDiscontinuitySequence, ExtXEndList, ExtXIFramesOnly,
|
use tag::{ExtM3u, ExtXDiscontinuitySequence, ExtXEndList, ExtXIFramesOnly,
|
||||||
ExtXIndependentSegments, ExtXMediaSequence, ExtXPlaylistType, ExtXStart,
|
ExtXIndependentSegments, ExtXMediaSequence, ExtXPlaylistType, ExtXStart,
|
||||||
ExtXTargetDuration, ExtXVersion, Tag};
|
ExtXTargetDuration, ExtXVersion};
|
||||||
use types::ProtocolVersion;
|
use types::ProtocolVersion;
|
||||||
|
|
||||||
// TODO: There MUST NOT be more than one Media Playlist tag of each type in any Media Playlist.
|
// TODO: There MUST NOT be more than one Media Playlist tag of each type in any Media Playlist.
|
||||||
|
@ -167,10 +167,14 @@ impl FromStr for MediaPlaylist {
|
||||||
track_assert_eq!(start, None, ErrorKind::InvalidInput);
|
track_assert_eq!(start, None, ErrorKind::InvalidInput);
|
||||||
start = Some(t);
|
start = Some(t);
|
||||||
}
|
}
|
||||||
|
Tag::Unknown(_) => {
|
||||||
|
// [6.3.1. General Client Responsibilities]
|
||||||
|
// > ignore any unrecognized tags.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Line::Uri(uri) => {
|
Line::Uri(uri) => {
|
||||||
segment.uri(uri.to_owned());
|
segment.uri(uri);
|
||||||
segments.push(track!(segment.finish())?);
|
segments.push(track!(segment.finish())?);
|
||||||
segment = MediaSegmentBuilder::new();
|
segment = MediaSegmentBuilder::new();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,11 @@ use std::iter;
|
||||||
use {ErrorKind, Result};
|
use {ErrorKind, Result};
|
||||||
use tag::{ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey, ExtXMap,
|
use tag::{ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey, ExtXMap,
|
||||||
ExtXProgramDateTime, MediaSegmentTag};
|
ExtXProgramDateTime, MediaSegmentTag};
|
||||||
|
use types::SingleLineString;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MediaSegmentBuilder {
|
pub struct MediaSegmentBuilder {
|
||||||
uri: Option<String>,
|
uri: Option<SingleLineString>,
|
||||||
ext_inf: Option<ExtInf>,
|
ext_inf: Option<ExtInf>,
|
||||||
ext_x_byterange: Option<ExtXByteRange>,
|
ext_x_byterange: Option<ExtXByteRange>,
|
||||||
ext_x_daterange: Option<ExtXDateRange>,
|
ext_x_daterange: Option<ExtXDateRange>,
|
||||||
|
@ -29,7 +30,7 @@ impl MediaSegmentBuilder {
|
||||||
ext_x_program_date_time: None,
|
ext_x_program_date_time: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn uri(&mut self, uri: String) -> &mut Self {
|
pub fn uri(&mut self, uri: SingleLineString) -> &mut Self {
|
||||||
self.uri = Some(uri);
|
self.uri = Some(uri);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ impl MediaSegmentBuilder {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MediaSegment {
|
pub struct MediaSegment {
|
||||||
pub uri: String, // TODO
|
pub uri: SingleLineString,
|
||||||
pub ext_inf: ExtInf,
|
pub ext_inf: ExtInf,
|
||||||
pub tags: Vec<MediaSegmentTag>,
|
pub tags: Vec<MediaSegmentTag>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -368,8 +368,8 @@ impl fmt::Display for ExtXStreamInf {
|
||||||
impl FromStr for ExtXStreamInf {
|
impl FromStr for ExtXStreamInf {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
let mut lines = s.splitn(2, '\n'); // TODO:
|
let mut lines = s.splitn(2, '\n');
|
||||||
let first_line = lines.next().expect("Never fails");
|
let first_line = lines.next().expect("Never fails").trim_right_matches('\r');
|
||||||
let second_line = track_assert_some!(lines.next(), ErrorKind::InvalidInput);
|
let second_line = track_assert_some!(lines.next(), ErrorKind::InvalidInput);
|
||||||
|
|
||||||
track_assert!(
|
track_assert!(
|
||||||
|
|
111
src/tag/mod.rs
111
src/tag/mod.rs
|
@ -2,10 +2,9 @@
|
||||||
//!
|
//!
|
||||||
//! [4.3. Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3
|
//! [4.3. Playlist Tags]: https://tools.ietf.org/html/rfc8216#section-4.3
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
|
||||||
use trackable::error::ErrorKindExt;
|
use trackable::error::ErrorKindExt;
|
||||||
|
|
||||||
use {Error, ErrorKind, Result};
|
use {ErrorKind, Result};
|
||||||
|
|
||||||
macro_rules! may_invalid {
|
macro_rules! may_invalid {
|
||||||
($expr:expr) => {
|
($expr:expr) => {
|
||||||
|
@ -123,114 +122,6 @@ impl_from!(MediaSegmentTag, ExtXKey);
|
||||||
impl_from!(MediaSegmentTag, ExtXMap);
|
impl_from!(MediaSegmentTag, ExtXMap);
|
||||||
impl_from!(MediaSegmentTag, ExtXProgramDateTime);
|
impl_from!(MediaSegmentTag, ExtXProgramDateTime);
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Tag {
|
|
||||||
ExtM3u(ExtM3u),
|
|
||||||
ExtXVersion(ExtXVersion),
|
|
||||||
ExtInf(ExtInf),
|
|
||||||
ExtXByteRange(ExtXByteRange),
|
|
||||||
ExtXDiscontinuity(ExtXDiscontinuity),
|
|
||||||
ExtXKey(ExtXKey),
|
|
||||||
ExtXMap(ExtXMap),
|
|
||||||
ExtXProgramDateTime(ExtXProgramDateTime),
|
|
||||||
ExtXDateRange(ExtXDateRange),
|
|
||||||
ExtXTargetDuration(ExtXTargetDuration),
|
|
||||||
ExtXMediaSequence(ExtXMediaSequence),
|
|
||||||
ExtXDiscontinuitySequence(ExtXDiscontinuitySequence),
|
|
||||||
ExtXEndList(ExtXEndList),
|
|
||||||
ExtXPlaylistType(ExtXPlaylistType),
|
|
||||||
ExtXIFramesOnly(ExtXIFramesOnly),
|
|
||||||
ExtXMedia(ExtXMedia),
|
|
||||||
ExtXStreamInf(ExtXStreamInf),
|
|
||||||
ExtXIFrameStreamInf(ExtXIFrameStreamInf),
|
|
||||||
ExtXSessionData(ExtXSessionData),
|
|
||||||
ExtXSessionKey(ExtXSessionKey),
|
|
||||||
ExtXIndependentSegments(ExtXIndependentSegments),
|
|
||||||
ExtXStart(ExtXStart),
|
|
||||||
}
|
|
||||||
impl fmt::Display for Tag {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Tag::ExtM3u(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXVersion(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtInf(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXByteRange(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXDiscontinuity(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXKey(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXMap(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXProgramDateTime(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXDateRange(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXTargetDuration(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXMediaSequence(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXDiscontinuitySequence(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXEndList(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXPlaylistType(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXIFramesOnly(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXMedia(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXStreamInf(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXIFrameStreamInf(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXSessionData(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXSessionKey(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXIndependentSegments(ref t) => t.fmt(f),
|
|
||||||
Tag::ExtXStart(ref t) => t.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FromStr for Tag {
|
|
||||||
type Err = Error;
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
|
||||||
if s.starts_with(ExtM3u::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtM3u))
|
|
||||||
} else if s.starts_with(ExtXVersion::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXVersion))
|
|
||||||
} else if s.starts_with(ExtInf::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtInf))
|
|
||||||
} else if s.starts_with(ExtXByteRange::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXByteRange))
|
|
||||||
} else if s.starts_with(ExtXDiscontinuity::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXDiscontinuity))
|
|
||||||
} else if s.starts_with(ExtXKey::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXKey))
|
|
||||||
} else if s.starts_with(ExtXMap::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXMap))
|
|
||||||
} else if s.starts_with(ExtXProgramDateTime::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXProgramDateTime))
|
|
||||||
} else if s.starts_with(ExtXTargetDuration::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXTargetDuration))
|
|
||||||
} else if s.starts_with(ExtXDateRange::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXDateRange))
|
|
||||||
} else if s.starts_with(ExtXMediaSequence::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXMediaSequence))
|
|
||||||
} else if s.starts_with(ExtXDiscontinuitySequence::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXDiscontinuitySequence))
|
|
||||||
} else if s.starts_with(ExtXEndList::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXEndList))
|
|
||||||
} else if s.starts_with(ExtXPlaylistType::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXPlaylistType))
|
|
||||||
} else if s.starts_with(ExtXIFramesOnly::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXIFramesOnly))
|
|
||||||
} else if s.starts_with(ExtXMedia::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXMedia))
|
|
||||||
} else if s.starts_with(ExtXStreamInf::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXStreamInf))
|
|
||||||
} else if s.starts_with(ExtXIFrameStreamInf::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXIFrameStreamInf))
|
|
||||||
} else if s.starts_with(ExtXSessionData::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXSessionData))
|
|
||||||
} else if s.starts_with(ExtXSessionKey::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXSessionKey))
|
|
||||||
} else if s.starts_with(ExtXIndependentSegments::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXIndependentSegments))
|
|
||||||
} else if s.starts_with(ExtXStart::PREFIX) {
|
|
||||||
track!(s.parse().map(Tag::ExtXStart))
|
|
||||||
} else {
|
|
||||||
// TODO: ignore any unrecognized tags. (section-6.3.1)
|
|
||||||
track_panic!(ErrorKind::InvalidInput, "Unknown tag: {:?}", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_yes_or_no(s: &str) -> Result<bool> {
|
fn parse_yes_or_no(s: &str) -> Result<bool> {
|
||||||
match s {
|
match s {
|
||||||
"YES" => Ok(true),
|
"YES" => Ok(true),
|
||||||
|
|
Loading…
Reference in a new issue