2019-09-06 10:55:00 +00:00
|
|
|
use std::fmt;
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
2019-09-10 09:05:20 +00:00
|
|
|
use getset::{Getters, MutGetters, Setters};
|
|
|
|
|
|
|
|
use crate::attribute::AttributePairs;
|
2019-09-15 14:45:43 +00:00
|
|
|
use crate::types::ProtocolVersion;
|
2019-09-10 09:05:20 +00:00
|
|
|
use crate::utils::{quote, tag, unquote};
|
2019-09-13 14:06:52 +00:00
|
|
|
use crate::Error;
|
2019-09-10 09:05:20 +00:00
|
|
|
|
2019-09-15 14:45:43 +00:00
|
|
|
/// 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)]
|
|
|
|
pub enum SessionData {
|
|
|
|
Value(String),
|
|
|
|
Uri(String),
|
|
|
|
}
|
|
|
|
|
2019-09-06 10:55:00 +00:00
|
|
|
/// [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
|
2019-09-10 09:05:20 +00:00
|
|
|
#[derive(Getters, MutGetters, Setters, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
#[get = "pub"]
|
|
|
|
#[set = "pub"]
|
|
|
|
#[get_mut = "pub"]
|
2019-09-06 10:55:00 +00:00
|
|
|
pub struct ExtXSessionData {
|
2019-09-10 09:05:20 +00:00
|
|
|
/// The identifier of the data.
|
2019-09-08 09:30:52 +00:00
|
|
|
data_id: String,
|
2019-09-10 09:05:20 +00:00
|
|
|
/// The session data.
|
2019-09-06 10:55:00 +00:00
|
|
|
data: SessionData,
|
2019-09-10 09:05:20 +00:00
|
|
|
/// The language of the data.
|
2019-09-08 09:30:52 +00:00
|
|
|
language: Option<String>,
|
2019-09-06 10:55:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ExtXSessionData {
|
|
|
|
pub(crate) const PREFIX: &'static str = "#EXT-X-SESSION-DATA:";
|
|
|
|
|
|
|
|
/// Makes a new `ExtXSessionData` tag.
|
2019-09-08 09:30:52 +00:00
|
|
|
pub fn new<T: ToString>(data_id: T, data: SessionData) -> Self {
|
2019-09-06 10:55:00 +00:00
|
|
|
ExtXSessionData {
|
2019-09-08 09:30:52 +00:00
|
|
|
data_id: data_id.to_string(),
|
2019-09-06 10:55:00 +00:00
|
|
|
data,
|
|
|
|
language: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Makes a new `ExtXSessionData` with the given language.
|
2019-09-08 09:30:52 +00:00
|
|
|
pub fn with_language<T: ToString>(data_id: T, data: SessionData, language: T) -> Self {
|
2019-09-06 10:55:00 +00:00
|
|
|
ExtXSessionData {
|
2019-09-08 09:30:52 +00:00
|
|
|
data_id: data_id.to_string(),
|
2019-09-06 10:55:00 +00:00
|
|
|
data,
|
2019-09-08 09:30:52 +00:00
|
|
|
language: Some(language.to_string()),
|
2019-09-06 10:55:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the protocol compatibility version that this tag requires.
|
2019-09-08 10:23:33 +00:00
|
|
|
pub const fn requires_version(&self) -> ProtocolVersion {
|
2019-09-06 10:55:00 +00:00
|
|
|
ProtocolVersion::V1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for ExtXSessionData {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", Self::PREFIX)?;
|
2019-09-08 09:30:52 +00:00
|
|
|
write!(f, "DATA-ID={}", quote(&self.data_id))?;
|
2019-09-14 19:42:06 +00:00
|
|
|
match &self.data {
|
|
|
|
SessionData::Value(value) => write!(f, ",VALUE={}", quote(value))?,
|
|
|
|
SessionData::Uri(value) => write!(f, ",URI={}", quote(value))?,
|
2019-09-06 10:55:00 +00:00
|
|
|
}
|
2019-09-14 19:42:06 +00:00
|
|
|
if let Some(value) = &self.language {
|
|
|
|
write!(f, ",LANGUAGE={}", quote(value))?;
|
2019-09-06 10:55:00 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for ExtXSessionData {
|
|
|
|
type Err = Error;
|
2019-09-08 10:23:33 +00:00
|
|
|
|
2019-09-10 09:05:20 +00:00
|
|
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
|
|
|
let input = tag(input, Self::PREFIX)?;
|
2019-09-06 10:55:00 +00:00
|
|
|
|
|
|
|
let mut data_id = None;
|
|
|
|
let mut session_value = None;
|
|
|
|
let mut uri = None;
|
|
|
|
let mut language = None;
|
2019-09-10 09:05:20 +00:00
|
|
|
|
2019-09-14 09:31:16 +00:00
|
|
|
for (key, value) in input.parse::<AttributePairs>()? {
|
|
|
|
match key.as_str() {
|
2019-09-08 09:30:52 +00:00
|
|
|
"DATA-ID" => data_id = Some(unquote(value)),
|
|
|
|
"VALUE" => session_value = Some(unquote(value)),
|
|
|
|
"URI" => uri = Some(unquote(value)),
|
|
|
|
"LANGUAGE" => language = Some(unquote(value)),
|
2019-09-06 10:55:00 +00:00
|
|
|
_ => {
|
|
|
|
// [6.3.1. General Client Responsibilities]
|
|
|
|
// > ignore any attribute/value pair with an unrecognized AttributeName.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-14 09:31:16 +00:00
|
|
|
let data_id = data_id.ok_or(Error::missing_value("EXT-X-DATA-ID"))?;
|
2019-09-13 14:06:52 +00:00
|
|
|
let data = {
|
|
|
|
if let Some(value) = session_value {
|
|
|
|
if uri.is_some() {
|
|
|
|
return Err(Error::invalid_input());
|
|
|
|
} else {
|
|
|
|
SessionData::Value(value)
|
|
|
|
}
|
|
|
|
} else if let Some(uri) = uri {
|
|
|
|
SessionData::Uri(uri)
|
|
|
|
} else {
|
|
|
|
return Err(Error::invalid_input());
|
|
|
|
}
|
2019-09-06 10:55:00 +00:00
|
|
|
};
|
2019-09-13 14:06:52 +00:00
|
|
|
|
2019-09-06 10:55:00 +00:00
|
|
|
Ok(ExtXSessionData {
|
|
|
|
data_id,
|
|
|
|
data,
|
|
|
|
language,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
2019-09-10 09:05:20 +00:00
|
|
|
fn test_display() {
|
2019-09-08 09:30:52 +00:00
|
|
|
let tag = ExtXSessionData::new("foo", SessionData::Value("bar".into()));
|
2019-09-06 10:55:00 +00:00
|
|
|
let text = r#"#EXT-X-SESSION-DATA:DATA-ID="foo",VALUE="bar""#;
|
|
|
|
assert_eq!(tag.to_string(), text);
|
|
|
|
|
2019-09-08 09:30:52 +00:00
|
|
|
let tag = ExtXSessionData::new("foo", SessionData::Uri("bar".into()));
|
2019-09-06 10:55:00 +00:00
|
|
|
let text = r#"#EXT-X-SESSION-DATA:DATA-ID="foo",URI="bar""#;
|
|
|
|
assert_eq!(tag.to_string(), text);
|
|
|
|
|
2019-09-08 09:30:52 +00:00
|
|
|
let tag = ExtXSessionData::with_language("foo", SessionData::Value("bar".into()), "baz");
|
2019-09-06 10:55:00 +00:00
|
|
|
let text = r#"#EXT-X-SESSION-DATA:DATA-ID="foo",VALUE="bar",LANGUAGE="baz""#;
|
|
|
|
assert_eq!(tag.to_string(), text);
|
2019-09-10 09:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parser() {
|
|
|
|
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::<ExtXSessionData>().unwrap(), tag);
|
|
|
|
|
|
|
|
let tag = ExtXSessionData::new("foo", SessionData::Uri("bar".into()));
|
|
|
|
let text = r#"#EXT-X-SESSION-DATA:DATA-ID="foo",URI="bar""#;
|
|
|
|
assert_eq!(text.parse::<ExtXSessionData>().unwrap(), tag);
|
|
|
|
|
|
|
|
let tag = ExtXSessionData::with_language("foo", SessionData::Value("bar".into()), "baz");
|
|
|
|
let text = r#"#EXT-X-SESSION-DATA:DATA-ID="foo",VALUE="bar",LANGUAGE="baz""#;
|
|
|
|
assert_eq!(text.parse::<ExtXSessionData>().unwrap(), tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_requires_version() {
|
|
|
|
let tag = ExtXSessionData::new("foo", SessionData::Value("bar".into()));
|
2019-09-06 10:55:00 +00:00
|
|
|
assert_eq!(tag.requires_version(), ProtocolVersion::V1);
|
|
|
|
}
|
|
|
|
}
|