use crate::{prelude::*, Error};
pub fn parse_tagged_attribute(group: &Group, prefix: &str) -> Result<Option<Vec<ParsedAttribute>>> {
let stream = &mut group.stream().into_iter();
if let Some(TokenTree::Ident(attribute_ident)) = stream.next() {
#[allow(clippy::cmp_owned)] if attribute_ident.to_string() == prefix {
if let Some(TokenTree::Group(group)) = stream.next() {
let mut result = Vec::new();
let mut stream = group.stream().into_iter().peekable();
while let Some(token) = stream.next() {
match (token, stream.peek()) {
(TokenTree::Ident(key), Some(TokenTree::Punct(p)))
if p.as_char() == ',' =>
{
result.push(ParsedAttribute::Tag(key));
stream.next();
}
(TokenTree::Ident(key), None) => {
result.push(ParsedAttribute::Tag(key));
stream.next();
}
(TokenTree::Ident(key), Some(TokenTree::Punct(p)))
if p.as_char() == '=' =>
{
stream.next();
if let Some(TokenTree::Literal(lit)) = stream.next() {
result.push(ParsedAttribute::Property(key, lit));
match stream.next() {
Some(TokenTree::Punct(p)) if p.as_char() == ',' => {}
None => {}
x => {
return Err(Error::custom_at_opt_token("Expected `,`", x));
}
}
}
}
(x, _) => {
return Err(Error::custom_at(
"Expected `key` or `key = \"val\"`",
x.span(),
));
}
}
}
return Ok(Some(result));
}
}
}
Ok(None)
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum ParsedAttribute {
Tag(Ident),
Property(Ident, Literal),
}
#[test]
fn test_parse_tagged_attribute() {
let group: Group = match crate::token_stream("[prefix(result, foo = \"bar\", baz)]").next() {
Some(TokenTree::Group(group)) => group,
x => panic!("Unexpected token {:?}", x),
};
let attributes = parse_tagged_attribute(&group, "prefix").unwrap().unwrap();
let mut iter = attributes.into_iter();
match iter.next() {
Some(ParsedAttribute::Tag(i)) => {
assert_eq!(i.to_string(), String::from("result"));
}
x => panic!("Unexpected attribute: {:?}", x),
}
match iter.next() {
Some(ParsedAttribute::Property(key, val)) => {
assert_eq!(key.to_string(), String::from("foo"));
assert_eq!(val.to_string(), String::from("\"bar\""));
}
x => panic!("Unexpected attribute: {:?}", x),
}
match iter.next() {
Some(ParsedAttribute::Tag(i)) => {
assert_eq!(i.to_string(), String::from("baz"));
}
x => panic!("Unexpected attribute: {:?}", x),
}
}