mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-11-22 15:21:01 +00:00
Rewrote AttributePairs
This commit is contained in:
parent
c8f3df1228
commit
3721106795
11 changed files with 168 additions and 129 deletions
196
src/attribute.rs
196
src/attribute.rs
|
@ -1,94 +1,136 @@
|
||||||
use crate::{Error, Result};
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::str;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Debug)]
|
use crate::Error;
|
||||||
pub struct AttributePairs<'a> {
|
|
||||||
input: &'a str,
|
|
||||||
visited_keys: HashSet<&'a str>,
|
|
||||||
}
|
|
||||||
impl<'a> AttributePairs<'a> {
|
|
||||||
pub fn parse(input: &'a str) -> Self {
|
|
||||||
AttributePairs {
|
|
||||||
input,
|
|
||||||
visited_keys: HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_name(&mut self) -> Result<&'a str> {
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
for i in 0..self.input.len() {
|
pub struct AttributePairs(HashMap<String, String>);
|
||||||
match self.input.as_bytes()[i] {
|
|
||||||
b'=' => {
|
|
||||||
let (key, _) = self.input.split_at(i);
|
|
||||||
let (_, rest) = self.input.split_at(i + 1);
|
|
||||||
self.input = rest;
|
|
||||||
return Ok(key);
|
|
||||||
}
|
|
||||||
b'A'..=b'Z' | b'0'..=b'9' | b'-' => {}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::invalid_attribute(self.input.to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::missing_value(self.input.to_string()))
|
impl AttributePairs {
|
||||||
}
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
fn parse_raw_value(&mut self) -> &'a str {
|
|
||||||
let mut in_quote = false;
|
|
||||||
let mut value_end = self.input.len();
|
|
||||||
let mut next = self.input.len();
|
|
||||||
for (i, c) in self.input.bytes().enumerate() {
|
|
||||||
match c {
|
|
||||||
b'"' => {
|
|
||||||
in_quote = !in_quote;
|
|
||||||
}
|
|
||||||
b',' if !in_quote => {
|
|
||||||
value_end = i;
|
|
||||||
next = i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let (value, _) = self.input.split_at(value_end);
|
|
||||||
let (_, rest) = self.input.split_at(next);
|
|
||||||
self.input = rest;
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Iterator for AttributePairs<'a> {
|
|
||||||
type Item = Result<(&'a str, &'a str)>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
impl Deref for AttributePairs {
|
||||||
if self.input.is_empty() {
|
type Target = HashMap<String, String>;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = || -> Result<(&'a str, &'a str)> {
|
fn deref(&self) -> &Self::Target {
|
||||||
let key = self.parse_name()?;
|
&self.0
|
||||||
self.visited_keys.insert(key);
|
|
||||||
|
|
||||||
let value = self.parse_raw_value();
|
|
||||||
Ok((key, value))
|
|
||||||
}();
|
|
||||||
Some(result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DerefMut for AttributePairs {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for AttributePairs {
|
||||||
|
type Item = (String, String);
|
||||||
|
type IntoIter = ::std::collections::hash_map::IntoIter<String, String>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a AttributePairs {
|
||||||
|
type Item = (&'a String, &'a String);
|
||||||
|
type IntoIter = ::std::collections::hash_map::Iter<'a, String, String>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for AttributePairs {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut result = AttributePairs::new();
|
||||||
|
|
||||||
|
for line in split(input) {
|
||||||
|
let pair = line.trim().split("=").collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if pair.len() < 2 {
|
||||||
|
return Err(Error::invalid_input());
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = pair[0].to_uppercase();
|
||||||
|
let value = pair[1].to_string();
|
||||||
|
|
||||||
|
result.insert(key.to_string(), value.to_string());
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split(value: &str) -> Vec<String> {
|
||||||
|
let mut result = vec![];
|
||||||
|
|
||||||
|
let mut inside_quotes = false;
|
||||||
|
let mut temp_string = String::new();
|
||||||
|
|
||||||
|
for c in value.chars() {
|
||||||
|
match c {
|
||||||
|
'"' => {
|
||||||
|
if inside_quotes {
|
||||||
|
inside_quotes = false;
|
||||||
|
} else {
|
||||||
|
inside_quotes = true;
|
||||||
|
}
|
||||||
|
temp_string.push(c);
|
||||||
|
}
|
||||||
|
',' => {
|
||||||
|
if !inside_quotes {
|
||||||
|
result.push(temp_string);
|
||||||
|
temp_string = String::new();
|
||||||
|
} else {
|
||||||
|
temp_string.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
temp_string.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(temp_string);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn test_parser() {
|
||||||
let mut pairs = AttributePairs::parse("FOO=BAR,BAR=\"baz,qux\",ABC=12.3");
|
let pairs = ("FOO=BAR,BAR=\"baz,qux\",ABC=12.3")
|
||||||
assert_eq!(pairs.next().map(|x| x.ok()), Some(Some(("FOO", "BAR"))));
|
.parse::<AttributePairs>()
|
||||||
assert_eq!(
|
.unwrap();
|
||||||
pairs.next().map(|x| x.ok()),
|
|
||||||
Some(Some(("BAR", "\"baz,qux\"")))
|
let mut iterator = pairs.iter();
|
||||||
);
|
assert!(iterator.any(|(k, v)| k == "FOO" && "BAR" == v));
|
||||||
assert_eq!(pairs.next().map(|x| x.ok()), Some(Some(("ABC", "12.3"))));
|
|
||||||
assert_eq!(pairs.next().map(|x| x.ok()), None)
|
let mut iterator = pairs.iter();
|
||||||
|
assert!(iterator.any(|(k, v)| k == "BAR" && v == "\"baz,qux\""));
|
||||||
|
|
||||||
|
let mut iterator = pairs.iter();
|
||||||
|
assert!(iterator.any(|(k, v)| k == "ABC" && v == "12.3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_iterator() {
|
||||||
|
let mut attrs = AttributePairs::new();
|
||||||
|
attrs.insert("key_01".to_string(), "value_01".to_string());
|
||||||
|
attrs.insert("key_02".to_string(), "value_02".to_string());
|
||||||
|
|
||||||
|
let mut iterator = attrs.iter();
|
||||||
|
assert!(iterator.any(|(k, v)| k == "key_01" && v == "value_01"));
|
||||||
|
|
||||||
|
let mut iterator = attrs.iter();
|
||||||
|
assert!(iterator.any(|(k, v)| k == "key_02" && v == "value_02"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
src/error.rs
13
src/error.rs
|
@ -46,6 +46,9 @@ pub enum ErrorKind {
|
||||||
#[fail(display = "Unknown Protocol version: {:?}", _0)]
|
#[fail(display = "Unknown Protocol version: {:?}", _0)]
|
||||||
UnknownProtocolVersion(String),
|
UnknownProtocolVersion(String),
|
||||||
|
|
||||||
|
#[fail(display = "IoError: {}", _0)]
|
||||||
|
Io(String),
|
||||||
|
|
||||||
/// Hints that destructuring should not be exhaustive.
|
/// Hints that destructuring should not be exhaustive.
|
||||||
///
|
///
|
||||||
/// This enum may grow additional variants, so this makes sure clients
|
/// This enum may grow additional variants, so this makes sure clients
|
||||||
|
@ -164,6 +167,10 @@ impl Error {
|
||||||
pub(crate) fn unknown_protocol_version<T: ToString>(value: T) -> Self {
|
pub(crate) fn unknown_protocol_version<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::UnknownProtocolVersion(value.to_string()))
|
Self::from(ErrorKind::UnknownProtocolVersion(value.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn io<T: ToString>(value: T) -> Self {
|
||||||
|
Self::from(ErrorKind::Io(value.to_string()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::num::ParseIntError> for Error {
|
impl From<std::num::ParseIntError> for Error {
|
||||||
|
@ -177,3 +184,9 @@ impl From<std::num::ParseFloatError> for Error {
|
||||||
Error::parse_float_error(value)
|
Error::parse_float_error(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(value: ::std::io::Error) -> Self {
|
||||||
|
Error::io(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -94,10 +94,8 @@ impl FromStr for ExtXIFrameStreamInf {
|
||||||
let mut hdcp_level = None;
|
let mut hdcp_level = None;
|
||||||
let mut video = None;
|
let mut video = None;
|
||||||
|
|
||||||
let attrs = AttributePairs::parse(input);
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
for attr in attrs {
|
match key.as_str() {
|
||||||
let (key, value) = attr?;
|
|
||||||
match key {
|
|
||||||
"URI" => uri = Some(unquote(value)),
|
"URI" => uri = Some(unquote(value)),
|
||||||
"BANDWIDTH" => bandwidth = Some(parse_u64(value)?),
|
"BANDWIDTH" => bandwidth = Some(parse_u64(value)?),
|
||||||
"AVERAGE-BANDWIDTH" => average_bandwidth = Some(parse_u64(value)?),
|
"AVERAGE-BANDWIDTH" => average_bandwidth = Some(parse_u64(value)?),
|
||||||
|
|
|
@ -331,10 +331,9 @@ impl FromStr for ExtXMedia {
|
||||||
let input = tag(input, Self::PREFIX)?;
|
let input = tag(input, Self::PREFIX)?;
|
||||||
|
|
||||||
let mut builder = ExtXMediaBuilder::new();
|
let mut builder = ExtXMediaBuilder::new();
|
||||||
let attrs = AttributePairs::parse(input);
|
|
||||||
for attr in attrs {
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
let (key, value) = attr?;
|
match key.as_str() {
|
||||||
match key {
|
|
||||||
"TYPE" => {
|
"TYPE" => {
|
||||||
builder.media_type(value.parse()?);
|
builder.media_type(value.parse()?);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,8 @@ impl FromStr for ExtXSessionData {
|
||||||
let mut uri = None;
|
let mut uri = None;
|
||||||
let mut language = None;
|
let mut language = None;
|
||||||
|
|
||||||
let attrs = AttributePairs::parse(input);
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
for attr in attrs {
|
match key.as_str() {
|
||||||
let (key, value) = attr?;
|
|
||||||
match key {
|
|
||||||
"DATA-ID" => data_id = Some(unquote(value)),
|
"DATA-ID" => data_id = Some(unquote(value)),
|
||||||
"VALUE" => session_value = Some(unquote(value)),
|
"VALUE" => session_value = Some(unquote(value)),
|
||||||
"URI" => uri = Some(unquote(value)),
|
"URI" => uri = Some(unquote(value)),
|
||||||
|
@ -92,7 +90,7 @@ impl FromStr for ExtXSessionData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_id = data_id.ok_or(Error::missing_value("DATA-ID"))?;
|
let data_id = data_id.ok_or(Error::missing_value("EXT-X-DATA-ID"))?;
|
||||||
let data = {
|
let data = {
|
||||||
if let Some(value) = session_value {
|
if let Some(value) = session_value {
|
||||||
if uri.is_some() {
|
if uri.is_some() {
|
||||||
|
|
|
@ -149,10 +149,10 @@ impl FromStr for ExtXStreamInf {
|
||||||
|
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
let mut lines = input.lines();
|
let mut lines = input.lines();
|
||||||
let first_line = lines.next().ok_or(Error::invalid_input())?; // TODO!
|
let first_line = lines.next().ok_or(Error::missing_value("first_line"))?;
|
||||||
let second_line = lines.next().ok_or(Error::invalid_input())?; // TODO!
|
let second_line = lines.next().ok_or(Error::missing_value("second_line"))?;
|
||||||
|
|
||||||
tag(first_line, Self::PREFIX)?;
|
let first_line = tag(first_line, Self::PREFIX)?;
|
||||||
|
|
||||||
let uri = SingleLineString::new(second_line)?;
|
let uri = SingleLineString::new(second_line)?;
|
||||||
|
|
||||||
|
@ -167,10 +167,8 @@ impl FromStr for ExtXStreamInf {
|
||||||
let mut subtitles = None;
|
let mut subtitles = None;
|
||||||
let mut closed_captions = None;
|
let mut closed_captions = None;
|
||||||
|
|
||||||
let attrs = AttributePairs::parse(first_line.split_at(Self::PREFIX.len()).1);
|
for (key, value) in first_line.parse::<AttributePairs>()? {
|
||||||
for attr in attrs {
|
match key.as_str() {
|
||||||
let (key, value) = (attr)?;
|
|
||||||
match key {
|
|
||||||
"BANDWIDTH" => bandwidth = Some((parse_u64(value))?),
|
"BANDWIDTH" => bandwidth = Some((parse_u64(value))?),
|
||||||
"AVERAGE-BANDWIDTH" => average_bandwidth = Some((parse_u64(value))?),
|
"AVERAGE-BANDWIDTH" => average_bandwidth = Some((parse_u64(value))?),
|
||||||
"CODECS" => codecs = Some(unquote(value)),
|
"CODECS" => codecs = Some(unquote(value)),
|
||||||
|
@ -188,7 +186,7 @@ impl FromStr for ExtXStreamInf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let bandwidth = bandwidth.ok_or(Error::missing_value("BANDWIDTH"))?;
|
let bandwidth = bandwidth.ok_or(Error::missing_value("EXT-X-BANDWIDTH"))?;
|
||||||
|
|
||||||
Ok(ExtXStreamInf {
|
Ok(ExtXStreamInf {
|
||||||
uri,
|
uri,
|
||||||
|
|
|
@ -96,11 +96,9 @@ impl FromStr for ExtXDateRange {
|
||||||
let mut end_on_next = false;
|
let mut end_on_next = false;
|
||||||
|
|
||||||
let mut client_attributes = BTreeMap::new();
|
let mut client_attributes = BTreeMap::new();
|
||||||
let attrs = AttributePairs::parse(input);
|
|
||||||
|
|
||||||
for attr in attrs {
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
let (key, value) = attr?;
|
match key.as_str() {
|
||||||
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" => start_date = Some(unquote(value)),
|
||||||
|
|
|
@ -10,33 +10,31 @@ use crate::Error;
|
||||||
///
|
///
|
||||||
/// [4.3.2.4. EXT-X-KEY]: https://tools.ietf.org/html/rfc8216#section-4.3.2.4
|
/// [4.3.2.4. EXT-X-KEY]: https://tools.ietf.org/html/rfc8216#section-4.3.2.4
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ExtXKey {
|
pub struct ExtXKey(Option<DecryptionKey>);
|
||||||
key: Option<DecryptionKey>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExtXKey {
|
impl ExtXKey {
|
||||||
pub(crate) const PREFIX: &'static str = "#EXT-X-KEY:";
|
pub(crate) const PREFIX: &'static str = "#EXT-X-KEY:";
|
||||||
|
|
||||||
/// Makes a new `ExtXKey` tag.
|
/// Makes a new `ExtXKey` tag.
|
||||||
pub const fn new(key: DecryptionKey) -> Self {
|
pub const fn new(key: DecryptionKey) -> Self {
|
||||||
ExtXKey { key: Some(key) }
|
Self(Some(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `ExtXKey` tag without a decryption key.
|
/// Makes a new `ExtXKey` tag without a decryption key.
|
||||||
///
|
///
|
||||||
/// This tag has the `METHDO=NONE` attribute.
|
/// This tag has the `METHDO=NONE` attribute.
|
||||||
pub const fn new_without_key() -> Self {
|
pub const fn new_without_key() -> Self {
|
||||||
ExtXKey { key: None }
|
Self(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the decryption key for the following media segments and media initialization sections.
|
/// Returns the decryption key for the following media segments and media initialization sections.
|
||||||
pub fn key(&self) -> Option<&DecryptionKey> {
|
pub fn key(&self) -> Option<&DecryptionKey> {
|
||||||
self.key.as_ref()
|
self.0.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the protocol compatibility version that this tag requires.
|
/// Returns the protocol compatibility version that this tag requires.
|
||||||
pub fn requires_version(&self) -> ProtocolVersion {
|
pub fn requires_version(&self) -> ProtocolVersion {
|
||||||
self.key
|
self.0
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(ProtocolVersion::V1, |k| k.requires_version())
|
.map_or(ProtocolVersion::V1, |k| k.requires_version())
|
||||||
}
|
}
|
||||||
|
@ -45,7 +43,7 @@ impl ExtXKey {
|
||||||
impl fmt::Display for ExtXKey {
|
impl fmt::Display for ExtXKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", Self::PREFIX)?;
|
write!(f, "{}", Self::PREFIX)?;
|
||||||
if let Some(ref key) = self.key {
|
if let Some(ref key) = self.0 {
|
||||||
write!(f, "{}", key)?;
|
write!(f, "{}", key)?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "METHOD=NONE")?;
|
write!(f, "METHOD=NONE")?;
|
||||||
|
@ -60,17 +58,18 @@ impl FromStr for ExtXKey {
|
||||||
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)?;
|
||||||
|
|
||||||
if AttributePairs::parse(input).any(|a| a.as_ref().ok() == Some(&("METHOD", "NONE"))) {
|
let pairs = input.parse::<AttributePairs>()?;
|
||||||
for attr in AttributePairs::parse(input) {
|
|
||||||
let (key, _) = attr?;
|
if pairs.iter().any(|(k, v)| k == "METHOD" && v == "NONE") {
|
||||||
|
for (key, _) in pairs {
|
||||||
if key == "URI" || key == "IV" || key == "KEYFORMAT" || key == "KEYFORMATVERSIONS" {
|
if key == "URI" || key == "IV" || key == "KEYFORMAT" || key == "KEYFORMATVERSIONS" {
|
||||||
return Err(Error::invalid_input());
|
return Err(Error::invalid_input());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ExtXKey { key: None })
|
|
||||||
|
Ok(Self(None))
|
||||||
} else {
|
} else {
|
||||||
let key = input.parse()?;
|
Ok(Self(Some(input.parse()?)))
|
||||||
Ok(ExtXKey { key: Some(key) })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,10 +69,9 @@ impl FromStr for ExtXMap {
|
||||||
|
|
||||||
let mut uri = None;
|
let mut uri = None;
|
||||||
let mut range = None;
|
let mut range = None;
|
||||||
let attrs = AttributePairs::parse(input);
|
|
||||||
for attr in attrs {
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
let (key, value) = (attr)?;
|
match key.as_str() {
|
||||||
match key {
|
|
||||||
"URI" => uri = Some(unquote(value)),
|
"URI" => uri = Some(unquote(value)),
|
||||||
"BYTERANGE" => {
|
"BYTERANGE" => {
|
||||||
range = Some((unquote(value).parse())?);
|
range = Some((unquote(value).parse())?);
|
||||||
|
|
|
@ -71,11 +71,8 @@ impl FromStr for ExtXStart {
|
||||||
let mut time_offset = None;
|
let mut time_offset = None;
|
||||||
let mut precise = false;
|
let mut precise = false;
|
||||||
|
|
||||||
let attrs = AttributePairs::parse(input);
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
|
match key.as_str() {
|
||||||
for attr in attrs {
|
|
||||||
let (key, value) = (attr)?;
|
|
||||||
match key {
|
|
||||||
"TIME-OFFSET" => time_offset = Some((value.parse())?),
|
"TIME-OFFSET" => time_offset = Some((value.parse())?),
|
||||||
"PRECISE" => precise = (parse_yes_or_no(value))?,
|
"PRECISE" => precise = (parse_yes_or_no(value))?,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -60,10 +60,8 @@ impl FromStr for DecryptionKey {
|
||||||
let mut key_format = None;
|
let mut key_format = None;
|
||||||
let mut key_format_versions = None;
|
let mut key_format_versions = None;
|
||||||
|
|
||||||
let attrs = AttributePairs::parse(input);
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
for attr in attrs {
|
match key.as_str() {
|
||||||
let (key, value) = (attr)?;
|
|
||||||
match key {
|
|
||||||
"METHOD" => method = Some((value.parse())?),
|
"METHOD" => method = Some((value.parse())?),
|
||||||
"URI" => uri = Some(unquote(value)),
|
"URI" => uri = Some(unquote(value)),
|
||||||
"IV" => iv = Some((value.parse())?),
|
"IV" => iv = Some((value.parse())?),
|
||||||
|
|
Loading…
Reference in a new issue