1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-05-18 16:28:20 +00:00

remove unnecessary allocations

This commit is contained in:
Luro02 2020-02-06 12:27:48 +01:00
parent aae3809545
commit 1b0eb56224
No known key found for this signature in database
GPG key ID: B66FD4F74501A9CF
10 changed files with 59 additions and 134 deletions

View file

@ -1,3 +1,4 @@
use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;
@ -12,7 +13,7 @@ pub(crate) struct Lines<'a> {
}
impl<'a> Iterator for Lines<'a> {
type Item = crate::Result<Line>;
type Item = crate::Result<Line<'a>>;
fn next(&mut self) -> Option<Self::Item> {
let mut stream_inf = false;
@ -32,10 +33,7 @@ impl<'a> Iterator for Lines<'a> {
continue;
} else if line.starts_with("#EXT") {
match line.parse() {
Ok(value) => return Some(Ok(Line::Tag(value))),
Err(e) => return Some(Err(e)),
}
return Some(Tag::try_from(line).map(Line::Tag));
} else if line.starts_with('#') {
continue; // ignore comments
} else {
@ -44,17 +42,15 @@ impl<'a> Iterator for Lines<'a> {
stream_inf = false;
if let Some(first_line) = stream_inf_line {
match format!("{}\n{}", first_line, line).parse() {
Ok(value) => {
return Some(Ok(Line::Tag(value)));
}
Err(e) => return Some(Err(e)),
}
return Some(
tags::ExtXStreamInf::from_str(&format!("{}\n{}", first_line, line))
.map(|v| Line::Tag(Tag::ExtXStreamInf(v))),
);
} else {
continue;
}
} else {
return Some(Ok(Line::Uri(line.to_string())));
return Some(Ok(Line::Uri(line)));
}
}
}
@ -73,15 +69,14 @@ impl<'a> From<&'a str> for Lines<'a> {
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum Line {
Tag(Tag),
Uri(String),
pub(crate) enum Line<'a> {
Tag(Tag<'a>),
Uri(&'a str),
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum Tag {
ExtM3u(tags::ExtM3u),
pub(crate) enum Tag<'a> {
ExtXVersion(tags::ExtXVersion),
ExtInf(tags::ExtInf),
ExtXByteRange(tags::ExtXByteRange),
@ -103,13 +98,12 @@ pub(crate) enum Tag {
ExtXSessionKey(tags::ExtXSessionKey),
ExtXIndependentSegments(tags::ExtXIndependentSegments),
ExtXStart(tags::ExtXStart),
Unknown(String),
Unknown(&'a str),
}
impl fmt::Display for Tag {
impl<'a> fmt::Display for Tag<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
Self::ExtM3u(value) => value.fmt(f),
Self::ExtXVersion(value) => value.fmt(f),
Self::ExtInf(value) => value.fmt(f),
Self::ExtXByteRange(value) => value.fmt(f),
@ -136,13 +130,11 @@ impl fmt::Display for Tag {
}
}
impl FromStr for Tag {
type Err = Error;
impl<'a> TryFrom<&'a str> for Tag<'a> {
type Error = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
if input.starts_with(tags::ExtM3u::PREFIX) {
input.parse().map(Self::ExtM3u)
} else if input.starts_with(tags::ExtXVersion::PREFIX) {
fn try_from(input: &'a str) -> Result<Self, Self::Error> {
if input.starts_with(tags::ExtXVersion::PREFIX) {
input.parse().map(Self::ExtXVersion)
} else if input.starts_with(tags::ExtInf::PREFIX) {
input.parse().map(Self::ExtInf)
@ -185,7 +177,7 @@ impl FromStr for Tag {
} else if input.starts_with(tags::ExtXStart::PREFIX) {
input.parse().map(Self::ExtXStart)
} else {
Ok(Self::Unknown(input.to_string()))
Ok(Self::Unknown(input))
}
}
}

View file

@ -11,6 +11,7 @@ use crate::tags::{
ExtXSessionKey, ExtXStart, ExtXStreamInf, ExtXVersion,
};
use crate::types::{ClosedCaptions, MediaType, ProtocolVersion};
use crate::utils::tag;
use crate::{Error, RequiredVersion};
/// Master playlist.
@ -263,6 +264,7 @@ impl FromStr for MasterPlaylist {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let input = tag(input, ExtM3u::PREFIX)?;
let mut builder = Self::builder();
let mut media_tags = vec![];
@ -272,23 +274,15 @@ impl FromStr for MasterPlaylist {
let mut session_key_tags = vec![];
let mut unknown_tags = vec![];
for (i, line) in Lines::from(input).enumerate() {
for line in Lines::from(input) {
match line? {
Line::Tag(tag) => {
if i == 0 {
if tag != Tag::ExtM3u(ExtM3u) {
return Err(Error::invalid_input());
}
continue;
}
match tag {
Tag::ExtM3u(_) => {
return Err(Error::invalid_input());
}
Tag::ExtXVersion(_) => {
// This tag can be ignored, because the
// MasterPlaylist will automatically set the
// ExtXVersion tag to correct version!
// ExtXVersion tag to the minimum required version
// TODO: this might be verified?
}
Tag::ExtInf(_)
| Tag::ExtXByteRange(_)

View file

@ -12,6 +12,7 @@ use crate::tags::{
ExtXMediaSequence, ExtXPlaylistType, ExtXStart, ExtXTargetDuration, ExtXVersion,
};
use crate::types::ProtocolVersion;
use crate::utils::tag;
use crate::{Encrypted, Error, RequiredVersion};
/// Media playlist.
@ -276,6 +277,8 @@ fn parse_media_playlist(
input: &str,
builder: &mut MediaPlaylistBuilder,
) -> crate::Result<MediaPlaylist> {
let input = tag(input, "#EXTM3U")?;
let mut segment = MediaSegment::builder();
let mut segments = vec![];
@ -285,17 +288,10 @@ fn parse_media_playlist(
let mut available_key_tags: Vec<crate::tags::ExtXKey> = vec![];
for (i, line) in Lines::from(input).enumerate() {
for line in Lines::from(input) {
match line? {
Line::Tag(tag) => {
if i == 0 {
if tag != Tag::ExtM3u(ExtM3u) {
return Err(Error::custom("m3u8 doesn't start with #EXTM3U"));
}
continue;
}
match tag {
Tag::ExtM3u(_) => return Err(Error::invalid_input()),
Tag::ExtInf(t) => {
has_partial_segment = true;
segment.inf_tag(t);

View file

@ -11,31 +11,12 @@ use crate::{Error, RequiredVersion};
/// Playlist file.
/// It is the at the start of every [`Media Playlist`] and [`Master Playlist`].
///
/// # Examples
///
/// Parsing from a [`str`]:
///
/// ```
/// # use hls_m3u8::tags::ExtM3u;
/// #
/// assert_eq!("#EXTM3U".parse::<ExtM3u>()?, ExtM3u);
/// # Ok::<(), Box<dyn ::std::error::Error>>(())
/// ```
///
/// Converting to a [`str`]:
///
/// ```
/// # use hls_m3u8::tags::ExtM3u;
/// #
/// assert_eq!("#EXTM3U".to_string(), ExtM3u.to_string());
/// ```
///
/// [`Media Playlist`]: crate::MediaPlaylist
/// [`Master Playlist`]: crate::MasterPlaylist
/// [`M3U`]: https://en.wikipedia.org/wiki/M3U
/// [4.3.1.1. EXTM3U]: https://tools.ietf.org/html/rfc8216#section-4.3.1.1
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct ExtM3u;
pub(crate) struct ExtM3u;
impl ExtM3u {
pub(crate) const PREFIX: &'static str = "#EXTM3U";

View file

@ -1,5 +1,5 @@
mod m3u;
mod version;
pub use m3u::*;
pub(crate) use m3u::*;
pub use version::*;

View file

@ -66,23 +66,7 @@ impl FromStr for ExtXByteRange {
fn from_str(input: &str) -> Result<Self, Self::Err> {
let input = tag(input, Self::PREFIX)?;
let tokens = input.splitn(2, '@').collect::<Vec<_>>();
if tokens.is_empty() {
return Err(Error::invalid_input());
}
let length = tokens[0].parse()?;
let start = {
if tokens.len() == 2 {
Some(tokens[1].parse()?)
} else {
None
}
};
Ok(Self::new(length, start))
Ok(Self(ByteRange::from_str(input)?))
}
}

View file

@ -151,29 +151,14 @@ impl FromStr for ExtInf {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let input = tag(input, Self::PREFIX)?;
let tokens = input.splitn(2, ',').collect::<Vec<_>>();
let mut input = tag(input, Self::PREFIX)?.splitn(2, ',');
if tokens.is_empty() {
return Err(Error::custom(format!(
"failed to parse #EXTINF tag, couldn't split input: {:?}",
input
)));
}
let duration = Duration::from_secs_f64(tokens[0].parse()?);
let title = {
if tokens.len() >= 2 {
if tokens[1].trim().is_empty() {
None
} else {
Some(tokens[1].to_string())
}
} else {
None
}
};
let duration = Duration::from_secs_f64(input.next().unwrap().parse()?);
let title = input
.next()
.map(|value| value.trim())
.filter(|value| !value.is_empty())
.map(|value| value.to_string());
Ok(Self { duration, title })
}

View file

@ -74,22 +74,15 @@ impl fmt::Display for ByteRange {
impl FromStr for ByteRange {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let tokens = s.splitn(2, '@').collect::<Vec<_>>();
fn from_str(input: &str) -> Result<Self, Self::Err> {
let mut input = input.splitn(2, '@');
if tokens.is_empty() {
return Err(Error::invalid_input());
}
let length = input
.next()
.ok_or_else(|| Error::custom("missing length for #EXT-X-BYTERANGE"))
.and_then(|s| s.parse().map_err(Error::parse_int))?;
let length = tokens[0].parse()?;
let start = {
if tokens.len() == 2 {
Some(tokens[1].parse()?)
} else {
None
}
};
let start = input.next().map(str::parse).transpose()?;
Ok(Self::new(length, start))
}

View file

@ -83,17 +83,17 @@ impl FromStr for Channels {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let parameters = input.split('/').collect::<Vec<_>>();
let mut parameters = input.split('/');
let channel_number = parameters
.first()
.next()
.ok_or_else(|| Error::missing_attribute("first parameter of channels"))?
.parse()
.map_err(Error::parse_int)?;
Ok(Self {
channel_number,
unknown: parameters[1..].iter().map(|v| v.to_string()).collect(),
unknown: parameters.map(|v| (*v).to_string()).collect(),
})
}
}

View file

@ -36,19 +36,19 @@ impl FromStr for Resolution {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let tokens = input.splitn(2, 'x').collect::<Vec<_>>();
let mut input = input.splitn(2, 'x');
if tokens.len() != 2 {
return Err(Error::custom(format!(
"InvalidInput: Expected input format: [width]x[height] (ex. 1920x1080), got {:?}",
input,
)));
}
let width = input
.next()
.ok_or_else(|| Error::custom("missing width for `Resolution` or an invalid input"))
.and_then(|v| v.parse().map_err(Error::parse_int))?;
Ok(Self {
width: tokens[0].parse().map_err(Error::parse_int)?,
height: tokens[1].parse().map_err(Error::parse_int)?,
})
let height = input
.next()
.ok_or_else(|| Error::custom("missing height for `Resolution` or an invalid input"))
.and_then(|v| v.parse().map_err(Error::parse_int))?;
Ok(Self { width, height })
}
}