1
0
Fork 0
mirror of https://github.com/sile/hls_m3u8.git synced 2024-06-01 19:43:39 +00:00
hls_m3u8/src/attribute.rs
2018-02-18 23:36:52 +09:00

105 lines
2.9 KiB
Rust

use std::collections::HashSet;
use std::str;
use {ErrorKind, Result};
#[derive(Debug)]
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> {
for i in 0..self.input.len() {
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'-' => {}
_ => track_panic!(
ErrorKind::InvalidInput,
"Malformed attribute name: {:?}",
self.input
),
}
}
track_panic!(
ErrorKind::InvalidInput,
"No attribute value: {:?}",
self.input
);
}
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> {
if self.input.is_empty() {
return None;
}
let result = || -> Result<(&'a str, &'a str)> {
let key = track!(self.parse_name())?;
track_assert!(
self.visited_keys.insert(key),
ErrorKind::InvalidInput,
"Duplicate attribute key: {:?}",
key
);
let value = self.parse_raw_value();
Ok((key, value))
}();
Some(result)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_works() {
let mut pairs = AttributePairs::parse("FOO=BAR,BAR=\"baz,qux\",ABC=12.3");
assert_eq!(pairs.next().map(|x| x.ok()), Some(Some(("FOO", "BAR"))));
assert_eq!(
pairs.next().map(|x| x.ok()),
Some(Some(("BAR", "\"baz,qux\"")))
);
assert_eq!(pairs.next().map(|x| x.ok()), Some(Some(("ABC", "12.3"))));
assert_eq!(pairs.next().map(|x| x.ok()), None)
}
}