1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-05-18 16:28:20 +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::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<MediaType>,
/// [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<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>,
/// Sets the name of a language associated with the rendition.
#[builder(setter(strip_option, into), default)]
assoc_language: Option<String>,
name: Option<String>,
default: bool,
autoselect: Option<bool>,
forced: Option<bool>,
/// 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<InStreamId>,
/// Sets the string that represents uniform type identifiers (UTI).
#[builder(setter(strip_option, into), default)]
characteristics: Option<String>,
/// Sets the string that represents the parameters of the rendition.
#[builder(setter(strip_option, into), default)]
channels: Option<String>,
}
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<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> {
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<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 {
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<Self, Self::Err> {
let input = tag(input, Self::PREFIX)?;
let mut builder = ExtXMediaBuilder::new();
let mut builder = ExtXMedia::builder();
for (key, value) in input.parse::<AttributePairs>()? {
match key.as_str() {
"TYPE" => {
builder.media_type(value.parse()?);
builder.media_type(value.parse::<MediaType>()?);
}
"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::<InStreamId>()?);
}
"CHARACTERISTICS" => {
builder.characteristics(unquote(value));
@ -377,7 +274,7 @@ impl FromStr for ExtXMedia {
}
}
}
(builder.finish())
builder.build().map_err(Error::builder_error)
}
}