From 324041730454ffeb92eb9d74a96e507aa20e5906 Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Sun, 22 Sep 2019 12:56:28 +0200 Subject: [PATCH] replaced builder with `derive_builder` #14 --- src/tags/master_playlist/media.rs | 241 +++++++++--------------------- 1 file changed, 69 insertions(+), 172 deletions(-) diff --git a/src/tags/master_playlist/media.rs b/src/tags/master_playlist/media.rs index ed71581..4cf05ce 100644 --- a/src/tags/master_playlist/media.rs +++ b/src/tags/master_playlist/media.rs @@ -1,195 +1,87 @@ use std::fmt; use std::str::FromStr; +use derive_builder::Builder; + use crate::attribute::AttributePairs; use crate::types::{InStreamId, MediaType, ProtocolVersion, RequiredVersion}; use crate::utils::{parse_yes_or_no, quote, tag, unquote}; use crate::Error; -/// `ExtXMedia` builder. -#[derive(Debug, Clone)] -pub struct ExtXMediaBuilder { - media_type: Option, +/// [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(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, - group_id: Option, + /// 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, + /// Sets the name of a language associated with the rendition. + #[builder(setter(strip_option, into), default)] assoc_language: Option, - name: Option, - default: bool, - autoselect: Option, - forced: Option, + /// Sets a human-readable description of the rendition. + name: String, + /// Sets the value of the `default` flag. + #[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, + /// Sets the string that represents uniform type identifiers (UTI). + #[builder(setter(strip_option, into), default)] characteristics: Option, + /// Sets the string that represents the parameters of the rendition. + #[builder(setter(strip_option, into), default)] channels: Option, } impl ExtXMediaBuilder { - /// Makes a `ExtXMediaBuilder` instance. - 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(&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(&mut self, name: T) -> &mut Self { - self.name = Some(name.to_string()); - self - } - - /// Sets the URI that identifies the media playlist. - pub fn uri(&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(&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(&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(&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(&mut self, channels: T) -> &mut Self { - self.channels = Some(channels.to_string()); - self - } - - /// Builds a `ExtXMedia` instance. - pub fn finish(self) -> crate::Result { + fn validate(&self) -> Result<(), String> { let media_type = self .media_type - .ok_or(Error::missing_value("self.media_type"))?; - 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"))?; + .ok_or(Error::missing_value("self.media_type").to_string())?; if MediaType::ClosedCaptions == media_type { if let None = self.uri { - return Err(Error::missing_value("self.uri")); + return Err(Error::missing_value("self.uri").to_string()); } self.instream_id - .ok_or(Error::missing_value("self.instream_id"))?; + .ok_or(Error::missing_value("self.instream_id").to_string())?; } else { 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 let Some(value) = &self.autoselect { - if *value { - Err(Error::invalid_input())?; - } - } + if self.is_default.unwrap_or(false) && self.is_autoselect.unwrap_or(false) { + return Err(Error::invalid_input().to_string()); } if MediaType::Subtitles != media_type { - if self.forced.is_some() { - Err(Error::invalid_input())?; + if self.is_forced.is_some() { + return Err(Error::invalid_input().to_string()); } } - Ok(ExtXMedia { - 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, - }) + Ok(()) } } -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, - group_id: String, - language: Option, - assoc_language: Option, - name: String, - default: bool, - autoselect: bool, - forced: bool, - instream_id: Option, - characteristics: Option, - channels: Option, -} - impl ExtXMedia { pub(crate) const PREFIX: &'static str = "#EXT-X-MEDIA:"; @@ -202,15 +94,20 @@ impl ExtXMedia { language: None, assoc_language: None, name: name.to_string(), - default: false, - autoselect: false, - forced: false, + is_default: false, + is_autoselect: false, + is_forced: false, instream_id: None, characteristics: None, channels: None, } } + /// Makes a [ExtXMediaBuilder] for [ExtXMedia]. + pub fn builder() -> ExtXMediaBuilder { + ExtXMediaBuilder::default() + } + /// Returns the type of the media associated with this tag. pub const fn media_type(&self) -> MediaType { self.media_type @@ -242,19 +139,19 @@ impl ExtXMedia { } /// Returns whether this is the default rendition. - pub const fn default(&self) -> bool { - self.default + pub const fn is_default(&self) -> bool { + self.is_default } /// Returns whether the client may choose to /// play this rendition in the absence of explicit user preference. pub const fn autoselect(&self) -> bool { - self.autoselect + self.is_autoselect } /// Returns whether the rendition contains content that is considered essential to play. - pub const fn forced(&self) -> bool { - self.forced + pub const fn is_forced(&self) -> bool { + self.is_forced } /// 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, ",NAME={}", quote(&self.name))?; - if self.default { + if self.is_default { write!(f, ",DEFAULT=YES")?; } - if self.autoselect { + if self.is_autoselect { write!(f, ",AUTOSELECT=YES")?; } - if self.forced { + if self.is_forced { write!(f, ",FORCED=YES")?; } if let Some(value) = &self.instream_id { @@ -331,12 +228,12 @@ impl FromStr for ExtXMedia { fn from_str(input: &str) -> Result { let input = tag(input, Self::PREFIX)?; - let mut builder = ExtXMediaBuilder::new(); + let mut builder = ExtXMedia::builder(); for (key, value) in input.parse::()? { match key.as_str() { "TYPE" => { - builder.media_type(value.parse()?); + builder.media_type(value.parse::()?); } "URI" => { builder.uri(unquote(value)); @@ -354,16 +251,16 @@ impl FromStr for ExtXMedia { builder.name(unquote(value)); } "DEFAULT" => { - builder.default((parse_yes_or_no(value))?); + builder.is_default(parse_yes_or_no(value)?); } "AUTOSELECT" => { - builder.autoselect((parse_yes_or_no(value))?); + builder.is_autoselect(parse_yes_or_no(value)?); } "FORCED" => { - builder.forced((parse_yes_or_no(value))?); + builder.is_forced(parse_yes_or_no(value)?); } "INSTREAM-ID" => { - builder.instream_id(unquote(value).parse()?); + builder.instream_id(unquote(value).parse::()?); } "CHARACTERISTICS" => { builder.characteristics(unquote(value)); @@ -377,7 +274,7 @@ impl FromStr for ExtXMedia { } } } - (builder.finish()) + builder.build().map_err(Error::builder_error) } }