2019-09-14 09:31:16 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
use crate::Error;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
|
|
|
pub struct AttributePairs(HashMap<String, String>);
|
|
|
|
|
|
|
|
impl AttributePairs {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
2018-02-11 06:10:52 +00:00
|
|
|
}
|
2019-09-14 09:31:16 +00:00
|
|
|
|
|
|
|
impl Deref for AttributePairs {
|
|
|
|
type Target = HashMap<String, String>;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
2018-02-11 06:10:52 +00:00
|
|
|
}
|
2019-09-14 09:31:16 +00:00
|
|
|
}
|
2018-02-11 06:10:52 +00:00
|
|
|
|
2019-09-14 09:31:16 +00:00
|
|
|
impl DerefMut for AttributePairs {
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
&mut self.0
|
|
|
|
}
|
|
|
|
}
|
2019-09-13 14:06:52 +00:00
|
|
|
|
2019-09-14 09:31:16 +00:00
|
|
|
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()
|
2018-02-11 06:10:52 +00:00
|
|
|
}
|
2019-09-14 09:31:16 +00:00
|
|
|
}
|
2018-02-11 06:10:52 +00:00
|
|
|
|
2019-09-14 09:31:16 +00:00
|
|
|
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();
|
|
|
|
|
2019-09-15 14:45:43 +00:00
|
|
|
for line in split(input, ',') {
|
|
|
|
let pair = split(line.trim(), '=');
|
2019-09-14 09:31:16 +00:00
|
|
|
|
|
|
|
if pair.len() < 2 {
|
|
|
|
return Err(Error::invalid_input());
|
2018-02-18 14:36:52 +00:00
|
|
|
}
|
2019-09-14 09:31:16 +00:00
|
|
|
|
|
|
|
let key = pair[0].to_uppercase();
|
|
|
|
let value = pair[1].to_string();
|
|
|
|
|
|
|
|
result.insert(key.to_string(), value.to_string());
|
2018-02-18 14:36:52 +00:00
|
|
|
}
|
2019-09-15 14:45:43 +00:00
|
|
|
|
2019-09-21 13:20:19 +00:00
|
|
|
#[cfg(test)]
|
2019-09-15 14:45:43 +00:00
|
|
|
dbg!(&result);
|
2019-09-14 09:31:16 +00:00
|
|
|
Ok(result)
|
2018-02-11 06:10:52 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-13 14:06:52 +00:00
|
|
|
|
2019-09-15 14:45:43 +00:00
|
|
|
fn split(value: &str, terminator: char) -> Vec<String> {
|
2019-09-14 09:31:16 +00:00
|
|
|
let mut result = vec![];
|
2018-02-11 06:10:52 +00:00
|
|
|
|
2019-09-14 09:31:16 +00:00
|
|
|
let mut inside_quotes = false;
|
|
|
|
let mut temp_string = String::new();
|
2018-02-14 15:24:35 +00:00
|
|
|
|
2019-09-14 09:31:16 +00:00
|
|
|
for c in value.chars() {
|
|
|
|
match c {
|
|
|
|
'"' => {
|
|
|
|
if inside_quotes {
|
|
|
|
inside_quotes = false;
|
|
|
|
} else {
|
|
|
|
inside_quotes = true;
|
|
|
|
}
|
|
|
|
temp_string.push(c);
|
|
|
|
}
|
2019-09-15 14:45:43 +00:00
|
|
|
k if (k == terminator) => {
|
2019-09-14 09:31:16 +00:00
|
|
|
if !inside_quotes {
|
|
|
|
result.push(temp_string);
|
|
|
|
temp_string = String::new();
|
|
|
|
} else {
|
|
|
|
temp_string.push(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
temp_string.push(c);
|
|
|
|
}
|
|
|
|
}
|
2018-02-11 06:10:52 +00:00
|
|
|
}
|
2019-09-14 09:31:16 +00:00
|
|
|
result.push(temp_string);
|
|
|
|
|
|
|
|
result
|
2018-02-11 06:10:52 +00:00
|
|
|
}
|
2018-02-18 14:36:52 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
2019-09-14 09:31:16 +00:00
|
|
|
fn test_parser() {
|
|
|
|
let pairs = ("FOO=BAR,BAR=\"baz,qux\",ABC=12.3")
|
|
|
|
.parse::<AttributePairs>()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let mut iterator = pairs.iter();
|
|
|
|
assert!(iterator.any(|(k, v)| k == "FOO" && "BAR" == v));
|
|
|
|
|
|
|
|
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"));
|
2018-02-18 14:36:52 +00:00
|
|
|
}
|
|
|
|
}
|