mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-09-26 13:39:58 +00:00
94 lines
2.6 KiB
Rust
94 lines
2.6 KiB
Rust
use crate::{Error, Result};
|
|
use std::collections::HashSet;
|
|
use std::str;
|
|
|
|
#[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'-' => {}
|
|
_ => {
|
|
return Err(Error::invalid_attribute(self.input.to_string()));
|
|
}
|
|
}
|
|
}
|
|
|
|
Err(Error::missing_value(self.input.to_string()))
|
|
}
|
|
|
|
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 = self.parse_name()?;
|
|
self.visited_keys.insert(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)
|
|
}
|
|
}
|