From 720dc32474203d8ff7248528e6ff754f8f3ced6f Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Sat, 21 Sep 2019 08:47:52 +0200 Subject: [PATCH 1/4] fixed test --- src/types/decryption_key.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/types/decryption_key.rs b/src/types/decryption_key.rs index 7e82ff9..0b425b9 100644 --- a/src/types/decryption_key.rs +++ b/src/types/decryption_key.rs @@ -388,15 +388,21 @@ mod test { use crate::types::EncryptionMethod; #[test] - fn test_requires_version() { + fn test_builder() { let key = DecryptionKey::builder() .method(EncryptionMethod::Aes128) .uri("https://www.example.com".parse::().unwrap()) .iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, ]) + .key_format("ABC123") + .key_format_versions("1,2,3,4,5/12345") .build() .unwrap(); + assert_eq!( + key.to_string(), + "METHOD=AES-128,URI=\"https://www.example.com/\",IV=0x10ef8f758ca555115584bb5b3c687f52,KEYFORMAT=\"ABC123\",KEYFORMATVERSIONS=\"1,2,3,4,5/12345\"".to_string() + ) } #[test] From 0900d7e56bb65335570c6e06bb9f2f7b60c7322b Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Sat, 21 Sep 2019 11:04:45 +0200 Subject: [PATCH 2/4] improved session_data docs + tests --- src/tags/master_playlist/session_data.rs | 280 +++++++++++++++++++++-- 1 file changed, 255 insertions(+), 25 deletions(-) diff --git a/src/tags/master_playlist/session_data.rs b/src/tags/master_playlist/session_data.rs index 0c7d1aa..ddd7ee6 100644 --- a/src/tags/master_playlist/session_data.rs +++ b/src/tags/master_playlist/session_data.rs @@ -1,45 +1,64 @@ use std::fmt; use std::str::FromStr; -use getset::{Getters, MutGetters, Setters}; +use derive_builder::Builder; use crate::attribute::AttributePairs; use crate::types::ProtocolVersion; use crate::utils::{quote, tag, unquote}; use crate::Error; -/// Session data. -/// -/// See: [4.3.4.4. EXT-X-SESSION-DATA] -/// -/// [4.3.4.4. EXT-X-SESSION-DATA]: https://tools.ietf.org/html/rfc8216#section-4.3.4.4 -#[allow(missing_docs)] -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +/// The data of an [ExtXSessionData] tag. +#[derive(Hash, Eq, Ord, Debug, PartialEq, Clone, PartialOrd)] pub enum SessionData { + /// A String, that contains the data identified by [data_id](ExtXSessionData::data_id). + /// If a [language](ExtXSessionData::language) is specified, the value should + /// contain a human-readable string written in the specified language. Value(String), + /// An [uri], which points to a [json]. + /// + /// [json]: https://tools.ietf.org/html/rfc8259 + /// [uri]: https://tools.ietf.org/html/rfc3986 Uri(String), } /// [4.3.4.4. EXT-X-SESSION-DATA] /// +/// The [ExtXSessionData] tag allows arbitrary session data to be +/// carried in a [Master Playlist](crate::MasterPlaylist). +/// /// [4.3.4.4. EXT-X-SESSION-DATA]: https://tools.ietf.org/html/rfc8216#section-4.3.4.4 -#[derive(Getters, MutGetters, Setters, Debug, Clone, PartialEq, Eq, Hash)] -#[get = "pub"] -#[set = "pub"] -#[get_mut = "pub"] +#[derive(Builder, Hash, Eq, Ord, Debug, PartialEq, Clone, PartialOrd)] +#[builder(setter(into))] pub struct ExtXSessionData { - /// The identifier of the data. + /// The identifier of the data. For more information look [here](ExtXSessionData::set_data_id). + /// # Note + /// This field is required. data_id: String, - /// The session data. + /// The data associated with the [data_id](ExtXSessionDataBuilder::data_id). + /// For more information look [here](SessionData). + /// # Note + /// This field is required. data: SessionData, - /// The language of the data. + /// The language of the [data](ExtXSessionDataBuilder::data). + #[builder(setter(into, strip_option), default)] language: Option, } impl ExtXSessionData { pub(crate) const PREFIX: &'static str = "#EXT-X-SESSION-DATA:"; - /// Makes a new `ExtXSessionData` tag. + /// Makes a new [ExtXSessionData] tag. + /// + /// # Example + /// ``` + /// use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// + /// ExtXSessionData::new( + /// "com.example.movie.title", + /// SessionData::Uri("https://www.example.com/".to_string()) + /// ); + /// ``` pub fn new(data_id: T, data: SessionData) -> Self { ExtXSessionData { data_id: data_id.to_string(), @@ -48,7 +67,44 @@ impl ExtXSessionData { } } - /// Makes a new `ExtXSessionData` with the given language. + /// Returns a new Builder for [ExtXSessionData]. + /// + /// # Example + /// ``` + /// use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// + /// let session_data = ExtXSessionData::builder() + /// .data_id("com.example.movie.title") + /// .data(SessionData::Value("some data".to_string())) + /// .language("english") + /// .build() + /// .expect("Failed to build an ExtXSessionData tag."); + /// + /// assert_eq!( + /// session_data, + /// ExtXSessionData::with_language( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()), + /// "english" + /// ) + /// ); + /// ``` + pub fn builder() -> ExtXSessionDataBuilder { + ExtXSessionDataBuilder::default() + } + + /// Makes a new [ExtXSessionData] tag, with the given language. + /// + /// # Example + /// ``` + /// use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// + /// let session_data = ExtXSessionData::with_language( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()), + /// "english" + /// ); + /// ``` pub fn with_language(data_id: T, data: SessionData, language: T) -> Self { ExtXSessionData { data_id: data_id.to_string(), @@ -57,7 +113,147 @@ impl ExtXSessionData { } } - /// Returns the protocol compatibility version that this tag requires. + /// Returns the `data_id`, that identifies a `data_value`. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// # + /// let data = ExtXSessionData::new( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()) + /// ); + /// + /// assert_eq!( + /// data.data_id(), + /// &"com.example.movie.title".to_string() + /// ) + /// ``` + pub const fn data_id(&self) -> &String { + &self.data_id + } + + /// Returns the `data`. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// # + /// let data = ExtXSessionData::new( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()) + /// ); + /// + /// assert_eq!( + /// data.data(), + /// &SessionData::Value("some data".to_string()) + /// ) + /// ``` + pub const fn data(&self) -> &SessionData { + &self.data + } + + /// Returns the `language` tag, that identifies the language of [SessionData]. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// # + /// let data = ExtXSessionData::with_language( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()), + /// "english" + /// ); + /// + /// assert_eq!( + /// data.language(), + /// &Some("english".to_string()) + /// ) + /// ``` + pub const fn language(&self) -> &Option { + &self.language + } + + /// Sets the `language` attribute, that identifies the language of [SessionData]. + /// See [rfc5646](https://tools.ietf.org/html/rfc5646). + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// # + /// let mut data = ExtXSessionData::new( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()), + /// ); + /// + /// assert_eq!(data.language(), &None); + /// + /// data.set_language(Some("english")); + /// assert_eq!(data.language(), &Some("english".to_string())); + /// ``` + pub fn set_language(&mut self, value: Option) -> &mut Self { + self.language = value.map(|v| v.to_string()); + self + } + + /// Sets the `data_id` attribute, that should conform to a [reverse DNS] naming convention, + /// such as `com.example.movie.title`. + /// + /// # Note: + /// There is no central registration authority, so a value + /// should be choosen, that is unlikely to collide with others. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// # + /// let mut data = ExtXSessionData::new( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()), + /// ); + /// + /// assert_eq!(data.data_id(), &"com.example.movie.title".to_string()); + /// + /// data.set_data_id("com.other.movie.title"); + /// assert_eq!(data.data_id(), &"com.other.movie.title".to_string()); + /// ``` + /// [reverse DNS]: https://en.wikipedia.org/wiki/Reverse_domain_name_notation + pub fn set_data_id(&mut self, value: T) -> &mut Self { + self.data_id = value.to_string(); + self + } + + /// Sets the [data](ExtXSessionData::data) of this tag. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// # + /// let mut data = ExtXSessionData::new( + /// "com.example.movie.title", + /// SessionData::Value("some data".to_string()), + /// ); + /// + /// assert_eq!(data.data(), &SessionData::Value("some data".to_string())); + /// + /// data.set_data(SessionData::Value("new data".to_string())); + /// assert_eq!(data.data(), &SessionData::Value("new data".to_string())); + /// ``` + pub fn set_data(&mut self, value: SessionData) -> &mut Self { + self.data = value; + self + } + + /// Returns the protocol compatibility version, that this tag requires. + /// + /// # Example + /// ``` + /// # use hls_m3u8::types::ProtocolVersion; + /// # use hls_m3u8::tags::{ExtXSessionData, SessionData}; + /// # + /// let tag = ExtXSessionData::new("foo", SessionData::Value("bar".into())); + /// assert_eq!(tag.requires_version(), ProtocolVersion::V1); + /// ``` pub const fn requires_version(&self) -> ProtocolVersion { ProtocolVersion::V1 } @@ -106,7 +302,7 @@ impl FromStr for ExtXSessionData { let data = { if let Some(value) = session_value { if uri.is_some() { - return Err(Error::invalid_input()); + return Err(Error::custom("Unexpected URI")); } else { SessionData::Value(value) } @@ -146,6 +342,46 @@ mod test { #[test] fn test_parser() { + let tag = "#EXT-X-SESSION-DATA:DATA-ID=\"com.example.lyrics\",URI=\"lyrics.json\"" + .parse::() + .unwrap(); + + assert_eq!( + tag, + ExtXSessionData::new( + "com.example.lyrics", + SessionData::Uri("lyrics.json".to_string()) + ) + ); + + let tag = "#EXT-X-SESSION-DATA:DATA-ID=\"com.example.title\",\ + LANGUAGE=\"en\", VALUE=\"This is an example\"" + .parse::() + .unwrap(); + + assert_eq!( + tag, + ExtXSessionData::with_language( + "com.example.title", + SessionData::Value("This is an example".to_string()), + "en" + ) + ); + + let tag = "#EXT-X-SESSION-DATA:DATA-ID=\"com.example.title\",\ + LANGUAGE=\"es\", VALUE=\"Este es un ejemplo\"" + .parse::() + .unwrap(); + + assert_eq!( + tag, + ExtXSessionData::with_language( + "com.example.title", + SessionData::Value("Este es un ejemplo".to_string()), + "es" + ) + ); + let tag = ExtXSessionData::new("foo", SessionData::Value("bar".into())); let text = r#"#EXT-X-SESSION-DATA:DATA-ID="foo",VALUE="bar""#; assert_eq!(text.parse::().unwrap(), tag); @@ -158,10 +394,4 @@ mod test { let text = r#"#EXT-X-SESSION-DATA:DATA-ID="foo",VALUE="bar",LANGUAGE="baz""#; assert_eq!(text.parse::().unwrap(), tag); } - - #[test] - fn test_requires_version() { - let tag = ExtXSessionData::new("foo", SessionData::Value("bar".into())); - assert_eq!(tag.requires_version(), ProtocolVersion::V1); - } } From ea75128aee85fd4807282fd2dbde980af514c3f8 Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Sat, 21 Sep 2019 11:53:34 +0200 Subject: [PATCH 3/4] remove getset #19 --- Cargo.toml | 1 - .../master_playlist/i_frame_stream_inf.rs | 228 +++++++++++++++--- src/tags/media_segment/byte_range.rs | 6 +- src/tags/media_segment/date_range.rs | 6 +- src/types/byte_range.rs | 65 ++++- 5 files changed, 257 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d37b563..4e2f85c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ travis-ci = {repository = "sile/hls_m3u8"} codecov = {repository = "sile/hls_m3u8"} [dependencies] -getset = "0.0.8" failure = "0.1.5" derive_builder = "0.7.2" url = "2.1.0" diff --git a/src/tags/master_playlist/i_frame_stream_inf.rs b/src/tags/master_playlist/i_frame_stream_inf.rs index 1567c07..cbd60b8 100644 --- a/src/tags/master_playlist/i_frame_stream_inf.rs +++ b/src/tags/master_playlist/i_frame_stream_inf.rs @@ -1,8 +1,6 @@ use std::fmt; use std::str::FromStr; -use getset::{Getters, MutGetters, Setters}; - use crate::attribute::AttributePairs; use crate::types::{DecimalResolution, HdcpLevel, ProtocolVersion}; use crate::utils::parse_u64; @@ -12,39 +10,14 @@ use crate::Error; /// [4.3.4.3. EXT-X-I-FRAME-STREAM-INF] /// /// [4.3.4.3. EXT-X-I-FRAME-STREAM-INF]: https://tools.ietf.org/html/rfc8216#section-4.3.4.3 -#[derive(Getters, Setters, MutGetters, Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ExtXIFrameStreamInf { - #[get = "pub"] - #[set = "pub"] - #[get_mut = "pub"] - /// The URI, that identifies the associated media playlist. uri: String, - #[get = "pub"] - #[set = "pub"] - #[get_mut = "pub"] - /// The peak segment bit rate of the variant stream. bandwidth: u64, - #[get = "pub"] - #[set = "pub"] - #[get_mut = "pub"] - /// The average segment bit rate of the variant stream. average_bandwidth: Option, - #[get = "pub"] - #[set = "pub"] - #[get_mut = "pub"] - /// A string that represents the list of codec types contained the variant stream. codecs: Option, - /// The optimal pixel resolution at which to display all the video in the variant stream. resolution: Option, - #[get = "pub"] - #[set = "pub"] - #[get_mut = "pub"] - /// The HDCP level of the variant stream. hdcp_level: Option, - #[get = "pub"] - #[set = "pub"] - #[get_mut = "pub"] - /// The group identifier for the video in the variant stream. video: Option, } @@ -64,7 +37,160 @@ impl ExtXIFrameStreamInf { } } - /// The optimal pixel resolution at which to display all the video in the variant stream. + /// Returns the URI, that identifies the associated media playlist. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// assert_eq!(stream.uri(), &"https://www.example.com".to_string()); + /// ``` + pub const fn uri(&self) -> &String { + &self.uri + } + + /// Sets the URI, that identifies the associated media playlist. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// + /// stream.set_uri("../new/uri"); + /// assert_eq!(stream.uri(), &"../new/uri".to_string()); + /// ``` + pub fn set_uri(&mut self, value: T) -> &mut Self { + self.uri = value.to_string(); + self + } + + /// Returns the peak segment bit rate of the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// assert_eq!(stream.bandwidth(), 20); + /// ``` + pub const fn bandwidth(&self) -> u64 { + self.bandwidth + } + + /// Sets the group identifier for the video in the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// + /// stream.set_video(Some("video")); + /// assert_eq!(stream.video(), &Some("video".to_string())); + /// ``` + pub fn set_video(&mut self, value: Option) -> &mut Self { + self.video = value.map(|v| v.to_string()); + self + } + + /// Returns the group identifier for the video in the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// assert_eq!(stream.video(), &None); + /// ``` + pub const fn video(&self) -> &Option { + &self.video + } + + /// Sets the peak segment bit rate of the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// + /// stream.set_bandwidth(5); + /// assert_eq!(stream.bandwidth(), 5); + /// ``` + pub fn set_bandwidth(&mut self, value: u64) -> &mut Self { + self.bandwidth = value; + self + } + + /// Returns the average segment bit rate of the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// assert_eq!(stream.average_bandwidth(), None); + /// ``` + pub const fn average_bandwidth(&self) -> Option { + self.average_bandwidth + } + + /// Sets the average segment bit rate of the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// + /// stream.set_average_bandwidth(Some(300)); + /// assert_eq!(stream.average_bandwidth(), Some(300)); + /// ``` + pub fn set_average_bandwidth(&mut self, value: Option) -> &mut Self { + self.average_bandwidth = value; + self + } + + /// A string that represents the list of codec types contained the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// assert_eq!(stream.codecs(), &None); + /// ``` + pub const fn codecs(&self) -> &Option { + &self.codecs + } + + /// A string that represents the list of codec types contained the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// + /// stream.set_uri("../new/uri"); + /// assert_eq!(stream.uri(), &"../new/uri".to_string()); + /// ``` + pub fn set_codecs(&mut self, value: Option) -> &mut Self { + self.codecs = value.map(|v| v.to_string()); + self + } + + /// Returns the resolution of the stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// assert_eq!(stream.resolution(), None); + /// ``` pub fn resolution(&self) -> Option<(usize, usize)> { if let Some(res) = &self.resolution { Some((res.width(), res.height())) @@ -73,7 +199,17 @@ impl ExtXIFrameStreamInf { } } - /// Sets the optimal pixel resolution at which to display all the video in the variant stream. + /// Sets the resolution of the stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// + /// stream.set_resolution(1920, 1080); + /// assert_eq!(stream.resolution(), Some((1920, 1080))); + /// ``` pub fn set_resolution(&mut self, width: usize, height: usize) -> &mut Self { if let Some(res) = &mut self.resolution { res.set_width(width); @@ -83,6 +219,36 @@ impl ExtXIFrameStreamInf { } self } + + /// The HDCP level of the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// assert_eq!(stream.uri(), &"https://www.example.com".to_string()); + /// ``` + pub const fn hdcp_level(&self) -> Option { + self.hdcp_level + } + + /// The HDCP level of the variant stream. + /// + /// # Example + /// ``` + /// # use hls_m3u8::tags::ExtXIFrameStreamInf; + /// # + /// let mut stream = ExtXIFrameStreamInf::new("https://www.example.com", 20); + /// + /// stream.set_uri("../new/uri"); + /// assert_eq!(stream.uri(), &"../new/uri".to_string()); + /// ``` + pub fn set_hdcp_level>(&mut self, value: Option) -> &mut Self { + self.hdcp_level = value.map(|v| v.into()); + self + } + /// Returns the protocol compatibility version that this tag requires. pub const fn requires_version(&self) -> ProtocolVersion { ProtocolVersion::V1 @@ -179,7 +345,7 @@ mod test { ); assert_eq!(i_frame_stream_inf.uri(), "foo"); - assert_eq!(*i_frame_stream_inf.bandwidth(), 1000); + assert_eq!(i_frame_stream_inf.bandwidth(), 1000); // TODO: test all the optional fields } diff --git a/src/tags/media_segment/byte_range.rs b/src/tags/media_segment/byte_range.rs index e7a895a..c1bf2ce 100644 --- a/src/tags/media_segment/byte_range.rs +++ b/src/tags/media_segment/byte_range.rs @@ -114,7 +114,7 @@ mod test { } #[test] - fn test_parse() { + fn test_parser() { let byte_range = ExtXByteRange::new(99999, Some(2)); assert_eq!( byte_range, @@ -132,7 +132,7 @@ mod test { fn test_deref() { let byte_range = ExtXByteRange::new(0, Some(22)); - assert_eq!(*byte_range.length(), 0); - assert_eq!(*byte_range.start(), Some(22)); + assert_eq!(byte_range.length(), 0); + assert_eq!(byte_range.start(), Some(22)); } } diff --git a/src/tags/media_segment/date_range.rs b/src/tags/media_segment/date_range.rs index d1c4fbd..4f17db3 100644 --- a/src/tags/media_segment/date_range.rs +++ b/src/tags/media_segment/date_range.rs @@ -4,7 +4,6 @@ use std::str::FromStr; use std::time::Duration; use chrono::{DateTime, FixedOffset}; -use getset::{Getters, MutGetters, Setters}; use crate::attribute::AttributePairs; use crate::types::{DecimalFloatingPoint, ProtocolVersion}; @@ -17,10 +16,7 @@ use crate::Error; /// /// TODO: Implement properly #[allow(missing_docs)] -#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters, MutGetters, Setters)] -#[get = "pub"] -#[set = "pub"] -#[get_mut = "pub"] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ExtXDateRange { /// A string that uniquely identifies a Date Range in the Playlist. /// This attribute is REQUIRED. diff --git a/src/types/byte_range.rs b/src/types/byte_range.rs index 09f3535..36b0a74 100644 --- a/src/types/byte_range.rs +++ b/src/types/byte_range.rs @@ -1,8 +1,6 @@ use std::fmt; use std::str::FromStr; -use getset::{Getters, MutGetters, Setters}; - use crate::Error; /// Byte range. @@ -10,14 +8,9 @@ use crate::Error; /// See: [4.3.2.2. EXT-X-BYTERANGE] /// /// [4.3.2.2. EXT-X-BYTERANGE]: https://tools.ietf.org/html/rfc8216#section-4.3.2.2 -#[derive(Getters, Setters, MutGetters, Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[get = "pub"] -#[set = "pub"] -#[get_mut = "pub"] +#[derive(Copy, Hash, Eq, Ord, Debug, PartialEq, Clone, PartialOrd)] pub struct ByteRange { - /// The length of the range. length: usize, - /// The start of the range. start: Option, } @@ -26,6 +19,60 @@ impl ByteRange { pub const fn new(length: usize, start: Option) -> Self { Self { length, start } } + + /// Returns the length of the range. + /// # Example + /// ``` + /// # use hls_m3u8::types::ByteRange; + /// # + /// assert_eq!(ByteRange::new(20, Some(3)).length(), 20); + /// ``` + pub const fn length(&self) -> usize { + self.length + } + + /// Sets the length of the range. + /// # Example + /// ``` + /// # use hls_m3u8::types::ByteRange; + /// # + /// let mut range = ByteRange::new(20, Some(3)); + /// + /// # assert_eq!(range.length(), 20); + /// range.set_length(10); + /// assert_eq!(range.length(), 10); + /// ``` + pub fn set_length(&mut self, value: usize) -> &mut Self { + self.length = value; + self + } + + /// Returns the start of the range. + /// # Example + /// ``` + /// # use hls_m3u8::types::ByteRange; + /// # + /// assert_eq!(ByteRange::new(20, Some(3)).start(), Some(3)); + /// ``` + pub const fn start(&self) -> Option { + self.start + } + + /// Sets the start of the range. + /// # Example + /// ``` + /// # use hls_m3u8::types::ByteRange; + /// # + /// let mut range = ByteRange::new(20, None); + /// + /// # assert_eq!(range.start(), None); + /// range.set_start(Some(3)); + /// assert_eq!(range.start(), Some(3)); + /// ``` + pub fn set_start(&mut self, value: Option) -> &mut Self { + self.start = value; + self + } } impl fmt::Display for ByteRange { @@ -86,7 +133,7 @@ mod tests { } #[test] - fn test_parse() { + fn test_parser() { let byte_range = ByteRange { length: 99999, start: Some(2), From 71361ff3286a15e0eab9647438aae07d08e24874 Mon Sep 17 00:00:00 2001 From: Luro02 <24826124+Luro02@users.noreply.github.com> Date: Sat, 21 Sep 2019 12:11:36 +0200 Subject: [PATCH 4/4] remove url #21 --- Cargo.toml | 1 - src/error.rs | 14 +----- src/line.rs | 6 +-- src/media_segment.rs | 5 +- src/tags/master_playlist/session_key.rs | 12 ++--- src/tags/master_playlist/stream_inf.rs | 18 ++++--- src/tags/media_segment/key.rs | 14 ++---- src/types/decryption_key.rs | 62 ++++++++++++------------- tests/playlist.rs | 4 +- 9 files changed, 54 insertions(+), 82 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4e2f85c..9a6c983 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ codecov = {repository = "sile/hls_m3u8"} [dependencies] failure = "0.1.5" derive_builder = "0.7.2" -url = "2.1.0" chrono = "0.4.9" [dev-dependencies] diff --git a/src/error.rs b/src/error.rs index 7acb888..c2db7c2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,9 +12,7 @@ pub enum ErrorKind { #[fail(display = "ChronoParseError: {}", _0)] /// An error from the [Chrono](chrono) crate. ChronoParseError(String), - #[fail(display = "UrlParseError: {}", _0)] - /// An error from the [Url](url) crate. - UrlParseError(String), + #[fail(display = "UnknownError: {}", _0)] /// An unknown error occured. UnknownError(String), @@ -184,10 +182,6 @@ impl Error { Self::from(ErrorKind::BuilderError(value.to_string())) } - pub(crate) fn url(value: T) -> Self { - Self::from(ErrorKind::UrlParseError(value.to_string())) - } - pub(crate) fn chrono(value: T) -> Self { Self::from(ErrorKind::ChronoParseError(value.to_string())) } @@ -211,12 +205,6 @@ impl From<::std::io::Error> for Error { } } -impl From<::url::ParseError> for Error { - fn from(value: ::url::ParseError) -> Self { - Error::url(value) - } -} - impl From<::chrono::ParseError> for Error { fn from(value: ::chrono::ParseError) -> Self { Error::chrono(value) diff --git a/src/line.rs b/src/line.rs index 28b3a32..6d8ca95 100644 --- a/src/line.rs +++ b/src/line.rs @@ -2,8 +2,6 @@ use std::fmt; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use url::Url; - use crate::tags; use crate::Error; @@ -55,7 +53,7 @@ impl FromStr for Lines { continue; } } else { - Line::Uri(line.trim().parse()?) + Line::Uri(line.trim().to_string()) } } }; @@ -93,7 +91,7 @@ impl DerefMut for Lines { #[derive(Debug, PartialEq, Eq)] pub enum Line { Tag(Tag), - Uri(Url), + Uri(String), } #[allow(clippy::large_enum_variant)] diff --git a/src/media_segment.rs b/src/media_segment.rs index d637131..8460547 100644 --- a/src/media_segment.rs +++ b/src/media_segment.rs @@ -2,7 +2,6 @@ use std::fmt; use std::iter; use derive_builder::Builder; -use url::Url; use crate::tags::{ ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey, ExtXMap, ExtXProgramDateTime, @@ -34,7 +33,7 @@ pub struct MediaSegment { /// Sets an [ExtInf] tag. inf_tag: ExtInf, /// Sets an Uri. - uri: Url, + uri: String, } impl MediaSegmentBuilder { @@ -81,7 +80,7 @@ impl MediaSegment { MediaSegmentBuilder::default() } /// Returns the URI of the media segment. - pub const fn uri(&self) -> &Url { + pub const fn uri(&self) -> &String { &self.uri } diff --git a/src/tags/master_playlist/session_key.rs b/src/tags/master_playlist/session_key.rs index 0d7d275..e76fb64 100644 --- a/src/tags/master_playlist/session_key.rs +++ b/src/tags/master_playlist/session_key.rs @@ -2,8 +2,6 @@ use std::fmt; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use url::Url; - use crate::types::{DecryptionKey, EncryptionMethod, ProtocolVersion}; use crate::utils::tag; use crate::Error; @@ -20,7 +18,7 @@ impl ExtXSessionKey { /// Makes a new [ExtXSessionKey] tag. /// # Panic /// This method will panic, if the [EncryptionMethod] is None. - pub fn new(method: EncryptionMethod, uri: Url) -> Self { + pub fn new(method: EncryptionMethod, uri: T) -> Self { if method == EncryptionMethod::None { panic!("The EncryptionMethod is not allowed to be None"); } @@ -36,7 +34,7 @@ impl ExtXSessionKey { /// /// let mut key = ExtXSessionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// assert_eq!( @@ -93,7 +91,7 @@ mod test { fn test_display() { let mut key = ExtXSessionKey::new( EncryptionMethod::Aes128, - "https://www.example.com/hls-key/key.bin".parse().unwrap(), + "https://www.example.com/hls-key/key.bin", ); key.set_iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, @@ -116,13 +114,13 @@ mod test { .unwrap(), ExtXSessionKey::new( EncryptionMethod::Aes128, - "https://priv.example.com/key.php?r=52".parse().unwrap() + "https://priv.example.com/key.php?r=52" ) ); let mut key = ExtXSessionKey::new( EncryptionMethod::Aes128, - "https://www.example.com/hls-key/key.bin".parse().unwrap(), + "https://www.example.com/hls-key/key.bin", ); key.set_iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, diff --git a/src/tags/master_playlist/stream_inf.rs b/src/tags/master_playlist/stream_inf.rs index 808d4fc..74c0325 100644 --- a/src/tags/master_playlist/stream_inf.rs +++ b/src/tags/master_playlist/stream_inf.rs @@ -1,8 +1,6 @@ use std::fmt; use std::str::FromStr; -use url::Url; - use crate::attribute::AttributePairs; use crate::types::{ ClosedCaptions, DecimalFloatingPoint, DecimalResolution, HdcpLevel, ProtocolVersion, @@ -15,7 +13,7 @@ use crate::Error; /// [4.3.4.2. EXT-X-STREAM-INF]: https://tools.ietf.org/html/rfc8216#section-4.3.4.2 #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtXStreamInf { - uri: Url, + uri: String, bandwidth: u64, average_bandwidth: Option, codecs: Option, @@ -32,9 +30,9 @@ impl ExtXStreamInf { pub(crate) const PREFIX: &'static str = "#EXT-X-STREAM-INF:"; /// Makes a new `ExtXStreamInf` tag. - pub const fn new(uri: Url, bandwidth: u64) -> Self { + pub fn new(uri: T, bandwidth: u64) -> Self { ExtXStreamInf { - uri, + uri: uri.to_string(), bandwidth, average_bandwidth: None, codecs: None, @@ -49,7 +47,7 @@ impl ExtXStreamInf { } /// Returns the URI that identifies the associated media playlist. - pub const fn uri(&self) -> &Url { + pub const fn uri(&self) -> &String { &self.uri } @@ -193,7 +191,7 @@ impl FromStr for ExtXStreamInf { let bandwidth = bandwidth.ok_or(Error::missing_value("EXT-X-BANDWIDTH"))?; Ok(ExtXStreamInf { - uri: uri.parse()?, + uri: uri.to_string(), bandwidth, average_bandwidth, codecs, @@ -220,7 +218,7 @@ mod test { assert_eq!( stream_inf, - ExtXStreamInf::new("http://www.example.com".parse().unwrap(), 1000) + ExtXStreamInf::new("http://www.example.com", 1000) ); } @@ -228,14 +226,14 @@ mod test { fn test_requires_version() { assert_eq!( ProtocolVersion::V1, - ExtXStreamInf::new("http://www.example.com".parse().unwrap(), 1000).requires_version() + ExtXStreamInf::new("http://www.example.com", 1000).requires_version() ); } #[test] fn test_display() { assert_eq!( - ExtXStreamInf::new("http://www.example.com".parse().unwrap(), 1000).to_string(), + ExtXStreamInf::new("http://www.example.com/", 1000).to_string(), "#EXT-X-STREAM-INF:BANDWIDTH=1000\nhttp://www.example.com/".to_string() ); } diff --git a/src/tags/media_segment/key.rs b/src/tags/media_segment/key.rs index 64abf6d..9effe62 100644 --- a/src/tags/media_segment/key.rs +++ b/src/tags/media_segment/key.rs @@ -2,8 +2,6 @@ use std::fmt; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use url::Url; - use crate::types::{DecryptionKey, EncryptionMethod}; use crate::utils::tag; use crate::Error; @@ -22,14 +20,12 @@ impl ExtXKey { /// Makes a new `ExtXKey` tag. /// # Example /// ``` - /// use url::Url; - /// /// use hls_m3u8::tags::ExtXKey; /// use hls_m3u8::types::EncryptionMethod; /// /// let key = ExtXKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// assert_eq!( @@ -37,7 +33,7 @@ impl ExtXKey { /// "#EXT-X-KEY:METHOD=AES-128,URI=\"https://www.example.com/\"" /// ); /// ``` - pub const fn new(method: EncryptionMethod, uri: Url) -> Self { + pub fn new(method: EncryptionMethod, uri: T) -> Self { Self(DecryptionKey::new(method, uri)) } @@ -128,7 +124,7 @@ mod test { key.set_iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, ]); - key.set_uri("https://www.example.com".parse().unwrap()); + key.set_uri(Some("https://www.example.com")); key.set_key_format_versions("1/2/3"); assert_eq!(key.to_string(), "#EXT-X-KEY:METHOD=NONE".to_string()); @@ -142,13 +138,13 @@ mod test { .unwrap(), ExtXKey::new( EncryptionMethod::Aes128, - "https://priv.example.com/key.php?r=52".parse().unwrap() + "https://priv.example.com/key.php?r=52" ) ); let mut key = ExtXKey::new( EncryptionMethod::Aes128, - "https://www.example.com/hls-key/key.bin".parse().unwrap(), + "https://www.example.com/hls-key/key.bin", ); key.set_iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, diff --git a/src/types/decryption_key.rs b/src/types/decryption_key.rs index 0b425b9..8e2ec86 100644 --- a/src/types/decryption_key.rs +++ b/src/types/decryption_key.rs @@ -2,7 +2,6 @@ use std::fmt; use std::str::FromStr; use derive_builder::Builder; -use url::Url; use crate::attribute::AttributePairs; use crate::types::{EncryptionMethod, InitializationVector, ProtocolVersion}; @@ -14,7 +13,7 @@ use crate::Error; pub struct DecryptionKey { pub(crate) method: EncryptionMethod, #[builder(setter(into, strip_option), default)] - pub(crate) uri: Option, + pub(crate) uri: Option, #[builder(setter(into, strip_option), default)] pub(crate) iv: Option, #[builder(setter(into, strip_option), default)] @@ -27,13 +26,11 @@ impl DecryptionKey { /// Makes a new `DecryptionKey`. /// # Example /// ``` - /// use url::Url; - /// /// use hls_m3u8::types::{EncryptionMethod, DecryptionKey}; /// /// let key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// assert_eq!( @@ -41,10 +38,10 @@ impl DecryptionKey { /// "METHOD=AES-128,URI=\"https://www.example.com/\"" /// ); /// ``` - pub const fn new(method: EncryptionMethod, uri: Url) -> Self { + pub fn new(method: EncryptionMethod, uri: T) -> Self { Self { method, - uri: Some(uri), + uri: Some(uri.to_string()), iv: None, key_format: None, key_format_versions: None, @@ -58,7 +55,7 @@ impl DecryptionKey { /// /// let key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// assert_eq!( @@ -82,7 +79,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// key.set_method(EncryptionMethod::SampleAes); @@ -105,39 +102,41 @@ impl DecryptionKey { /// /// let key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// assert_eq!( /// key.uri(), - /// &Some("https://www.example.com".parse().unwrap()) + /// &Some("https://www.example.com/".to_string()) /// ); /// ``` - pub const fn uri(&self) -> &Option { + pub const fn uri(&self) -> &Option { &self.uri } /// Sets the `URI` attribute. /// - /// This attribute is required, if the [EncryptionMethod] is not None. + /// # Note + /// This attribute is required, if the [EncryptionMethod] is not `None`. + /// /// # Example /// ``` /// use hls_m3u8::types::{DecryptionKey, EncryptionMethod}; /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// - /// key.set_uri("http://www.google.com".parse().unwrap()); + /// key.set_uri(Some("http://www.google.com/")); /// /// assert_eq!( /// key.to_string(), /// "METHOD=AES-128,URI=\"http://www.google.com/\"".to_string() /// ); /// ``` - pub fn set_uri(&mut self, value: Url) { - self.uri = Some(value); + pub fn set_uri(&mut self, value: Option) { + self.uri = value.map(|v| v.to_string()); } /// Returns the IV (Initialization Vector) attribute. @@ -149,7 +148,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// key.set_iv([ @@ -178,7 +177,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// key.set_iv([ @@ -207,7 +206,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// key.set_key_format("key_format_attribute"); @@ -230,7 +229,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// key.set_key_format("key_format_attribute"); @@ -257,7 +256,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// key.set_key_format_versions("1/2/3/4/5"); @@ -280,7 +279,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// key.set_key_format_versions("1/2/3/4/5"); @@ -301,7 +300,7 @@ impl DecryptionKey { /// /// let mut key = DecryptionKey::new( /// EncryptionMethod::Aes128, - /// "https://www.example.com".parse().unwrap() + /// "https://www.example.com/" /// ); /// /// assert_eq!( @@ -333,7 +332,7 @@ impl FromStr for DecryptionKey { for (key, value) in input.parse::()? { match key.as_str() { "METHOD" => method = Some((value.parse())?), - "URI" => uri = Some(unquote(value).parse()?), + "URI" => uri = Some(unquote(value)), "IV" => iv = Some((value.parse())?), "KEYFORMAT" => key_format = Some(unquote(value)), "KEYFORMATVERSIONS" => key_format_versions = Some(unquote(value)), @@ -391,7 +390,7 @@ mod test { fn test_builder() { let key = DecryptionKey::builder() .method(EncryptionMethod::Aes128) - .uri("https://www.example.com".parse::().unwrap()) + .uri("https://www.example.com/") .iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, ]) @@ -409,7 +408,7 @@ mod test { fn test_display() { let mut key = DecryptionKey::new( EncryptionMethod::Aes128, - "https://www.example.com/hls-key/key.bin".parse().unwrap(), + "https://www.example.com/hls-key/key.bin", ); key.set_iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, @@ -432,13 +431,13 @@ mod test { .unwrap(), DecryptionKey::new( EncryptionMethod::Aes128, - "https://priv.example.com/key.php?r=52".parse().unwrap() + "https://priv.example.com/key.php?r=52" ) ); let mut key = DecryptionKey::new( EncryptionMethod::Aes128, - "https://www.example.com/hls-key/key.bin".parse().unwrap(), + "https://www.example.com/hls-key/key.bin", ); key.set_iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, @@ -453,10 +452,7 @@ mod test { key ); - let mut key = DecryptionKey::new( - EncryptionMethod::Aes128, - "http://www.example.com".parse().unwrap(), - ); + let mut key = DecryptionKey::new(EncryptionMethod::Aes128, "http://www.example.com"); key.set_iv([ 16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82, ]); diff --git a/tests/playlist.rs b/tests/playlist.rs index b61068a..25ccabd 100644 --- a/tests/playlist.rs +++ b/tests/playlist.rs @@ -36,11 +36,11 @@ fn test_simple_playlist() { assert_eq!( media_playlist.segments()[0].uri(), - &"http://media.example.com/entire1.ts".parse().unwrap() + &"http://media.example.com/entire1.ts".to_string() ); assert_eq!( media_playlist.segments()[1].uri(), - &"http://media.example.com/entire2.ts".parse().unwrap() + &"http://media.example.com/entire2.ts".to_string() ); }