1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2025-02-16 13:15:14 +00:00

replaced builder with derive_builder #14

This commit is contained in:
Luro02 2019-09-22 12:56:28 +02:00
parent 81f9a421fe
commit 3240417304

View file

@ -1,195 +1,87 @@
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use derive_builder::Builder;
use crate::attribute::AttributePairs; use crate::attribute::AttributePairs;
use crate::types::{InStreamId, MediaType, ProtocolVersion, RequiredVersion}; use crate::types::{InStreamId, MediaType, ProtocolVersion, RequiredVersion};
use crate::utils::{parse_yes_or_no, quote, tag, unquote}; use crate::utils::{parse_yes_or_no, quote, tag, unquote};
use crate::Error; use crate::Error;
/// `ExtXMedia` builder. /// [4.3.4.1. EXT-X-MEDIA]
#[derive(Debug, Clone)] ///
pub struct ExtXMediaBuilder { /// [4.3.4.1. EXT-X-MEDIA]: https://tools.ietf.org/html/rfc8216#section-4.3.4.1
media_type: Option<MediaType>, #[derive(Builder, Debug, Clone, PartialEq, Eq, Hash)]
#[builder(setter(into))]
#[builder(build_fn(validate = "Self::validate"))]
pub struct ExtXMedia {
/// Sets the media type of the rendition.
media_type: MediaType,
#[builder(setter(strip_option, into), default)]
/// Sets the URI that identifies the media playlist.
uri: Option<String>, uri: Option<String>,
group_id: Option<String>, /// Sets the identifier that specifies the group to which the rendition belongs.
group_id: String,
/// Sets the name of the primary language used in the rendition.
#[builder(setter(strip_option, into), default)]
language: Option<String>, language: Option<String>,
/// Sets the name of a language associated with the rendition.
#[builder(setter(strip_option, into), default)]
assoc_language: Option<String>, assoc_language: Option<String>,
name: Option<String>, /// Sets a human-readable description of the rendition.
default: bool, name: String,
autoselect: Option<bool>, /// Sets the value of the `default` flag.
forced: Option<bool>, #[builder(default)]
is_default: bool,
/// Sets the value of the `autoselect` flag.
#[builder(default)]
is_autoselect: bool,
/// Sets the value of the `forced` flag.
#[builder(default)]
is_forced: bool,
/// Sets the identifier that specifies a rendition within the segments in the media playlist.
#[builder(setter(strip_option, into), default)]
instream_id: Option<InStreamId>, instream_id: Option<InStreamId>,
/// Sets the string that represents uniform type identifiers (UTI).
#[builder(setter(strip_option, into), default)]
characteristics: Option<String>, characteristics: Option<String>,
/// Sets the string that represents the parameters of the rendition.
#[builder(setter(strip_option, into), default)]
channels: Option<String>, channels: Option<String>,
} }
impl ExtXMediaBuilder { impl ExtXMediaBuilder {
/// Makes a `ExtXMediaBuilder` instance. fn validate(&self) -> Result<(), String> {
pub const fn new() -> Self {
ExtXMediaBuilder {
media_type: None,
uri: None,
group_id: None,
language: None,
assoc_language: None,
name: None,
default: false,
autoselect: None,
forced: None,
instream_id: None,
characteristics: None,
channels: None,
}
}
/// Sets the media type of the rendition.
pub fn media_type(&mut self, media_type: MediaType) -> &mut Self {
self.media_type = Some(media_type);
self
}
/// Sets the identifier that specifies the group to which the rendition belongs.
pub fn group_id<T: ToString>(&mut self, group_id: T) -> &mut Self {
self.group_id = Some(group_id.to_string());
self
}
/// Sets a human-readable description of the rendition.
pub fn name<T: ToString>(&mut self, name: T) -> &mut Self {
self.name = Some(name.to_string());
self
}
/// Sets the URI that identifies the media playlist.
pub fn uri<T: ToString>(&mut self, uri: T) -> &mut Self {
self.uri = Some(uri.to_string());
self
}
/// Sets the name of the primary language used in the rendition.
pub fn language<T: ToString>(&mut self, language: T) -> &mut Self {
self.language = Some(language.to_string());
self
}
/// Sets the name of a language associated with the rendition.
pub fn assoc_language<T: ToString>(&mut self, language: T) -> &mut Self {
self.assoc_language = Some(language.to_string());
self
}
/// Sets the value of the `default` flag.
pub fn default(&mut self, b: bool) -> &mut Self {
self.default = b;
self
}
/// Sets the value of the `autoselect` flag.
pub fn autoselect(&mut self, b: bool) -> &mut Self {
self.autoselect = Some(b);
self
}
/// Sets the value of the `forced` flag.
pub fn forced(&mut self, b: bool) -> &mut Self {
self.forced = Some(b);
self
}
/// Sets the identifier that specifies a rendition within the segments in the media playlist.
pub fn instream_id(&mut self, id: InStreamId) -> &mut Self {
self.instream_id = Some(id);
self
}
/// Sets the string that represents uniform type identifiers (UTI).
pub fn characteristics<T: ToString>(&mut self, characteristics: T) -> &mut Self {
self.characteristics = Some(characteristics.to_string());
self
}
/// Sets the string that represents the parameters of the rendition.
pub fn channels<T: ToString>(&mut self, channels: T) -> &mut Self {
self.channels = Some(channels.to_string());
self
}
/// Builds a `ExtXMedia` instance.
pub fn finish(self) -> crate::Result<ExtXMedia> {
let media_type = self let media_type = self
.media_type .media_type
.ok_or(Error::missing_value("self.media_type"))?; .ok_or(Error::missing_value("self.media_type").to_string())?;
let group_id = self.group_id.ok_or(Error::missing_value("self.group_id"))?;
let name = self.name.ok_or(Error::missing_value("self.name"))?;
if MediaType::ClosedCaptions == media_type { if MediaType::ClosedCaptions == media_type {
if let None = self.uri { if let None = self.uri {
return Err(Error::missing_value("self.uri")); return Err(Error::missing_value("self.uri").to_string());
} }
self.instream_id self.instream_id
.ok_or(Error::missing_value("self.instream_id"))?; .ok_or(Error::missing_value("self.instream_id").to_string())?;
} else { } else {
if let Some(_) = &self.instream_id { if let Some(_) = &self.instream_id {
Err(Error::invalid_input())?; return Err(Error::invalid_input().to_string());
} }
} }
if self.default && self.autoselect.is_some() { if self.is_default.unwrap_or(false) && self.is_autoselect.unwrap_or(false) {
if let Some(value) = &self.autoselect { return Err(Error::invalid_input().to_string());
if *value {
Err(Error::invalid_input())?;
}
}
} }
if MediaType::Subtitles != media_type { if MediaType::Subtitles != media_type {
if self.forced.is_some() { if self.is_forced.is_some() {
Err(Error::invalid_input())?; return Err(Error::invalid_input().to_string());
} }
} }
Ok(ExtXMedia { Ok(())
media_type,
uri: self.uri,
group_id,
language: self.language,
assoc_language: self.assoc_language,
name,
default: self.default,
autoselect: self.autoselect.unwrap_or(false),
forced: self.forced.unwrap_or(false),
instream_id: self.instream_id,
characteristics: self.characteristics,
channels: self.channels,
})
} }
} }
impl Default for ExtXMediaBuilder {
fn default() -> Self {
Self::new()
}
}
/// [4.3.4.1. EXT-X-MEDIA]
///
/// [4.3.4.1. EXT-X-MEDIA]: https://tools.ietf.org/html/rfc8216#section-4.3.4.1
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExtXMedia {
media_type: MediaType,
uri: Option<String>,
group_id: String,
language: Option<String>,
assoc_language: Option<String>,
name: String,
default: bool,
autoselect: bool,
forced: bool,
instream_id: Option<InStreamId>,
characteristics: Option<String>,
channels: Option<String>,
}
impl ExtXMedia { impl ExtXMedia {
pub(crate) const PREFIX: &'static str = "#EXT-X-MEDIA:"; pub(crate) const PREFIX: &'static str = "#EXT-X-MEDIA:";
@ -202,15 +94,20 @@ impl ExtXMedia {
language: None, language: None,
assoc_language: None, assoc_language: None,
name: name.to_string(), name: name.to_string(),
default: false, is_default: false,
autoselect: false, is_autoselect: false,
forced: false, is_forced: false,
instream_id: None, instream_id: None,
characteristics: None, characteristics: None,
channels: None, channels: None,
} }
} }
/// Makes a [ExtXMediaBuilder] for [ExtXMedia].
pub fn builder() -> ExtXMediaBuilder {
ExtXMediaBuilder::default()
}
/// Returns the type of the media associated with this tag. /// Returns the type of the media associated with this tag.
pub const fn media_type(&self) -> MediaType { pub const fn media_type(&self) -> MediaType {
self.media_type self.media_type
@ -242,19 +139,19 @@ impl ExtXMedia {
} }
/// Returns whether this is the default rendition. /// Returns whether this is the default rendition.
pub const fn default(&self) -> bool { pub const fn is_default(&self) -> bool {
self.default self.is_default
} }
/// Returns whether the client may choose to /// Returns whether the client may choose to
/// play this rendition in the absence of explicit user preference. /// play this rendition in the absence of explicit user preference.
pub const fn autoselect(&self) -> bool { pub const fn autoselect(&self) -> bool {
self.autoselect self.is_autoselect
} }
/// Returns whether the rendition contains content that is considered essential to play. /// Returns whether the rendition contains content that is considered essential to play.
pub const fn forced(&self) -> bool { pub const fn is_forced(&self) -> bool {
self.forced self.is_forced
} }
/// Returns the identifier that specifies a rendition within the segments in the media playlist. /// Returns the identifier that specifies a rendition within the segments in the media playlist.
@ -303,13 +200,13 @@ impl fmt::Display for ExtXMedia {
write!(f, ",ASSOC-LANGUAGE={}", quote(value))?; write!(f, ",ASSOC-LANGUAGE={}", quote(value))?;
} }
write!(f, ",NAME={}", quote(&self.name))?; write!(f, ",NAME={}", quote(&self.name))?;
if self.default { if self.is_default {
write!(f, ",DEFAULT=YES")?; write!(f, ",DEFAULT=YES")?;
} }
if self.autoselect { if self.is_autoselect {
write!(f, ",AUTOSELECT=YES")?; write!(f, ",AUTOSELECT=YES")?;
} }
if self.forced { if self.is_forced {
write!(f, ",FORCED=YES")?; write!(f, ",FORCED=YES")?;
} }
if let Some(value) = &self.instream_id { if let Some(value) = &self.instream_id {
@ -331,12 +228,12 @@ impl FromStr for ExtXMedia {
fn from_str(input: &str) -> Result<Self, Self::Err> { fn from_str(input: &str) -> Result<Self, Self::Err> {
let input = tag(input, Self::PREFIX)?; let input = tag(input, Self::PREFIX)?;
let mut builder = ExtXMediaBuilder::new(); let mut builder = ExtXMedia::builder();
for (key, value) in input.parse::<AttributePairs>()? { for (key, value) in input.parse::<AttributePairs>()? {
match key.as_str() { match key.as_str() {
"TYPE" => { "TYPE" => {
builder.media_type(value.parse()?); builder.media_type(value.parse::<MediaType>()?);
} }
"URI" => { "URI" => {
builder.uri(unquote(value)); builder.uri(unquote(value));
@ -354,16 +251,16 @@ impl FromStr for ExtXMedia {
builder.name(unquote(value)); builder.name(unquote(value));
} }
"DEFAULT" => { "DEFAULT" => {
builder.default((parse_yes_or_no(value))?); builder.is_default(parse_yes_or_no(value)?);
} }
"AUTOSELECT" => { "AUTOSELECT" => {
builder.autoselect((parse_yes_or_no(value))?); builder.is_autoselect(parse_yes_or_no(value)?);
} }
"FORCED" => { "FORCED" => {
builder.forced((parse_yes_or_no(value))?); builder.is_forced(parse_yes_or_no(value)?);
} }
"INSTREAM-ID" => { "INSTREAM-ID" => {
builder.instream_id(unquote(value).parse()?); builder.instream_id(unquote(value).parse::<InStreamId>()?);
} }
"CHARACTERISTICS" => { "CHARACTERISTICS" => {
builder.characteristics(unquote(value)); builder.characteristics(unquote(value));
@ -377,7 +274,7 @@ impl FromStr for ExtXMedia {
} }
} }
} }
(builder.finish()) builder.build().map_err(Error::builder_error)
} }
} }