1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-11-25 08:31:00 +00:00

added RequiredVersion trait

This commit is contained in:
Luro02 2019-09-22 10:57:28 +02:00
parent b2c9f2db36
commit 81f9a421fe
28 changed files with 550 additions and 293 deletions

View file

@ -61,10 +61,10 @@ impl FromStr for AttributePairs {
let key = pair[0].to_uppercase();
let value = pair[1].to_string();
result.insert(key.to_string(), value.to_string());
result.insert(key.trim().to_string(), value.trim().to_string());
}
#[cfg(test)]
#[cfg(test)] // this is very useful, when a test fails!
dbg!(&result);
Ok(result)
}

View file

@ -10,7 +10,7 @@ use crate::tags::{
ExtM3u, ExtXIFrameStreamInf, ExtXIndependentSegments, ExtXMedia, ExtXSessionData,
ExtXSessionKey, ExtXStart, ExtXStreamInf, ExtXVersion,
};
use crate::types::{ClosedCaptions, MediaType, ProtocolVersion};
use crate::types::{ClosedCaptions, MediaType, ProtocolVersion, RequiredVersion};
use crate::Error;
/// Master playlist.
@ -92,6 +92,12 @@ impl MasterPlaylist {
}
}
impl RequiredVersion for MasterPlaylist {
fn required_version(&self) -> ProtocolVersion {
self.version_tag.version()
}
}
impl MasterPlaylistBuilder {
fn validate(&self) -> Result<(), String> {
let required_version = self.required_version();
@ -118,43 +124,43 @@ impl MasterPlaylistBuilder {
.chain(
self.independent_segments_tag
.iter()
.map(|t| t.iter().map(|t| t.requires_version()))
.map(|t| t.iter().map(|t| t.required_version()))
.flatten(),
)
.chain(
self.start_tag
.iter()
.map(|t| t.iter().map(|t| t.requires_version()))
.map(|t| t.iter().map(|t| t.required_version()))
.flatten(),
)
.chain(
self.media_tags
.iter()
.map(|t| t.iter().map(|t| t.requires_version()))
.map(|t| t.iter().map(|t| t.required_version()))
.flatten(),
)
.chain(
self.stream_inf_tags
.iter()
.map(|t| t.iter().map(|t| t.requires_version()))
.map(|t| t.iter().map(|t| t.required_version()))
.flatten(),
)
.chain(
self.i_frame_stream_inf_tags
.iter()
.map(|t| t.iter().map(|t| t.requires_version()))
.map(|t| t.iter().map(|t| t.required_version()))
.flatten(),
)
.chain(
self.session_data_tags
.iter()
.map(|t| t.iter().map(|t| t.requires_version()))
.map(|t| t.iter().map(|t| t.required_version()))
.flatten(),
)
.chain(
self.session_key_tags
.iter()
.map(|t| t.iter().map(|t| t.requires_version()))
.map(|t| t.iter().map(|t| t.required_version()))
.flatten(),
)
.max()

View file

@ -11,7 +11,7 @@ use crate::tags::{
ExtM3u, ExtXDiscontinuitySequence, ExtXEndList, ExtXIFramesOnly, ExtXIndependentSegments,
ExtXMediaSequence, ExtXPlaylistType, ExtXStart, ExtXTargetDuration, ExtXVersion,
};
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::Error;
/// Media playlist.
@ -142,60 +142,60 @@ impl MediaPlaylistBuilder {
.chain(
self.target_duration_tag
.iter()
.map(|t| t.requires_version()),
.map(|t| t.required_version()),
)
.chain(self.media_sequence_tag.iter().map(|t| {
if let Some(p) = t {
p.requires_version()
p.required_version()
} else {
ProtocolVersion::V1
}
}))
.chain(self.discontinuity_sequence_tag.iter().map(|t| {
if let Some(p) = t {
p.requires_version()
p.required_version()
} else {
ProtocolVersion::V1
}
}))
.chain(self.playlist_type_tag.iter().map(|t| {
if let Some(p) = t {
p.requires_version()
p.required_version()
} else {
ProtocolVersion::V1
}
}))
.chain(self.i_frames_only_tag.iter().map(|t| {
if let Some(p) = t {
p.requires_version()
p.required_version()
} else {
ProtocolVersion::V1
}
}))
.chain(self.independent_segments_tag.iter().map(|t| {
if let Some(p) = t {
p.requires_version()
p.required_version()
} else {
ProtocolVersion::V1
}
}))
.chain(self.start_tag.iter().map(|t| {
if let Some(p) = t {
p.requires_version()
p.required_version()
} else {
ProtocolVersion::V1
}
}))
.chain(self.end_list_tag.iter().map(|t| {
if let Some(p) = t {
p.requires_version()
p.required_version()
} else {
ProtocolVersion::V1
}
}))
.chain(self.segments.iter().map(|t| {
t.iter()
.map(|s| s.requires_version())
.map(|s| s.required_version())
.max()
.unwrap_or(ProtocolVersion::V1)
}))

View file

@ -6,7 +6,7 @@ use derive_builder::Builder;
use crate::tags::{
ExtInf, ExtXByteRange, ExtXDateRange, ExtXDiscontinuity, ExtXKey, ExtXMap, ExtXProgramDateTime,
};
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
/// Media segment.
#[derive(Debug, Clone, Builder)]
@ -118,21 +118,22 @@ impl MediaSegment {
pub fn key_tags(&self) -> &[ExtXKey] {
&self.key_tags
}
}
/// Returns the protocol compatibility version that this segment requires.
pub fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for MediaSegment {
fn required_version(&self) -> ProtocolVersion {
iter::empty()
.chain(self.key_tags.iter().map(|t| t.requires_version()))
.chain(self.map_tag.iter().map(|t| t.requires_version()))
.chain(self.byte_range_tag.iter().map(|t| t.requires_version()))
.chain(self.date_range_tag.iter().map(|t| t.requires_version()))
.chain(self.discontinuity_tag.iter().map(|t| t.requires_version()))
.chain(self.key_tags.iter().map(|t| t.required_version()))
.chain(self.map_tag.iter().map(|t| t.required_version()))
.chain(self.byte_range_tag.iter().map(|t| t.required_version()))
.chain(self.date_range_tag.iter().map(|t| t.required_version()))
.chain(self.discontinuity_tag.iter().map(|t| t.required_version()))
.chain(
self.program_date_time_tag
.iter()
.map(|t| t.requires_version()),
.map(|t| t.required_version()),
)
.chain(iter::once(self.inf_tag.requires_version()))
.chain(iter::once(self.inf_tag.required_version()))
.max()
.unwrap_or(ProtocolVersion::V7)
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -13,9 +13,10 @@ pub struct ExtM3u;
impl ExtM3u {
pub(crate) const PREFIX: &'static str = "#EXTM3U";
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtM3u {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -50,7 +51,7 @@ mod test {
}
#[test]
fn test_requires_version() {
assert_eq!(ExtM3u.requires_version(), ProtocolVersion::V1);
fn test_required_version() {
assert_eq!(ExtM3u.required_version(), ProtocolVersion::V1);
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -20,12 +20,24 @@ impl ExtXVersion {
}
/// Returns the protocol compatibility version of the playlist containing this tag.
///
/// # Example
/// ```
/// # use hls_m3u8::tags::ExtXVersion;
/// use hls_m3u8::types::ProtocolVersion;
///
/// assert_eq!(
/// ExtXVersion::new(ProtocolVersion::V6).version(),
/// ProtocolVersion::V6
/// );
/// ```
pub const fn version(&self) -> ProtocolVersion {
self.0
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXVersion {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -78,18 +90,10 @@ mod test {
}
#[test]
fn test_requires_version() {
fn test_required_version() {
assert_eq!(
ExtXVersion::new(ProtocolVersion::V6).requires_version(),
ExtXVersion::new(ProtocolVersion::V6).required_version(),
ProtocolVersion::V1
);
}
#[test]
fn test_version() {
assert_eq!(
ExtXVersion::new(ProtocolVersion::V6).version(),
ProtocolVersion::V6
);
}
}

View file

@ -3,12 +3,23 @@ use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{ProtocolVersion, StreamInf};
use crate::types::{ProtocolVersion, RequiredVersion, StreamInf};
use crate::utils::{quote, tag, unquote};
use crate::Error;
/// [4.3.4.3. EXT-X-I-FRAME-STREAM-INF]
/// # [4.3.4.3. EXT-X-I-FRAME-STREAM-INF]
/// The [ExtXIFrameStreamInf] tag identifies a [Media Playlist] file
/// containing the I-frames of a multimedia presentation. It stands
/// alone, in that it does not apply to a particular URI in the [Master Playlist].
///
/// Its format is:
///
/// ```text
/// #EXT-X-I-FRAME-STREAM-INF:<attribute-list>
/// ```
///
/// [Master Playlist]: crate::MasterPlaylist
/// [Media Playlist]: crate::MediaPlaylist
/// [4.3.4.3. EXT-X-I-FRAME-STREAM-INF]: https://tools.ietf.org/html/rfc8216#section-4.3.4.3
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExtXIFrameStreamInf {
@ -19,7 +30,7 @@ pub struct ExtXIFrameStreamInf {
impl ExtXIFrameStreamInf {
pub(crate) const PREFIX: &'static str = "#EXT-X-I-FRAME-STREAM-INF:";
/// Makes a new `ExtXIFrameStreamInf` tag.
/// Makes a new [ExtXIFrameStreamInf] tag.
pub fn new<T: ToString>(uri: T, bandwidth: u64) -> Self {
ExtXIFrameStreamInf {
uri: uri.to_string(),
@ -55,9 +66,10 @@ impl ExtXIFrameStreamInf {
self.uri = value.to_string();
self
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXIFrameStreamInf {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -133,9 +145,9 @@ mod test {
}
#[test]
fn test_requires_version() {
fn test_required_version() {
assert_eq!(
ExtXIFrameStreamInf::new("foo", 1000).requires_version(),
ExtXIFrameStreamInf::new("foo", 1000).required_version(),
ProtocolVersion::V1
);
}

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{InStreamId, MediaType, ProtocolVersion};
use crate::types::{InStreamId, MediaType, ProtocolVersion, RequiredVersion};
use crate::utils::{parse_yes_or_no, quote, tag, unquote};
use crate::Error;
@ -273,9 +273,10 @@ impl ExtXMedia {
pub fn channels(&self) -> Option<&String> {
self.channels.as_ref()
}
}
/// Returns the protocol compatibility version that this tag requires.
pub fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXMedia {
fn required_version(&self) -> ProtocolVersion {
match self.instream_id {
None
| Some(InStreamId::Cc1)
@ -385,11 +386,28 @@ mod test {
use super::*;
#[test]
fn ext_x_media() {
let tag = ExtXMedia::new(MediaType::Audio, "foo", "bar");
let text = r#"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="foo",NAME="bar""#;
assert_eq!(text.parse().ok(), Some(tag.clone()));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(
ExtXMedia::new(MediaType::Audio, "foo", "bar").to_string(),
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"foo\",NAME=\"bar\"".to_string()
)
}
#[test]
fn test_parser() {
assert_eq!(
ExtXMedia::new(MediaType::Audio, "foo", "bar"),
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"foo\",NAME=\"bar\""
.parse()
.unwrap()
)
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXMedia::new(MediaType::Audio, "foo", "bar").required_version(),
ProtocolVersion::V1
)
}
}

View file

@ -4,7 +4,7 @@ use std::str::FromStr;
use derive_builder::Builder;
use crate::attribute::AttributePairs;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::{quote, tag, unquote};
use crate::Error;
@ -243,18 +243,10 @@ impl ExtXSessionData {
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 {
impl RequiredVersion for ExtXSessionData {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use crate::types::{DecryptionKey, EncryptionMethod, ProtocolVersion};
use crate::types::{DecryptionKey, EncryptionMethod, ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -25,24 +25,10 @@ impl ExtXSessionKey {
Self(DecryptionKey::new(method, uri))
}
}
/// Returns the protocol compatibility version that this tag requires.
/// # Example
/// ```
/// use hls_m3u8::tags::ExtXSessionKey;
/// use hls_m3u8::types::{EncryptionMethod, ProtocolVersion};
///
/// let mut key = ExtXSessionKey::new(
/// EncryptionMethod::Aes128,
/// "https://www.example.com/"
/// );
///
/// assert_eq!(
/// key.requires_version(),
/// ProtocolVersion::V1
/// );
/// ```
pub fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXSessionKey {
fn required_version(&self) -> ProtocolVersion {
if self.0.key_format.is_some() | self.0.key_format_versions.is_some() {
ProtocolVersion::V5
} else if self.0.iv.is_some() {
@ -143,4 +129,13 @@ mod test {
key
)
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXSessionKey::new(EncryptionMethod::Aes128, "https://www.example.com/")
.required_version(),
ProtocolVersion::V1
);
}
}

View file

@ -3,7 +3,9 @@ use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{ClosedCaptions, DecimalFloatingPoint, ProtocolVersion, StreamInf};
use crate::types::{
ClosedCaptions, DecimalFloatingPoint, ProtocolVersion, RequiredVersion, StreamInf,
};
use crate::utils::{quote, tag, unquote};
use crate::Error;
@ -23,7 +25,9 @@ pub struct ExtXStreamInf {
impl ExtXStreamInf {
pub(crate) const PREFIX: &'static str = "#EXT-X-STREAM-INF:";
/// Makes a new [ExtXStreamInf] tag.
/// Creates a new [ExtXStreamInf] tag.
///
/// # Examples
/// ```
/// # use hls_m3u8::tags::ExtXStreamInf;
/// #
@ -40,11 +44,21 @@ impl ExtXStreamInf {
}
}
pub fn set_uri<T: ToString>(&mut self, value: T) -> &mut Self {
self.uri = value.to_string();
self
}
/// Returns the URI that identifies the associated media playlist.
pub const fn uri(&self) -> &String {
&self.uri
}
pub fn set_frame_rate(&mut self, value: Option<f64>) -> &mut Self {
self.frame_rate = value.map(|v| v.into());
self
}
/// Returns the maximum frame rate for all the video in the variant stream.
pub fn frame_rate(&self) -> Option<f64> {
self.frame_rate.map_or(None, |v| Some(v.as_f64()))
@ -64,9 +78,10 @@ impl ExtXStreamInf {
pub fn closed_captions(&self) -> Option<&ClosedCaptions> {
self.closed_captions.as_ref()
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXStreamInf {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -158,10 +173,10 @@ mod test {
}
#[test]
fn test_requires_version() {
fn test_required_version() {
assert_eq!(
ProtocolVersion::V1,
ExtXStreamInf::new("http://www.example.com", 1000).requires_version()
ExtXStreamInf::new("http://www.example.com", 1000).required_version()
);
}

View file

@ -1,40 +1,39 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
/// [4.3.3.3. EXT-X-DISCONTINUITY-SEQUENCE]
///
/// [4.3.3.3. EXT-X-DISCONTINUITY-SEQUENCE]: https://tools.ietf.org/html/rfc8216#section-4.3.3.3
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExtXDiscontinuitySequence {
seq_num: u64,
}
#[derive(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.
pub const fn new(seq_num: u64) -> Self {
ExtXDiscontinuitySequence { seq_num }
Self(seq_num)
}
/// Returns the discontinuity sequence number of
/// the first media segment that appears in the associated playlist.
pub const fn seq_num(self) -> u64 {
self.seq_num
pub const fn seq_num(&self) -> u64 {
self.0
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(self) -> ProtocolVersion {
impl RequiredVersion for ExtXDiscontinuitySequence {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXDiscontinuitySequence {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", Self::PREFIX, self.seq_num)
write!(f, "{}{}", Self::PREFIX, self.0)
}
}
@ -42,7 +41,7 @@ impl FromStr for ExtXDiscontinuitySequence {
type Err = crate::Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let seq_num = tag(input, Self::PREFIX)?.parse().unwrap(); // TODO!
let seq_num = tag(input, Self::PREFIX)?.parse()?;
Ok(Self::new(seq_num))
}
}
@ -52,11 +51,26 @@ mod test {
use super::*;
#[test]
fn ext_x_discontinuity_sequence() {
let tag = ExtXDiscontinuitySequence::new(123);
let text = "#EXT-X-DISCONTINUITY-SEQUENCE:123";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(
ExtXDiscontinuitySequence::new(123).to_string(),
"#EXT-X-DISCONTINUITY-SEQUENCE:123".to_string()
);
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXDiscontinuitySequence::new(123).required_version(),
ProtocolVersion::V1
)
}
#[test]
fn test_parser() {
assert_eq!(
ExtXDiscontinuitySequence::new(123),
"#EXT-X-DISCONTINUITY-SEQUENCE:123".parse().unwrap()
);
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -10,11 +10,13 @@ use crate::Error;
/// [4.3.3.4. EXT-X-ENDLIST]: https://tools.ietf.org/html/rfc8216#section-4.3.3.4
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExtXEndList;
impl ExtXEndList {
pub(crate) const PREFIX: &'static str = "#EXT-X-ENDLIST";
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(self) -> ProtocolVersion {
impl RequiredVersion for ExtXEndList {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -39,11 +41,17 @@ mod test {
use super::*;
#[test]
fn ext_x_endlist() {
let tag = ExtXEndList;
let text = "#EXT-X-ENDLIST";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(ExtXEndList.to_string(), "#EXT-X-ENDLIST".to_string());
}
#[test]
fn test_parser() {
assert_eq!(ExtXEndList, "#EXT-X-ENDLIST".parse().unwrap());
}
#[test]
fn test_required_version() {
assert_eq!(ExtXEndList.required_version(), ProtocolVersion::V1);
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -13,9 +13,10 @@ pub struct ExtXIFramesOnly;
impl ExtXIFramesOnly {
pub(crate) const PREFIX: &'static str = "#EXT-X-I-FRAMES-ONLY";
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(self) -> ProtocolVersion {
impl RequiredVersion for ExtXIFramesOnly {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V4
}
}
@ -40,11 +41,20 @@ mod test {
use super::*;
#[test]
fn ext_i_frames_only() {
let tag = ExtXIFramesOnly;
let text = "#EXT-X-I-FRAMES-ONLY";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V4);
fn test_display() {
assert_eq!(
ExtXIFramesOnly.to_string(),
"#EXT-X-I-FRAMES-ONLY".to_string(),
)
}
#[test]
fn test_parser() {
assert_eq!(ExtXIFramesOnly, "#EXT-X-I-FRAMES-ONLY".parse().unwrap(),)
}
#[test]
fn test_required_version() {
assert_eq!(ExtXIFramesOnly.required_version(), ProtocolVersion::V4)
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -9,32 +9,32 @@ use crate::Error;
///
/// [4.3.3.2. EXT-X-MEDIA-SEQUENCE]: https://tools.ietf.org/html/rfc8216#section-4.3.3.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExtXMediaSequence {
seq_num: u64,
}
pub struct ExtXMediaSequence(u64);
impl ExtXMediaSequence {
pub(crate) const PREFIX: &'static str = "#EXT-X-MEDIA-SEQUENCE:";
/// Makes a new `ExtXMediaSequence` tag.
pub const fn new(seq_num: u64) -> Self {
ExtXMediaSequence { seq_num }
Self(seq_num)
}
/// Returns the sequence number of the first media segment that appears in the associated playlist.
pub const fn seq_num(self) -> u64 {
self.seq_num
/// Returns the sequence number of the first media segment,
/// that appears in the associated playlist.
pub const fn seq_num(&self) -> u64 {
self.0
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(self) -> ProtocolVersion {
impl RequiredVersion for ExtXMediaSequence {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXMediaSequence {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", Self::PREFIX, self.seq_num)
write!(f, "{}{}", Self::PREFIX, self.0)
}
}
@ -43,7 +43,6 @@ impl FromStr for ExtXMediaSequence {
fn from_str(input: &str) -> Result<Self, Self::Err> {
let seq_num = tag(input, Self::PREFIX)?.parse()?;
Ok(ExtXMediaSequence::new(seq_num))
}
}
@ -53,11 +52,26 @@ mod test {
use super::*;
#[test]
fn ext_x_media_sequence() {
let tag = ExtXMediaSequence::new(123);
let text = "#EXT-X-MEDIA-SEQUENCE:123";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(
ExtXMediaSequence::new(123).to_string(),
"#EXT-X-MEDIA-SEQUENCE:123".to_string()
);
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXMediaSequence::new(123).required_version(),
ProtocolVersion::V1
);
}
#[test]
fn test_parser() {
assert_eq!(
ExtXMediaSequence::new(123),
"#EXT-X-MEDIA-SEQUENCE:123".parse().unwrap()
);
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -31,9 +31,10 @@ pub enum ExtXPlaylistType {
impl ExtXPlaylistType {
pub(crate) const PREFIX: &'static str = "#EXT-X-PLAYLIST-TYPE:";
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXPlaylistType {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -99,13 +100,13 @@ mod test {
}
#[test]
fn test_requires_version() {
fn test_required_version() {
assert_eq!(
ExtXPlaylistType::Vod.requires_version(),
ExtXPlaylistType::Vod.required_version(),
ProtocolVersion::V1
);
assert_eq!(
ExtXPlaylistType::Event.requires_version(),
ExtXPlaylistType::Event.required_version(),
ProtocolVersion::V1
);
}

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::str::FromStr;
use std::time::Duration;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -10,9 +10,7 @@ use crate::Error;
///
/// [4.3.3.1. EXT-X-TARGETDURATION]: https://tools.ietf.org/html/rfc8216#section-4.3.3.1
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct ExtXTargetDuration {
duration: Duration,
}
pub struct ExtXTargetDuration(Duration);
impl ExtXTargetDuration {
pub(crate) const PREFIX: &'static str = "#EXT-X-TARGETDURATION:";
@ -21,24 +19,24 @@ impl ExtXTargetDuration {
///
/// Note that the nanoseconds part of the `duration` will be discarded.
pub const fn new(duration: Duration) -> Self {
let duration = Duration::from_secs(duration.as_secs());
ExtXTargetDuration { duration }
Self(Duration::from_secs(duration.as_secs()))
}
/// Returns the maximum media segment duration in the associated playlist.
pub const fn duration(&self) -> Duration {
self.duration
self.0
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXTargetDuration {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
impl fmt::Display for ExtXTargetDuration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", Self::PREFIX, self.duration.as_secs())
write!(f, "{}{}", Self::PREFIX, self.0.as_secs())
}
}
@ -47,9 +45,7 @@ impl FromStr for ExtXTargetDuration {
fn from_str(input: &str) -> Result<Self, Self::Err> {
let input = tag(input, Self::PREFIX)?.parse()?;
Ok(ExtXTargetDuration {
duration: Duration::from_secs(input),
})
Ok(Self::new(Duration::from_secs(input)))
}
}
@ -58,11 +54,26 @@ mod test {
use super::*;
#[test]
fn ext_x_targetduration() {
let tag = ExtXTargetDuration::new(Duration::from_secs(5));
let text = "#EXT-X-TARGETDURATION:5";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(
ExtXTargetDuration::new(Duration::from_secs(5)).to_string(),
"#EXT-X-TARGETDURATION:5".to_string()
);
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXTargetDuration::new(Duration::from_secs(5)).required_version(),
ProtocolVersion::V1
);
}
#[test]
fn test_parser() {
assert_eq!(
ExtXTargetDuration::new(Duration::from_secs(5)),
"#EXT-X-TARGETDURATION:5".parse().unwrap()
);
}
}

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::ops::Deref;
use std::str::FromStr;
use crate::types::{ByteRange, ProtocolVersion};
use crate::types::{ByteRange, ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -16,6 +16,7 @@ impl ExtXByteRange {
pub(crate) const PREFIX: &'static str = "#EXT-X-BYTERANGE:";
/// Makes a new `ExtXByteRange` tag.
///
/// # Example
/// ```
/// use hls_m3u8::tags::ExtXByteRange;
@ -27,6 +28,7 @@ impl ExtXByteRange {
}
/// Converts the [ExtXByteRange] to a [ByteRange].
///
/// # Example
/// ```
/// use hls_m3u8::tags::ExtXByteRange;
@ -38,17 +40,10 @@ impl ExtXByteRange {
pub const fn to_range(&self) -> ByteRange {
self.0
}
}
/// Returns the protocol compatibility version that this tag requires.
/// # Example
/// ```
/// use hls_m3u8::tags::ExtXByteRange;
/// use hls_m3u8::types::ProtocolVersion;
///
/// let byte_range = ExtXByteRange::new(20, Some(5));
/// assert_eq!(byte_range.requires_version(), ProtocolVersion::V4);
/// ```
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXByteRange {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V4
}
}
@ -76,6 +71,7 @@ impl FromStr for ExtXByteRange {
let input = tag(input, Self::PREFIX)?;
let tokens = input.splitn(2, '@').collect::<Vec<_>>();
if tokens.is_empty() {
return Err(Error::invalid_input());
}
@ -135,4 +131,12 @@ mod test {
assert_eq!(byte_range.length(), 0);
assert_eq!(byte_range.start(), Some(22));
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXByteRange::new(20, Some(5)).required_version(),
ProtocolVersion::V4
);
}
}

View file

@ -6,7 +6,7 @@ use std::time::Duration;
use chrono::{DateTime, FixedOffset};
use crate::attribute::AttributePairs;
use crate::types::{DecimalFloatingPoint, ProtocolVersion};
use crate::types::{DecimalFloatingPoint, ProtocolVersion, RequiredVersion};
use crate::utils::{quote, tag, unquote};
use crate::Error;
@ -63,9 +63,10 @@ pub struct ExtXDateRange {
impl ExtXDateRange {
pub(crate) const PREFIX: &'static str = "#EXT-X-DATERANGE:";
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXDateRange {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}

View file

@ -1,9 +1,9 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::{Error, Result};
use crate::Error;
/// [4.3.2.3. EXT-X-DISCONTINUITY]
///
@ -13,9 +13,10 @@ pub struct ExtXDiscontinuity;
impl ExtXDiscontinuity {
pub(crate) const PREFIX: &'static str = "#EXT-X-DISCONTINUITY";
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(self) -> ProtocolVersion {
impl RequiredVersion for ExtXDiscontinuity {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -29,7 +30,7 @@ impl fmt::Display for ExtXDiscontinuity {
impl FromStr for ExtXDiscontinuity {
type Err = Error;
fn from_str(input: &str) -> Result<Self> {
fn from_str(input: &str) -> Result<Self, Self::Err> {
tag(input, Self::PREFIX)?;
Ok(ExtXDiscontinuity)
}
@ -40,10 +41,20 @@ mod test {
use super::*;
#[test]
fn ext_x_discontinuity() {
let tag = ExtXDiscontinuity;
assert_eq!("#EXT-X-DISCONTINUITY".parse().ok(), Some(tag));
assert_eq!(tag.to_string(), "#EXT-X-DISCONTINUITY");
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(
ExtXDiscontinuity.to_string(),
"#EXT-X-DISCONTINUITY".to_string(),
)
}
#[test]
fn test_parser() {
assert_eq!(ExtXDiscontinuity, "#EXT-X-DISCONTINUITY".parse().unwrap(),)
}
#[test]
fn test_required_version() {
assert_eq!(ExtXDiscontinuity.required_version(), ProtocolVersion::V1)
}
}

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::str::FromStr;
use std::time::Duration;
use crate::types::{DecimalFloatingPoint, ProtocolVersion};
use crate::types::{DecimalFloatingPoint, ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -78,9 +78,10 @@ impl ExtInf {
pub fn title(&self) -> Option<&String> {
self.title.as_ref()
}
}
/// Returns the protocol compatibility version that this tag requires.
pub fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtInf {
fn required_version(&self) -> ProtocolVersion {
if self.duration.subsec_nanos() == 0 {
ProtocolVersion::V1
} else {
@ -206,13 +207,13 @@ mod test {
}
#[test]
fn test_requires_version() {
fn test_required_version() {
assert_eq!(
ExtInf::new(Duration::from_secs(4)).requires_version(),
ExtInf::new(Duration::from_secs(4)).required_version(),
ProtocolVersion::V1
);
assert_eq!(
ExtInf::new(Duration::from_millis(4400)).requires_version(),
ExtInf::new(Duration::from_millis(4400)).required_version(),
ProtocolVersion::V3
);
}

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{ByteRange, ProtocolVersion};
use crate::types::{ByteRange, ProtocolVersion, RequiredVersion};
use crate::utils::{quote, tag, unquote};
use crate::Error;
@ -43,9 +43,10 @@ impl ExtXMap {
pub const fn range(&self) -> Option<ByteRange> {
self.range
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXMap {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V6
}
}
@ -93,19 +94,37 @@ mod test {
use super::*;
#[test]
fn ext_x_map() {
let tag = ExtXMap::new("foo");
let text = r#"#EXT-X-MAP:URI="foo""#;
assert_eq!(text.parse().ok(), Some(tag.clone()));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V6);
fn test_display() {
assert_eq!(
ExtXMap::new("foo").to_string(),
"#EXT-X-MAP:URI=\"foo\"".to_string(),
);
let tag = ExtXMap::with_range("foo", ByteRange::new(9, Some(2)));
let text = r#"#EXT-X-MAP:URI="foo",BYTERANGE="9@2""#;
ExtXMap::from_str(text).unwrap();
assert_eq!(
ExtXMap::with_range("foo", ByteRange::new(9, Some(2))).to_string(),
"#EXT-X-MAP:URI=\"foo\",BYTERANGE=\"9@2\"".to_string(),
);
}
assert_eq!(text.parse().ok(), Some(tag.clone()));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V6);
#[test]
fn test_parser() {
assert_eq!(
ExtXMap::new("foo"),
"#EXT-X-MAP:URI=\"foo\"".parse().unwrap()
);
assert_eq!(
ExtXMap::with_range("foo", ByteRange::new(9, Some(2))),
"#EXT-X-MAP:URI=\"foo\",BYTERANGE=\"9@2\"".parse().unwrap()
);
}
#[test]
fn test_required_version() {
assert_eq!(ExtXMap::new("foo").required_version(), ProtocolVersion::V6);
assert_eq!(
ExtXMap::with_range("foo", ByteRange::new(9, Some(2))).required_version(),
ProtocolVersion::V6
);
}
}

View file

@ -3,7 +3,7 @@ use std::str::FromStr;
use chrono::{DateTime, FixedOffset};
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -25,9 +25,10 @@ impl ExtXProgramDateTime {
pub const fn date_time(&self) -> &DateTime<FixedOffset> {
&self.0
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXProgramDateTime {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -45,7 +46,6 @@ impl FromStr for ExtXProgramDateTime {
fn from_str(input: &str) -> Result<Self, Self::Err> {
let input = tag(input, Self::PREFIX)?;
// TODO: parse with chrono
let date_time = DateTime::parse_from_rfc3339(input)?;
Ok(Self::new(date_time))
}
@ -54,6 +54,9 @@ impl FromStr for ExtXProgramDateTime {
#[cfg(test)]
mod test {
use super::*;
use chrono::TimeZone;
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
#[test]
fn test_display() {
@ -71,19 +74,26 @@ mod test {
#[test]
fn test_parser() {
"#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00"
.parse::<ExtXProgramDateTime>()
.unwrap();
assert_eq!(
ExtXProgramDateTime::new(
FixedOffset::east(8 * HOURS_IN_SECS)
.ymd(2010, 2, 19)
.and_hms_milli(14, 54, 23, 31)
),
"#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00"
.parse::<ExtXProgramDateTime>()
.unwrap()
);
}
#[test]
fn test_requires_version() {
let date_time = "2010-02-19T14:54:23.031+08:00"
.parse::<DateTime<FixedOffset>>()
.unwrap();
fn test_required_version() {
let program_date_time = ExtXProgramDateTime::new(
FixedOffset::east(8 * HOURS_IN_SECS)
.ymd(2010, 2, 19)
.and_hms_milli(14, 54, 23, 31),
);
let program_date_time = ExtXProgramDateTime::new(date_time);
assert_eq!(program_date_time.requires_version(), ProtocolVersion::V1);
assert_eq!(program_date_time.required_version(), ProtocolVersion::V1);
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::str::FromStr;
use crate::types::ProtocolVersion;
use crate::types::{ProtocolVersion, RequiredVersion};
use crate::utils::tag;
use crate::Error;
@ -10,11 +10,13 @@ use crate::Error;
/// [4.3.5.1. EXT-X-INDEPENDENT-SEGMENTS]: https://tools.ietf.org/html/rfc8216#section-4.3.5.1
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExtXIndependentSegments;
impl ExtXIndependentSegments {
pub(crate) const PREFIX: &'static str = "#EXT-X-INDEPENDENT-SEGMENTS";
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXIndependentSegments {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -39,11 +41,26 @@ mod test {
use super::*;
#[test]
fn ext_x_independent_segments() {
let tag = ExtXIndependentSegments;
let text = "#EXT-X-INDEPENDENT-SEGMENTS";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(
ExtXIndependentSegments.to_string(),
"#EXT-X-INDEPENDENT-SEGMENTS".to_string(),
)
}
#[test]
fn test_parser() {
assert_eq!(
ExtXIndependentSegments,
"#EXT-X-INDEPENDENT-SEGMENTS".parse().unwrap(),
)
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXIndependentSegments.required_version(),
ProtocolVersion::V1
)
}
}

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::str::FromStr;
use crate::attribute::AttributePairs;
use crate::types::{ProtocolVersion, SignedDecimalFloatingPoint};
use crate::types::{ProtocolVersion, RequiredVersion, SignedDecimalFloatingPoint};
use crate::utils::{parse_yes_or_no, tag};
use crate::Error;
@ -19,6 +19,7 @@ impl ExtXStart {
pub(crate) const PREFIX: &'static str = "#EXT-X-START:";
/// Makes a new `ExtXStart` tag.
///
/// # Panic
/// Panics if the time_offset value is infinite.
pub fn new(time_offset: f64) -> Self {
@ -33,6 +34,7 @@ impl ExtXStart {
}
/// Makes a new `ExtXStart` tag with the given `precise` flag.
///
/// # Panic
/// Panics if the time_offset value is infinite.
pub fn with_precise(time_offset: f64, precise: bool) -> Self {
@ -56,9 +58,10 @@ impl ExtXStart {
pub const fn precise(&self) -> bool {
self.precise
}
}
/// Returns the protocol compatibility version that this tag requires.
pub const fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for ExtXStart {
fn required_version(&self) -> ProtocolVersion {
ProtocolVersion::V1
}
}
@ -108,17 +111,41 @@ mod test {
use super::*;
#[test]
fn ext_x_start() {
let tag = ExtXStart::new(-1.23);
let text = "#EXT-X-START:TIME-OFFSET=-1.23";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
fn test_display() {
assert_eq!(
ExtXStart::new(-1.23).to_string(),
"#EXT-X-START:TIME-OFFSET=-1.23".to_string(),
);
let tag = ExtXStart::with_precise(1.23, true);
let text = "#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES";
assert_eq!(text.parse().ok(), Some(tag));
assert_eq!(tag.to_string(), text);
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
assert_eq!(
ExtXStart::with_precise(1.23, true).to_string(),
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES".to_string(),
);
}
#[test]
fn test_required_version() {
assert_eq!(
ExtXStart::new(-1.23).required_version(),
ProtocolVersion::V1,
);
assert_eq!(
ExtXStart::with_precise(1.23, true).required_version(),
ProtocolVersion::V1,
);
}
#[test]
fn test_parser() {
assert_eq!(
ExtXStart::new(-1.23),
"#EXT-X-START:TIME-OFFSET=-1.23".parse().unwrap(),
);
assert_eq!(
ExtXStart::with_precise(1.23, true),
"#EXT-X-START:TIME-OFFSET=1.23,PRECISE=YES".parse().unwrap(),
);
}
}

View file

@ -70,6 +70,18 @@ impl FromStr for DecimalFloatingPoint {
}
}
impl From<f64> for DecimalFloatingPoint {
fn from(value: f64) -> Self {
Self(value)
}
}
impl From<f32> for DecimalFloatingPoint {
fn from(value: f32) -> Self {
Self(value.into())
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -4,7 +4,7 @@ use std::str::FromStr;
use derive_builder::Builder;
use crate::attribute::AttributePairs;
use crate::types::{EncryptionMethod, InitializationVector, ProtocolVersion};
use crate::types::{EncryptionMethod, InitializationVector, ProtocolVersion, RequiredVersion};
use crate::utils::{quote, unquote};
use crate::Error;
@ -292,23 +292,10 @@ impl DecryptionKey {
pub fn set_key_format_versions<T: ToString>(&mut self, value: T) {
self.key_format_versions = Some(value.to_string());
}
}
/// Returns the protocol compatibility version that this tag requires.
/// # Example
/// ```
/// use hls_m3u8::types::{EncryptionMethod, ProtocolVersion, DecryptionKey};
///
/// let mut key = DecryptionKey::new(
/// EncryptionMethod::Aes128,
/// "https://www.example.com/"
/// );
///
/// assert_eq!(
/// key.requires_version(),
/// ProtocolVersion::V1
/// );
/// ```
pub fn requires_version(&self) -> ProtocolVersion {
impl RequiredVersion for DecryptionKey {
fn required_version(&self) -> ProtocolVersion {
if self.key_format.is_some() || self.key_format_versions.is_some() {
ProtocolVersion::V5
} else if self.iv.is_some() {
@ -464,4 +451,13 @@ mod test {
key
)
}
#[test]
fn test_required_version() {
assert_eq!(
DecryptionKey::new(EncryptionMethod::Aes128, "https://www.example.com/")
.required_version(),
ProtocolVersion::V1
)
}
}

View file

@ -3,6 +3,30 @@ use std::str::FromStr;
use crate::Error;
/// # Example
/// Implementing it:
/// ```
/// # use hls_m3u8::types::{ProtocolVersion, RequiredVersion};
/// #
/// struct NewTag(u64);
///
/// impl RequiredVersion for NewTag {
/// fn required_version(&self) -> ProtocolVersion {
/// if self.0 == 5 {
/// ProtocolVersion::V4
/// } else {
/// ProtocolVersion::V1
/// }
/// }
/// }
/// assert_eq!(NewTag(5).required_version(), ProtocolVersion::V4);
/// assert_eq!(NewTag(2).required_version(), ProtocolVersion::V1);
/// ```
pub trait RequiredVersion {
/// Returns the protocol compatibility version that this tag requires.
fn required_version(&self) -> ProtocolVersion;
}
/// [7. Protocol Version Compatibility]
///
/// [7. Protocol Version Compatibility]: https://tools.ietf.org/html/rfc8216#section-7
@ -29,13 +53,13 @@ impl fmt::Display for ProtocolVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let n = {
match &self {
ProtocolVersion::V1 => 1,
ProtocolVersion::V2 => 2,
ProtocolVersion::V3 => 3,
ProtocolVersion::V4 => 4,
ProtocolVersion::V5 => 5,
ProtocolVersion::V6 => 6,
ProtocolVersion::V7 => 7,
Self::V1 => 1,
Self::V2 => 2,
Self::V3 => 3,
Self::V4 => 4,
Self::V5 => 5,
Self::V6 => 6,
Self::V7 => 7,
}
};
write!(f, "{}", n)
@ -47,16 +71,49 @@ impl FromStr for ProtocolVersion {
fn from_str(input: &str) -> Result<Self, Self::Err> {
Ok({
match input {
"1" => ProtocolVersion::V1,
"2" => ProtocolVersion::V2,
"3" => ProtocolVersion::V3,
"4" => ProtocolVersion::V4,
"5" => ProtocolVersion::V5,
"6" => ProtocolVersion::V6,
"7" => ProtocolVersion::V7,
match input.trim() {
"1" => Self::V1,
"2" => Self::V2,
"3" => Self::V3,
"4" => Self::V4,
"5" => Self::V5,
"6" => Self::V6,
"7" => Self::V7,
_ => return Err(Error::unknown_protocol_version(input)),
}
})
}
}
impl Default for ProtocolVersion {
fn default() -> Self {
Self::V1
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display() {
assert_eq!(ProtocolVersion::V1.to_string(), "1".to_string());
assert_eq!(ProtocolVersion::V2.to_string(), "2".to_string());
assert_eq!(ProtocolVersion::V3.to_string(), "3".to_string());
assert_eq!(ProtocolVersion::V4.to_string(), "4".to_string());
assert_eq!(ProtocolVersion::V5.to_string(), "5".to_string());
assert_eq!(ProtocolVersion::V6.to_string(), "6".to_string());
assert_eq!(ProtocolVersion::V7.to_string(), "7".to_string());
}
#[test]
fn test_parser() {
assert_eq!(ProtocolVersion::V1, "1".parse().unwrap());
assert_eq!(ProtocolVersion::V2, "2".parse().unwrap());
assert_eq!(ProtocolVersion::V3, "3".parse().unwrap());
assert_eq!(ProtocolVersion::V4, "4".parse().unwrap());
assert_eq!(ProtocolVersion::V5, "5".parse().unwrap());
assert_eq!(ProtocolVersion::V6, "6".parse().unwrap());
assert_eq!(ProtocolVersion::V7, "7".parse().unwrap());
}
}