diff --git a/src/lib.rs b/src/lib.rs index fc1726f..3659b68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ missing_docs, missing_copy_implementations, missing_debug_implementations, - trivial_casts, // TODO (needed?) + trivial_casts, trivial_numeric_casts )] //! [HLS] m3u8 parser/generator. diff --git a/src/media_playlist.rs b/src/media_playlist.rs index ea1e57d..124e45f 100644 --- a/src/media_playlist.rs +++ b/src/media_playlist.rs @@ -391,6 +391,7 @@ fn parse_media_playlist( segment = MediaSegment::builder(); has_partial_segment = false; } + _ => {} } } diff --git a/src/tags/master_playlist/media.rs b/src/tags/master_playlist/media.rs index 7a5e2cc..d122930 100644 --- a/src/tags/master_playlist/media.rs +++ b/src/tags/master_playlist/media.rs @@ -12,10 +12,10 @@ use crate::{Error, RequiredVersion}; /// # [4.4.5.1. EXT-X-MEDIA] /// /// The [`ExtXMedia`] tag is used to relate [`Media Playlist`]s, -/// that contain alternative Renditions of the same content. +/// that contain alternative renditions of the same content. /// /// For example, three [`ExtXMedia`] tags can be used to identify audio-only -/// [`Media Playlist`]s, that contain English, French, and Spanish Renditions +/// [`Media Playlist`]s, that contain English, French, and Spanish renditions /// of the same presentation. Or, two [`ExtXMedia`] tags can be used to /// identify video-only [`Media Playlist`]s that show two different camera /// angles. @@ -35,7 +35,7 @@ pub struct ExtXMedia { /// This attribute is **required**. #[shorthand(enable(copy))] media_type: MediaType, - /// The `URI` that identifies the [`Media Playlist`]. + /// An `URI` to a [`Media Playlist`]. /// /// # Note /// @@ -184,14 +184,18 @@ impl ExtXMedia { pub(crate) const PREFIX: &'static str = "#EXT-X-MEDIA:"; /// Makes a new [`ExtXMedia`] tag. - pub fn new(media_type: MediaType, group_id: T, name: T) -> Self { + pub fn new(media_type: MediaType, group_id: T, name: K) -> Self + where + T: Into, + K: Into, + { Self { media_type, uri: None, - group_id: group_id.to_string(), + group_id: group_id.into(), language: None, assoc_language: None, - name: name.to_string(), + name: name.into(), is_default: false, is_autoselect: false, is_forced: false, diff --git a/src/tags/master_playlist/session_data.rs b/src/tags/master_playlist/session_data.rs index 206b4da..9e53e8b 100644 --- a/src/tags/master_playlist/session_data.rs +++ b/src/tags/master_playlist/session_data.rs @@ -13,7 +13,7 @@ use crate::{Error, RequiredVersion}; #[derive(Hash, Eq, Ord, Debug, PartialEq, Clone, PartialOrd)] pub enum SessionData { /// A String, that contains the data identified by - /// [`data_id`]. + /// [`data_id`](ExtXSessionData::data_id). /// If a [`language`] is specified, the value /// should contain a human-readable string written in the specified /// language. @@ -51,7 +51,7 @@ pub struct ExtXSessionData { /// /// [reverse DNS]: https://en.wikipedia.org/wiki/Reverse_domain_name_notation data_id: String, - /// The data associated with the [`data_id`]. + /// The data associated with the [`data_id`](ExtXSessionData::data_id). /// For more information look [`here`](SessionData). /// /// # Note @@ -70,6 +70,7 @@ impl ExtXSessionData { /// Makes a new [`ExtXSessionData`] tag. /// /// # Example + /// /// ``` /// use hls_m3u8::tags::{ExtXSessionData, SessionData}; /// @@ -78,9 +79,9 @@ impl ExtXSessionData { /// SessionData::Uri("https://www.example.com/".to_string()), /// ); /// ``` - pub fn new(data_id: T, data: SessionData) -> Self { + pub fn new>(data_id: T, data: SessionData) -> Self { Self { - data_id: data_id.to_string(), + data_id: data_id.into(), data, language: None, } @@ -89,6 +90,7 @@ impl ExtXSessionData { /// Returns a new Builder for [`ExtXSessionData`]. /// /// # Example + /// /// ``` /// use hls_m3u8::tags::{ExtXSessionData, SessionData}; /// @@ -123,11 +125,15 @@ impl ExtXSessionData { /// "english", /// ); /// ``` - pub fn with_language(data_id: T, data: SessionData, language: T) -> Self { + pub fn with_language(data_id: T, data: SessionData, language: K) -> Self + where + T: Into, + K: Into, + { Self { - data_id: data_id.to_string(), + data_id: data_id.into(), data, - language: Some(language.to_string()), + language: Some(language.into()), } } } diff --git a/src/tags/master_playlist/session_key.rs b/src/tags/master_playlist/session_key.rs index a46b015..ecbd270 100644 --- a/src/tags/master_playlist/session_key.rs +++ b/src/tags/master_playlist/session_key.rs @@ -40,7 +40,7 @@ impl ExtXSessionKey { /// /// let session_key = ExtXSessionKey::new(EncryptionMethod::Aes128, "https://www.example.com/"); /// ``` - pub fn new(method: EncryptionMethod, uri: T) -> Self { + pub fn new>(method: EncryptionMethod, uri: T) -> Self { if method == EncryptionMethod::None { panic!("The EncryptionMethod is not allowed to be None"); } @@ -49,8 +49,8 @@ impl ExtXSessionKey { } } -/// This tag requires the version returned by -/// [`DecryptionKey::required_version`]. +/// This tag requires the same [`ProtocolVersion`] that is returned by +/// `DecryptionKey::required_version`. impl RequiredVersion for ExtXSessionKey { fn required_version(&self) -> ProtocolVersion { self.0.required_version() } } diff --git a/src/tags/media_playlist/discontinuity_sequence.rs b/src/tags/media_playlist/discontinuity_sequence.rs index d3ec395..cf71520 100644 --- a/src/tags/media_playlist/discontinuity_sequence.rs +++ b/src/tags/media_playlist/discontinuity_sequence.rs @@ -1,6 +1,8 @@ use std::fmt; use std::str::FromStr; +use shorthand::ShortHand; + use crate::types::ProtocolVersion; use crate::utils::tag; use crate::RequiredVersion; @@ -15,22 +17,9 @@ use crate::RequiredVersion; /// [`Media Playlist`]: crate::MediaPlaylist /// [4.4.3.3. EXT-X-DISCONTINUITY-SEQUENCE]: /// https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-04#section-4.4.3.3 -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub struct ExtXDiscontinuitySequence(u64); - -impl ExtXDiscontinuitySequence { - pub(crate) const PREFIX: &'static str = "#EXT-X-DISCONTINUITY-SEQUENCE:"; - - /// Makes a new [ExtXDiscontinuitySequence] tag. - /// - /// # Example - /// - /// ``` - /// # use hls_m3u8::tags::ExtXDiscontinuitySequence; - /// let discontinuity_sequence = ExtXDiscontinuitySequence::new(5); - /// ``` - pub const fn new(seq_num: u64) -> Self { Self(seq_num) } - +#[derive(ShortHand, Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[shorthand(enable(must_use))] +pub struct ExtXDiscontinuitySequence { /// Returns the discontinuity sequence number of /// the first media segment that appears in the associated playlist. /// @@ -38,27 +27,26 @@ impl ExtXDiscontinuitySequence { /// /// ``` /// # use hls_m3u8::tags::ExtXDiscontinuitySequence; - /// let discontinuity_sequence = ExtXDiscontinuitySequence::new(5); - /// - /// assert_eq!(discontinuity_sequence.seq_num(), 5); - /// ``` - pub const fn seq_num(self) -> u64 { self.0 } - - /// Sets the sequence number. - /// - /// # Example - /// - /// ``` - /// # use hls_m3u8::tags::ExtXDiscontinuitySequence; /// let mut discontinuity_sequence = ExtXDiscontinuitySequence::new(5); /// /// discontinuity_sequence.set_seq_num(10); /// assert_eq!(discontinuity_sequence.seq_num(), 10); /// ``` - pub fn set_seq_num(&mut self, value: u64) -> &mut Self { - self.0 = value; - self - } + seq_num: u64, +} + +impl ExtXDiscontinuitySequence { + pub(crate) const PREFIX: &'static str = "#EXT-X-DISCONTINUITY-SEQUENCE:"; + + /// Makes a new [`ExtXDiscontinuitySequence`] tag. + /// + /// # Example + /// + /// ``` + /// # use hls_m3u8::tags::ExtXDiscontinuitySequence; + /// let discontinuity_sequence = ExtXDiscontinuitySequence::new(5); + /// ``` + pub const fn new(seq_num: u64) -> Self { Self { seq_num } } } /// This tag requires [`ProtocolVersion::V1`]. @@ -69,7 +57,7 @@ impl RequiredVersion for ExtXDiscontinuitySequence { impl fmt::Display for ExtXDiscontinuitySequence { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // - write!(f, "{}{}", Self::PREFIX, self.0) + write!(f, "{}{}", Self::PREFIX, self.seq_num) } } diff --git a/src/tags/media_segment/date_range.rs b/src/tags/media_segment/date_range.rs index 61a2bfd..f357c9a 100644 --- a/src/tags/media_segment/date_range.rs +++ b/src/tags/media_segment/date_range.rs @@ -121,7 +121,7 @@ pub struct ExtXDateRange { impl ExtXDateRangeBuilder { /// Inserts a key value pair. - pub fn insert_client_attribute>( + pub fn insert_client_attribute, V: Into>( &mut self, key: K, value: V, @@ -131,7 +131,7 @@ impl ExtXDateRangeBuilder { } if let Some(client_attributes) = &mut self.client_attributes { - client_attributes.insert(key.to_string(), value.into()); + client_attributes.insert(key.into(), value.into()); } else { unreachable!(); } @@ -160,9 +160,9 @@ impl ExtXDateRange { /// .and_hms_milli(14, 54, 23, 31), /// ); /// ``` - pub fn new(id: T, start_date: DateTime) -> Self { + pub fn new>(id: T, start_date: DateTime) -> Self { Self { - id: id.to_string(), + id: id.into(), class: None, start_date, end_date: None, @@ -281,7 +281,7 @@ impl fmt::Display for ExtXDateRange { write!( f, ",END-DATE={}", - quote(value.to_rfc3339_opts(SecondsFormat::AutoSi, true)) + quote(&value.to_rfc3339_opts(SecondsFormat::AutoSi, true)) )?; } diff --git a/src/tags/media_segment/inf.rs b/src/tags/media_segment/inf.rs index 39d4591..8d47376 100644 --- a/src/tags/media_segment/inf.rs +++ b/src/tags/media_segment/inf.rs @@ -49,10 +49,10 @@ impl ExtInf { /// /// let ext_inf = ExtInf::with_title(Duration::from_secs(5), "title"); /// ``` - pub fn with_title(duration: Duration, title: T) -> Self { + pub fn with_title>(duration: Duration, title: T) -> Self { Self { duration, - title: Some(title.to_string()), + title: Some(title.into()), } } @@ -156,9 +156,9 @@ impl FromStr for ExtInf { let duration = Duration::from_secs_f64(input.next().unwrap().parse()?); let title = input .next() - .map(|value| value.trim()) + .map(str::trim) .filter(|value| !value.is_empty()) - .map(|value| value.to_string()); + .map(ToString::to_string); Ok(Self { duration, title }) } diff --git a/src/tags/media_segment/key.rs b/src/tags/media_segment/key.rs index acf3e02..d44dec2 100644 --- a/src/tags/media_segment/key.rs +++ b/src/tags/media_segment/key.rs @@ -45,7 +45,7 @@ impl ExtXKey { /// "#EXT-X-KEY:METHOD=AES-128,URI=\"https://www.example.com/\"" /// ); /// ``` - pub fn new(method: EncryptionMethod, uri: T) -> Self { + pub fn new>(method: EncryptionMethod, uri: T) -> Self { Self(DecryptionKey::new(method, uri)) } @@ -87,8 +87,8 @@ impl ExtXKey { pub fn is_empty(&self) -> bool { self.0.method() == EncryptionMethod::None } } -/// This tag requires the [`ProtocolVersion`] returned by -/// [`DecryptionKey::required_version`]. +/// This tag requires the same [`ProtocolVersion`] that is returned by +/// `DecryptionKey::required_version`. impl RequiredVersion for ExtXKey { fn required_version(&self) -> ProtocolVersion { self.0.required_version() } } @@ -103,7 +103,10 @@ impl FromStr for ExtXKey { } impl fmt::Display for ExtXKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}{}", Self::PREFIX, self.0) } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // + write!(f, "{}{}", Self::PREFIX, self.0) + } } #[cfg(test)] diff --git a/src/tags/media_segment/map.rs b/src/tags/media_segment/map.rs index ec8a50e..1ab3a93 100644 --- a/src/tags/media_segment/map.rs +++ b/src/tags/media_segment/map.rs @@ -69,9 +69,9 @@ impl ExtXMap { /// # use hls_m3u8::tags::ExtXMap; /// let map = ExtXMap::new("https://prod.mediaspace.com/init.bin"); /// ``` - pub fn new(uri: T) -> Self { + pub fn new>(uri: T) -> Self { Self { - uri: uri.to_string(), + uri: uri.into(), range: None, keys: vec![], } @@ -90,9 +90,9 @@ impl ExtXMap { /// ByteRange::new(9, Some(2)), /// ); /// ``` - pub fn with_range(uri: T, range: ByteRange) -> Self { + pub fn with_range>(uri: T, range: ByteRange) -> Self { Self { - uri: uri.to_string(), + uri: uri.into(), range: Some(range), keys: vec![], } diff --git a/src/tags/shared/independent_segments.rs b/src/tags/shared/independent_segments.rs index 570c6bf..4bf445f 100644 --- a/src/tags/shared/independent_segments.rs +++ b/src/tags/shared/independent_segments.rs @@ -7,8 +7,13 @@ use crate::{Error, RequiredVersion}; /// # [4.3.5.1. EXT-X-INDEPENDENT-SEGMENTS] /// +/// The [`ExtXIndependentSegments`] tag signals that all media samples in a +/// [`MediaSegment`] can be decoded without information from other segments. +/// /// [4.3.5.1. EXT-X-INDEPENDENT-SEGMENTS]: /// https://tools.ietf.org/html/rfc8216#section-4.3.5.1 +/// +/// [`MediaSegment`]: crate::MediaSegment #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ExtXIndependentSegments; diff --git a/src/tags/shared/mod.rs b/src/tags/shared/mod.rs index 956efe7..ce2f2d2 100644 --- a/src/tags/shared/mod.rs +++ b/src/tags/shared/mod.rs @@ -1,3 +1,11 @@ +//! The tags in this section can appear in either Master Playlists or +//! Media Playlists. If one of these tags appears in a Master Playlist, +//! it should not appear in any Media Playlist referenced by that Master +//! Playlist. A tag that appears in both must have the same value; +//! otherwise, clients should ignore the value in the Media Playlist(s). +//! +//! These tags must not appear more than once in a Playlist. If a tag +//! appears more than once, clients must fail to parse the Playlist. mod independent_segments; mod start; diff --git a/src/types/decryption_key.rs b/src/types/decryption_key.rs index 526624e..275899a 100644 --- a/src/types/decryption_key.rs +++ b/src/types/decryption_key.rs @@ -18,7 +18,9 @@ use crate::{Error, RequiredVersion}; #[builder(setter(into), build_fn(validate = "Self::validate"))] #[shorthand(enable(must_use, into))] pub struct DecryptionKey { - /// The [`EncryptionMethod`]. + /// HLS supports multiple encryption methods for a segment. + /// + /// For example `AES-128`. /// /// # Example /// @@ -41,9 +43,10 @@ pub struct DecryptionKey { /// This attribute is required. #[shorthand(enable(copy))] pub(crate) method: EncryptionMethod, - /// An `URI`, that specifies how to obtain the key. + /// An `URI` that specifies how to obtain the key. /// /// # Example + /// /// ``` /// # use hls_m3u8::types::DecryptionKey; /// use hls_m3u8::types::EncryptionMethod; @@ -63,8 +66,10 @@ pub struct DecryptionKey { /// This attribute is required, if the [`EncryptionMethod`] is not `None`. #[builder(setter(into, strip_option), default)] pub(crate) uri: Option, - /// The IV (Initialization Vector) for the key. + /// An IV (initialization vector) is used to prevent repetitions between + /// segments of encrypted data. /// + /// /// /// # Example /// @@ -90,7 +95,7 @@ pub struct DecryptionKey { // TODO: workaround for https://github.com/Luro02/shorthand/issues/20 #[shorthand(enable(copy), disable(option_as_ref))] pub(crate) iv: Option<[u8; 16]>, - /// [`KeyFormat`] specifies how the key is + /// The [`KeyFormat`] specifies how the key is /// represented in the resource identified by the `URI`. /// /// # Example @@ -157,23 +162,25 @@ impl DecryptionKey { /// /// let key = DecryptionKey::new(EncryptionMethod::Aes128, "https://www.example.com/"); /// ``` - pub fn new(method: EncryptionMethod, uri: T) -> Self { + #[doc(hidden)] + pub fn new>(method: EncryptionMethod, uri: T) -> Self { Self { method, - uri: Some(uri.to_string()), + uri: Some(uri.into()), iv: None, key_format: None, key_format_versions: None, } } - /// Returns a Builder to build a [DecryptionKey]. + /// Returns a Builder to build a [`DecryptionKey`]. pub fn builder() -> DecryptionKeyBuilder { DecryptionKeyBuilder::default() } } /// This tag requires [`ProtocolVersion::V5`], if [`KeyFormat`] or /// [`KeyFormatVersions`] is specified and [`ProtocolVersion::V2`] if an iv is /// specified. +/// /// Otherwise [`ProtocolVersion::V1`] is required. impl RequiredVersion for DecryptionKey { fn required_version(&self) -> ProtocolVersion { @@ -187,6 +194,7 @@ impl RequiredVersion for DecryptionKey { } } +#[doc(hidden)] impl FromStr for DecryptionKey { type Err = Error; diff --git a/src/types/encryption_method.rs b/src/types/encryption_method.rs index acb4cc0..6d4f1ea 100644 --- a/src/types/encryption_method.rs +++ b/src/types/encryption_method.rs @@ -5,15 +5,16 @@ use strum::{Display, EnumString}; /// See: [4.3.2.4. EXT-X-KEY] /// /// [4.3.2.4. EXT-X-KEY]: https://tools.ietf.org/html/rfc8216#section-4.3.2.4 +#[non_exhaustive] #[allow(missing_docs)] #[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)] #[strum(serialize_all = "SCREAMING-KEBAB-CASE")] pub enum EncryptionMethod { /// `None` means that the [`MediaSegment`]s are not encrypted. /// - /// [MediaSegment]: crate::MediaSegment + /// [`MediaSegment`]: crate::MediaSegment None, - /// `Aes128` signals that the [MediaSegment]s are completely encrypted + /// `Aes128` signals that the [`MediaSegment`]s are completely encrypted /// using the Advanced Encryption Standard ([AES-128]) with a 128-bit /// key, Cipher Block Chaining (CBC), and /// [Public-Key Cryptography Standards #7 (PKCS7)] padding. @@ -22,14 +23,14 @@ pub enum EncryptionMethod { /// Initialization Vector (IV) attribute value or the Media Sequence /// Number as the IV. /// - /// [MediaSegment]: crate::MediaSegment - /// [AES_128]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf + /// [`MediaSegment`]: crate::MediaSegment + /// [AES-128]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf /// [Public-Key Cryptography Standards #7 (PKCS7)]: https://tools.ietf.org/html/rfc5652 #[strum(serialize = "AES-128")] Aes128, - /// `SampleAes` means that the [MediaSegment]s + /// `SampleAes` means that the [`MediaSegment`]s /// contain media samples, such as audio or video, that are encrypted - /// using the Advanced Encryption Standard ([AES_128]). How these media + /// using the Advanced Encryption Standard ([`AES-128`]). How these media /// streams are encrypted and encapsulated in a segment depends on the /// media encoding and the media format of the segment. fMP4 Media /// Segments are encrypted using the 'cbcs' scheme of @@ -39,7 +40,7 @@ pub enum EncryptionMethod { /// Live Streaming (HLS) [SampleEncryption specification]. /// /// [`MediaSegment`]: crate::MediaSegment - /// [AES-128]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf + /// [`AES-128`]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf /// [Common Encryption]: https://tools.ietf.org/html/rfc8216#ref-COMMON_ENC /// [H.264]: https://tools.ietf.org/html/rfc8216#ref-H_264 /// [AAC]: https://tools.ietf.org/html/rfc8216#ref-ISO_14496 diff --git a/src/types/hdcp_level.rs b/src/types/hdcp_level.rs index 1d03e2a..9796cfd 100644 --- a/src/types/hdcp_level.rs +++ b/src/types/hdcp_level.rs @@ -5,6 +5,7 @@ use strum::{Display, EnumString}; /// See: [4.3.4.2. EXT-X-STREAM-INF] /// /// [4.3.4.2. EXT-X-STREAM-INF]: https://tools.ietf.org/html/rfc8216#section-4.3.4.2 +#[non_exhaustive] #[allow(missing_docs)] #[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)] #[strum(serialize_all = "SCREAMING-KEBAB-CASE")] diff --git a/src/types/in_stream_id.rs b/src/types/in_stream_id.rs index b39ce5c..6f1fd1a 100644 --- a/src/types/in_stream_id.rs +++ b/src/types/in_stream_id.rs @@ -5,9 +5,11 @@ use strum::{Display, EnumString}; /// See: [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 +#[non_exhaustive] #[allow(missing_docs)] -#[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)] #[strum(serialize_all = "UPPERCASE")] +#[derive(Ord, PartialOrd, Debug, Clone, Copy, PartialEq, Eq, Hash, Display, EnumString)] +#[non_exhaustive] pub enum InStreamId { Cc1, Cc2, diff --git a/src/types/key_format.rs b/src/types/key_format.rs index 3995db0..f3b995a 100644 --- a/src/types/key_format.rs +++ b/src/types/key_format.rs @@ -7,6 +7,7 @@ use crate::{Error, RequiredVersion}; /// [`KeyFormat`] specifies, how the key is represented in the /// resource identified by the `URI`. +#[non_exhaustive] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub enum KeyFormat { /// The key is a single packed array of 16 octets in binary format. @@ -28,7 +29,7 @@ impl FromStr for KeyFormat { } impl fmt::Display for KeyFormat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", quote("identity")) } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", quote(&"identity")) } } /// This tag requires [`ProtocolVersion::V5`]. diff --git a/src/types/key_format_versions.rs b/src/types/key_format_versions.rs index 7fada99..0bd1189 100644 --- a/src/types/key_format_versions.rs +++ b/src/types/key_format_versions.rs @@ -31,7 +31,10 @@ impl KeyFormatVersions { /// Returns `true`, if [`KeyFormatVersions`] has the default value of /// `vec![1]`. - pub fn is_default(&self) -> bool { self.0 == vec![1] && self.0.len() == 1 || self.0.is_empty() } + pub fn is_default(&self) -> bool { + // + self.0 == vec![1] && self.0.len() == 1 || self.0.is_empty() + } } impl Default for KeyFormatVersions { @@ -73,7 +76,7 @@ impl fmt::Display for KeyFormatVersions { // vec![1, 2, 3] -> "1/2/3" self.0 .iter() - .map(|v| v.to_string()) + .map(ToString::to_string) .collect::>() .join("/") ) diff --git a/src/types/media_type.rs b/src/types/media_type.rs index 19a999f..c18cae3 100644 --- a/src/types/media_type.rs +++ b/src/types/media_type.rs @@ -1,6 +1,7 @@ use strum::{Display, EnumString}; /// Specifies the media type. +#[non_exhaustive] #[allow(missing_docs)] #[derive(Ord, PartialOrd, Display, EnumString, Debug, Clone, Copy, PartialEq, Eq, Hash)] #[strum(serialize_all = "SCREAMING-KEBAB-CASE")] diff --git a/src/types/protocol_version.rs b/src/types/protocol_version.rs index 5776ac1..c9e1af7 100644 --- a/src/types/protocol_version.rs +++ b/src/types/protocol_version.rs @@ -10,6 +10,7 @@ use crate::Error; /// /// [7. Protocol Version Compatibility]: /// https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-05#section-7 +#[non_exhaustive] #[allow(missing_docs)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ProtocolVersion { diff --git a/src/types/value.rs b/src/types/value.rs index 98eebe0..2a20662 100644 --- a/src/types/value.rs +++ b/src/types/value.rs @@ -6,8 +6,9 @@ use hex; use crate::utils::{quote, unquote}; use crate::Error; -#[derive(Debug, Clone, PartialEq, PartialOrd)] /// A [`Value`]. +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum Value { /// A [`String`]. String(String), diff --git a/src/utils.rs b/src/utils.rs index 989d029..3b2a375 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,5 @@ use crate::Error; +use core::iter; macro_rules! required_version { ( $( $tag:expr ),* ) => { @@ -22,14 +23,7 @@ pub(crate) fn parse_iv_from_str(input: &str) -> crate::Result<[u8; 16]> { let mut result = [0; 16]; - // TODO: - // hex::decode_to_slice(value.as_bytes()[2..], &mut result)?; - - for (i, c) in input.as_bytes().chunks(2).skip(1).enumerate() { - let d = core::str::from_utf8(c).map_err(Error::custom)?; - let b = u8::from_str_radix(d, 16).map_err(Error::custom)?; - result[i] = b; - } + hex::decode_to_slice(&input.as_bytes()[2..], &mut result).map_err(Error::hex)?; Ok(result) } @@ -50,19 +44,23 @@ pub(crate) fn parse_yes_or_no>(s: T) -> crate::Result { /// /// Therefore it is safe to simply remove any occurence of those characters. /// [rfc8216#section-4.2](https://tools.ietf.org/html/rfc8216#section-4.2) -pub(crate) fn unquote(value: T) -> String { +pub(crate) fn unquote>(value: T) -> String { value - .to_string() - .replace("\"", "") - .replace("\n", "") - .replace("\r", "") + .as_ref() + .chars() + .filter(|c| *c != '"' && *c != '\n' && *c != '\r') + .collect() } /// Puts a string inside quotes. +#[allow(clippy::needless_pass_by_value)] pub(crate) fn quote(value: T) -> String { // the replace is for the case, that quote is called on an already quoted // string, which could cause problems! - format!("\"{}\"", value.to_string().replace("\"", "")) + iter::once('"') + .chain(value.to_string().chars().filter(|c| *c != '"')) + .chain(iter::once('"')) + .collect() } /// Checks, if the given tag is at the start of the input. If this is the case,