mirror of
https://github.com/sile/hls_m3u8.git
synced 2025-02-16 21:25:15 +00:00
make chrono optional #49
This commit is contained in:
parent
1b01675250
commit
b2fb58559c
5 changed files with 235 additions and 124 deletions
|
@ -25,6 +25,7 @@ script:
|
||||||
- cargo clean
|
- cargo clean
|
||||||
- cargo build
|
- cargo build
|
||||||
- cargo test
|
- cargo test
|
||||||
|
- cargo test --features chrono
|
||||||
|
|
||||||
# it's enough to run this once:
|
# it's enough to run this once:
|
||||||
- |
|
- |
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -16,14 +16,16 @@ codecov = { repository = "sile/hls_m3u8" }
|
||||||
travis-ci = { repository = "sile/hls_m3u8" }
|
travis-ci = { repository = "sile/hls_m3u8" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4"
|
chrono = { version = "0.4", optional = true }
|
||||||
|
backtrace = { version = "0.3", features = ["std"], optional = true }
|
||||||
|
|
||||||
derive_builder = "0.9"
|
derive_builder = "0.9"
|
||||||
derive_more = "0.99"
|
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
thiserror = "1.0"
|
||||||
|
|
||||||
|
derive_more = "0.99"
|
||||||
shorthand = "0.1"
|
shorthand = "0.1"
|
||||||
strum = { version = "0.17", features = ["derive"] }
|
strum = { version = "0.17", features = ["derive"] }
|
||||||
thiserror = "1.0"
|
|
||||||
backtrace = { version = "0.3", features = ["std"], optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "0.6"
|
pretty_assertions = "0.6"
|
||||||
|
|
|
@ -59,6 +59,7 @@ enum ErrorKind {
|
||||||
UnexpectedTag { tag: String },
|
UnexpectedTag { tag: String },
|
||||||
|
|
||||||
#[error("{source}")]
|
#[error("{source}")]
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
Chrono { source: chrono::ParseError },
|
Chrono { source: chrono::ParseError },
|
||||||
|
|
||||||
#[error("builder error: {message}")]
|
#[error("builder error: {message}")]
|
||||||
|
@ -169,6 +170,7 @@ impl Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// third party crates:
|
// third party crates:
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
pub(crate) fn chrono(source: chrono::format::ParseError) -> Self {
|
pub(crate) fn chrono(source: chrono::format::ParseError) -> Self {
|
||||||
Self::new(ErrorKind::Chrono { source })
|
Self::new(ErrorKind::Chrono { source })
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
use chrono::{DateTime, FixedOffset, SecondsFormat};
|
use chrono::{DateTime, FixedOffset, SecondsFormat};
|
||||||
use derive_builder::Builder;
|
use derive_builder::Builder;
|
||||||
use shorthand::ShortHand;
|
use shorthand::ShortHand;
|
||||||
|
@ -12,13 +13,8 @@ use crate::types::{ProtocolVersion, Value};
|
||||||
use crate::utils::{quote, tag, unquote};
|
use crate::utils::{quote, tag, unquote};
|
||||||
use crate::{Error, RequiredVersion};
|
use crate::{Error, RequiredVersion};
|
||||||
|
|
||||||
/// # [4.3.2.7. EXT-X-DATERANGE]
|
/// The [`ExtXDateRange`] tag associates a date range (i.e., a range of time
|
||||||
///
|
/// defined by a starting and ending date) with a set of attribute/value pairs.
|
||||||
/// The [`ExtXDateRange`] tag associates a date range (i.e., a range of
|
|
||||||
/// time defined by a starting and ending date) with a set of attribute/
|
|
||||||
/// value pairs.
|
|
||||||
///
|
|
||||||
/// [4.3.2.7. EXT-X-DATERANGE]: https://tools.ietf.org/html/rfc8216#section-4.3.2.7
|
|
||||||
#[derive(ShortHand, Builder, Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(ShortHand, Builder, Debug, Clone, PartialEq, PartialOrd)]
|
||||||
#[builder(setter(into))]
|
#[builder(setter(into))]
|
||||||
#[shorthand(enable(must_use, into))]
|
#[shorthand(enable(must_use, into))]
|
||||||
|
@ -43,6 +39,7 @@ pub struct ExtXDateRange {
|
||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// This attribute is required.
|
/// This attribute is required.
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
start_date: DateTime<FixedOffset>,
|
start_date: DateTime<FixedOffset>,
|
||||||
/// The date at which the [`ExtXDateRange`] ends. It must be equal to or
|
/// The date at which the [`ExtXDateRange`] ends. It must be equal to or
|
||||||
/// later than the value of the [`start-date`] attribute.
|
/// later than the value of the [`start-date`] attribute.
|
||||||
|
@ -52,8 +49,12 @@ pub struct ExtXDateRange {
|
||||||
/// This attribute is optional.
|
/// This attribute is optional.
|
||||||
///
|
///
|
||||||
/// [`start-date`]: #method.start_date
|
/// [`start-date`]: #method.start_date
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
#[builder(setter(strip_option), default)]
|
#[builder(setter(strip_option), default)]
|
||||||
end_date: Option<DateTime<FixedOffset>>,
|
end_date: Option<DateTime<FixedOffset>>,
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
#[builder(setter(strip_option), default)]
|
||||||
|
end_date: Option<String>,
|
||||||
/// The duration of the [`ExtXDateRange`]. A single instant in time (e.g.,
|
/// The duration of the [`ExtXDateRange`]. A single instant in time (e.g.,
|
||||||
/// crossing a finish line) should be represented with a duration of 0.
|
/// crossing a finish line) should be represented with a duration of 0.
|
||||||
///
|
///
|
||||||
|
@ -145,27 +146,48 @@ impl ExtXDateRange {
|
||||||
/// Makes a new [`ExtXDateRange`] tag.
|
/// Makes a new [`ExtXDateRange`] tag.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
#[cfg_attr(
|
||||||
/// ```
|
feature = "chrono",
|
||||||
/// # use hls_m3u8::tags::ExtXDateRange;
|
doc = r#"
|
||||||
/// use chrono::offset::TimeZone;
|
```
|
||||||
/// use chrono::{DateTime, FixedOffset};
|
# use hls_m3u8::tags::ExtXDateRange;
|
||||||
///
|
use chrono::offset::TimeZone;
|
||||||
/// const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
use chrono::{DateTime, FixedOffset};
|
||||||
///
|
|
||||||
/// let date_range = ExtXDateRange::new(
|
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
||||||
/// "id",
|
|
||||||
/// FixedOffset::east(8 * HOURS_IN_SECS)
|
let date_range = ExtXDateRange::new(
|
||||||
/// .ymd(2010, 2, 19)
|
"id",
|
||||||
/// .and_hms_milli(14, 54, 23, 31),
|
FixedOffset::east(8 * HOURS_IN_SECS)
|
||||||
/// );
|
.ymd(2010, 2, 19)
|
||||||
/// ```
|
.and_hms_milli(14, 54, 23, 31),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
)]
|
||||||
|
#[cfg_attr(
|
||||||
|
not(feature = "chrono"),
|
||||||
|
doc = r#"
|
||||||
|
```
|
||||||
|
# use hls_m3u8::tags::ExtXDateRange;
|
||||||
|
|
||||||
|
let date_range = ExtXDateRange::new("id", "2010-02-19T14:54:23.031+08:00");
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new<T: Into<String>>(id: T, start_date: DateTime<FixedOffset>) -> Self {
|
pub fn new<T: Into<String>, #[cfg(not(feature = "chrono"))] I: Into<String>>(
|
||||||
|
id: T,
|
||||||
|
#[cfg(feature = "chrono")] start_date: DateTime<FixedOffset>,
|
||||||
|
#[cfg(not(feature = "chrono"))] start_date: I,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
class: None,
|
class: None,
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
start_date,
|
start_date,
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
start_date: start_date.into(),
|
||||||
end_date: None,
|
end_date: None,
|
||||||
duration: None,
|
duration: None,
|
||||||
planned_duration: None,
|
planned_duration: None,
|
||||||
|
@ -210,8 +232,26 @@ impl FromStr for ExtXDateRange {
|
||||||
match key {
|
match key {
|
||||||
"ID" => id = Some(unquote(value)),
|
"ID" => id = Some(unquote(value)),
|
||||||
"CLASS" => class = Some(unquote(value)),
|
"CLASS" => class = Some(unquote(value)),
|
||||||
"START-DATE" => start_date = Some(unquote(value)),
|
"START-DATE" => {
|
||||||
"END-DATE" => end_date = Some(unquote(value).parse().map_err(Error::chrono)?),
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
start_date = Some(unquote(value).parse().map_err(Error::chrono)?)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
start_date = Some(unquote(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"END-DATE" => {
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
end_date = Some(unquote(value).parse().map_err(Error::chrono)?)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
end_date = Some(unquote(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
"DURATION" => {
|
"DURATION" => {
|
||||||
duration = Some(Duration::from_secs_f64(
|
duration = Some(Duration::from_secs_f64(
|
||||||
value.parse().map_err(|e| Error::parse_float(value, e))?,
|
value.parse().map_err(|e| Error::parse_float(value, e))?,
|
||||||
|
@ -244,10 +284,7 @@ impl FromStr for ExtXDateRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = id.ok_or_else(|| Error::missing_value("ID"))?;
|
let id = id.ok_or_else(|| Error::missing_value("ID"))?;
|
||||||
let start_date = start_date
|
let start_date = start_date.ok_or_else(|| Error::missing_value("START-DATE"))?;
|
||||||
.ok_or_else(|| Error::missing_value("START-DATE"))?
|
|
||||||
.parse()
|
|
||||||
.map_err(Error::chrono)?;
|
|
||||||
|
|
||||||
if end_on_next && class.is_none() {
|
if end_on_next && class.is_none() {
|
||||||
return Err(Error::invalid_input());
|
return Err(Error::invalid_input());
|
||||||
|
@ -277,20 +314,36 @@ impl fmt::Display for ExtXDateRange {
|
||||||
write!(f, ",CLASS={}", quote(value))?;
|
write!(f, ",CLASS={}", quote(value))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(
|
#[cfg(feature = "chrono")]
|
||||||
f,
|
{
|
||||||
",START-DATE={}",
|
|
||||||
quote(&self.start_date.to_rfc3339_opts(SecondsFormat::AutoSi, true))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(value) = &self.end_date {
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
",END-DATE={}",
|
",START-DATE={}",
|
||||||
quote(&value.to_rfc3339_opts(SecondsFormat::AutoSi, true))
|
quote(&self.start_date.to_rfc3339_opts(SecondsFormat::AutoSi, true))
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
write!(f, ",START-DATE={}", quote(&self.start_date))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(value) = &self.end_date {
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
",END-DATE={}",
|
||||||
|
quote(&value.to_rfc3339_opts(SecondsFormat::AutoSi, true))
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
write!(f, ",END-DATE={}", quote(&value))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(value) = &self.duration {
|
if let Some(value) = &self.duration {
|
||||||
write!(f, ",DURATION={}", value.as_secs_f64())?;
|
write!(f, ",DURATION={}", value.as_secs_f64())?;
|
||||||
}
|
}
|
||||||
|
@ -327,9 +380,11 @@ impl fmt::Display for ExtXDateRange {
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::types::Float;
|
use crate::types::Float;
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
use chrono::offset::TimeZone;
|
use chrono::offset::TimeZone;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
||||||
|
|
||||||
macro_rules! generate_tests {
|
macro_rules! generate_tests {
|
||||||
|
@ -369,7 +424,16 @@ mod test {
|
||||||
{
|
{
|
||||||
ExtXDateRange::builder()
|
ExtXDateRange::builder()
|
||||||
.id("splice-6FFFFFF0")
|
.id("splice-6FFFFFF0")
|
||||||
.start_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 15, 0))
|
.start_date({
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 15, 0)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
"2014-03-05T11:15:00Z"
|
||||||
|
}
|
||||||
|
})
|
||||||
.planned_duration(Duration::from_secs_f64(59.993))
|
.planned_duration(Duration::from_secs_f64(59.993))
|
||||||
.scte35_out(concat!(
|
.scte35_out(concat!(
|
||||||
"0xFC002F0000000000FF00001",
|
"0xFC002F0000000000FF00001",
|
||||||
|
@ -393,8 +457,26 @@ mod test {
|
||||||
ExtXDateRange::builder()
|
ExtXDateRange::builder()
|
||||||
.id("test_id")
|
.id("test_id")
|
||||||
.class("test_class")
|
.class("test_class")
|
||||||
.start_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 15, 0))
|
.start_date({
|
||||||
.end_date(FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 16, 0))
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 15, 0)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
"2014-03-05T11:15:00Z"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.end_date({
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
FixedOffset::east(0).ymd(2014, 3, 5).and_hms(11, 16, 0)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
"2014-03-05T11:16:00Z"
|
||||||
|
}
|
||||||
|
})
|
||||||
.duration(Duration::from_secs_f64(60.1))
|
.duration(Duration::from_secs_f64(60.1))
|
||||||
.planned_duration(Duration::from_secs_f64(59.993))
|
.planned_duration(Duration::from_secs_f64(59.993))
|
||||||
.insert_client_attribute("X-CUSTOM", Float::new(45.3))
|
.insert_client_attribute("X-CUSTOM", Float::new(45.3))
|
||||||
|
@ -424,12 +506,18 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_required_version() {
|
fn test_required_version() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXDateRange::new(
|
ExtXDateRange::new("id", {
|
||||||
"id",
|
#[cfg(feature = "chrono")]
|
||||||
FixedOffset::east(8 * HOURS_IN_SECS)
|
{
|
||||||
.ymd(2010, 2, 19)
|
FixedOffset::east(8 * HOURS_IN_SECS)
|
||||||
.and_hms_milli(14, 54, 23, 31)
|
.ymd(2010, 2, 19)
|
||||||
)
|
.and_hms_milli(14, 54, 23, 31)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
"2010-02-19T14:54:23.031+08:00"
|
||||||
|
}
|
||||||
|
})
|
||||||
.required_version(),
|
.required_version(),
|
||||||
ProtocolVersion::V1
|
ProtocolVersion::V1
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
use chrono::{DateTime, FixedOffset, SecondsFormat};
|
use chrono::{DateTime, FixedOffset, SecondsFormat};
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::types::ProtocolVersion;
|
use crate::types::ProtocolVersion;
|
||||||
|
@ -16,8 +18,18 @@ use crate::{Error, RequiredVersion};
|
||||||
/// [`MediaSegment`]: crate::MediaSegment
|
/// [`MediaSegment`]: crate::MediaSegment
|
||||||
/// [4.3.2.6. EXT-X-PROGRAM-DATE-TIME]:
|
/// [4.3.2.6. EXT-X-PROGRAM-DATE-TIME]:
|
||||||
/// https://tools.ietf.org/html/rfc8216#section-4.3.2.6
|
/// https://tools.ietf.org/html/rfc8216#section-4.3.2.6
|
||||||
#[derive(Deref, DerefMut, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct ExtXProgramDateTime(DateTime<FixedOffset>);
|
#[cfg_attr(feature = "chrono", derive(Deref, DerefMut, Copy))]
|
||||||
|
pub struct ExtXProgramDateTime {
|
||||||
|
/// The date-time of the first sample of the associated media segment.
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
#[cfg_attr(feature = "chrono", deref_mut, deref)]
|
||||||
|
pub date_time: DateTime<FixedOffset>,
|
||||||
|
/// The date-time of the first sample of the associated media segment.
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
pub date_time: String,
|
||||||
|
__non_exhaustive: (),
|
||||||
|
}
|
||||||
|
|
||||||
impl ExtXProgramDateTime {
|
impl ExtXProgramDateTime {
|
||||||
pub(crate) const PREFIX: &'static str = "#EXT-X-PROGRAM-DATE-TIME:";
|
pub(crate) const PREFIX: &'static str = "#EXT-X-PROGRAM-DATE-TIME:";
|
||||||
|
@ -39,67 +51,28 @@ impl ExtXProgramDateTime {
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(date_time: DateTime<FixedOffset>) -> Self { Self(date_time) }
|
#[cfg(feature = "chrono")]
|
||||||
|
pub const fn new(date_time: DateTime<FixedOffset>) -> Self {
|
||||||
|
Self {
|
||||||
|
date_time,
|
||||||
|
__non_exhaustive: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the date-time of the first sample of the associated media
|
/// Makes a new [`ExtXProgramDateTime`] tag.
|
||||||
/// segment.
|
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use hls_m3u8::tags::ExtXProgramDateTime;
|
/// # use hls_m3u8::tags::ExtXProgramDateTime;
|
||||||
/// use chrono::{FixedOffset, TimeZone};
|
/// let program_date_time = ExtXProgramDateTime::new("2010-02-19T14:54:23.031+08:00");
|
||||||
///
|
|
||||||
/// const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
|
||||||
///
|
|
||||||
/// let program_date_time = ExtXProgramDateTime::new(
|
|
||||||
/// FixedOffset::east(8 * HOURS_IN_SECS)
|
|
||||||
/// .ymd(2010, 2, 19)
|
|
||||||
/// .and_hms_milli(14, 54, 23, 31),
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// assert_eq!(
|
|
||||||
/// program_date_time.date_time(),
|
|
||||||
/// FixedOffset::east(8 * HOURS_IN_SECS)
|
|
||||||
/// .ymd(2010, 2, 19)
|
|
||||||
/// .and_hms_milli(14, 54, 23, 31)
|
|
||||||
/// );
|
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[cfg(not(feature = "chrono"))]
|
||||||
pub const fn date_time(&self) -> DateTime<FixedOffset> { self.0 }
|
pub fn new<T: Into<String>>(date_time: T) -> Self {
|
||||||
|
Self {
|
||||||
/// Sets the date-time of the first sample of the associated media segment.
|
date_time: date_time.into(),
|
||||||
///
|
__non_exhaustive: (),
|
||||||
/// # Example
|
}
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use hls_m3u8::tags::ExtXProgramDateTime;
|
|
||||||
/// use chrono::{FixedOffset, TimeZone};
|
|
||||||
///
|
|
||||||
/// const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
|
||||||
///
|
|
||||||
/// let mut program_date_time = ExtXProgramDateTime::new(
|
|
||||||
/// FixedOffset::east(8 * HOURS_IN_SECS)
|
|
||||||
/// .ymd(2010, 2, 19)
|
|
||||||
/// .and_hms_milli(14, 54, 23, 31),
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// program_date_time.set_date_time(
|
|
||||||
/// FixedOffset::east(8 * HOURS_IN_SECS)
|
|
||||||
/// .ymd(2010, 10, 10)
|
|
||||||
/// .and_hms_milli(10, 10, 10, 10),
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// assert_eq!(
|
|
||||||
/// program_date_time.date_time(),
|
|
||||||
/// FixedOffset::east(8 * HOURS_IN_SECS)
|
|
||||||
/// .ymd(2010, 10, 10)
|
|
||||||
/// .and_hms_milli(10, 10, 10, 10)
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
pub fn set_date_time(&mut self, value: DateTime<FixedOffset>) -> &mut Self {
|
|
||||||
self.0 = value;
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +83,16 @@ impl RequiredVersion for ExtXProgramDateTime {
|
||||||
|
|
||||||
impl fmt::Display for ExtXProgramDateTime {
|
impl fmt::Display for ExtXProgramDateTime {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let date_time = self.0.to_rfc3339_opts(SecondsFormat::Millis, true);
|
let date_time = {
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
self.date_time.to_rfc3339_opts(SecondsFormat::Millis, true)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
&self.date_time
|
||||||
|
}
|
||||||
|
};
|
||||||
write!(f, "{}{}", Self::PREFIX, date_time)
|
write!(f, "{}{}", Self::PREFIX, date_time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +103,17 @@ impl FromStr for ExtXProgramDateTime {
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
let input = tag(input, Self::PREFIX)?;
|
let input = tag(input, Self::PREFIX)?;
|
||||||
|
|
||||||
let date_time = DateTime::parse_from_rfc3339(input).map_err(Error::chrono)?;
|
let date_time = {
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
|
{
|
||||||
|
DateTime::parse_from_rfc3339(input).map_err(Error::chrono)?
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
input
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self::new(date_time))
|
Ok(Self::new(date_time))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,20 +121,30 @@ impl FromStr for ExtXProgramDateTime {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
use chrono::{Datelike, TimeZone};
|
use chrono::{Datelike, TimeZone};
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
use core::ops::DerefMut;
|
use core::ops::DerefMut;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
const HOURS_IN_SECS: i32 = 3600; // 1 hour = 3600 seconds
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXProgramDateTime::new(
|
ExtXProgramDateTime::new({
|
||||||
FixedOffset::east(8 * HOURS_IN_SECS)
|
#[cfg(feature = "chrono")]
|
||||||
.ymd(2010, 2, 19)
|
{
|
||||||
.and_hms_milli(14, 54, 23, 31)
|
FixedOffset::east(8 * HOURS_IN_SECS)
|
||||||
)
|
.ymd(2010, 2, 19)
|
||||||
|
.and_hms_milli(14, 54, 23, 31)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
"2010-02-19T14:54:23.031+08:00"
|
||||||
|
}
|
||||||
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
"#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00".to_string()
|
"#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00".to_string()
|
||||||
);
|
);
|
||||||
|
@ -151,11 +153,18 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXProgramDateTime::new(
|
ExtXProgramDateTime::new({
|
||||||
FixedOffset::east(8 * HOURS_IN_SECS)
|
#[cfg(feature = "chrono")]
|
||||||
.ymd(2010, 2, 19)
|
{
|
||||||
.and_hms_milli(14, 54, 23, 31)
|
FixedOffset::east(8 * HOURS_IN_SECS)
|
||||||
),
|
.ymd(2010, 2, 19)
|
||||||
|
.and_hms_milli(14, 54, 23, 31)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
"2010-02-19T14:54:23.031+08:00"
|
||||||
|
}
|
||||||
|
}),
|
||||||
"#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00"
|
"#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00"
|
||||||
.parse::<ExtXProgramDateTime>()
|
.parse::<ExtXProgramDateTime>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -165,17 +174,25 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_required_version() {
|
fn test_required_version() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXProgramDateTime::new(
|
ExtXProgramDateTime::new({
|
||||||
FixedOffset::east(8 * HOURS_IN_SECS)
|
#[cfg(feature = "chrono")]
|
||||||
.ymd(2010, 2, 19)
|
{
|
||||||
.and_hms_milli(14, 54, 23, 31),
|
FixedOffset::east(8 * HOURS_IN_SECS)
|
||||||
)
|
.ymd(2010, 2, 19)
|
||||||
|
.and_hms_milli(14, 54, 23, 31)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "chrono"))]
|
||||||
|
{
|
||||||
|
"2010-02-19T14:54:23.031+08:00"
|
||||||
|
}
|
||||||
|
})
|
||||||
.required_version(),
|
.required_version(),
|
||||||
ProtocolVersion::V1
|
ProtocolVersion::V1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
fn test_deref() {
|
fn test_deref() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXProgramDateTime::new(
|
ExtXProgramDateTime::new(
|
||||||
|
@ -189,6 +206,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "chrono")]
|
||||||
fn test_deref_mut() {
|
fn test_deref_mut() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ExtXProgramDateTime::new(
|
ExtXProgramDateTime::new(
|
||||||
|
|
Loading…
Reference in a new issue