1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use proc_macro2::{Delimiter, Ident, TokenStream, TokenTree};
use std::iter;
use syn::{Error, Lit, LitBool, LitStr, Result};

pub(crate) trait CollectToResult {
	type Item;

	fn collect_to_result(self) -> Result<Vec<Self::Item>>;
}

impl<Item, I> CollectToResult for I
where
	I: Iterator<Item = Result<Item>>
{
	type Item = Item;

	fn collect_to_result(self) -> Result<Vec<Item>> {
		self.fold(Ok(Vec::new()), |res, code| match (code, res) {
			(Ok(code), Ok(mut codes)) => {
				codes.push(code);
				Ok(codes)
			},
			(Ok(_), Err(errors)) => Err(errors),
			(Err(err), Ok(_)) => Err(err),
			(Err(err), Err(mut errors)) => {
				errors.combine(err);
				Err(errors)
			}
		})
	}
}

pub(crate) trait IntoIdent {
	fn into_ident(self) -> Ident;
}

impl IntoIdent for LitStr {
	fn into_ident(self) -> Ident {
		Ident::new(&self.value(), self.span())
	}
}

pub(crate) trait ExpectLit {
	fn expect_bool(self) -> Result<LitBool>;
	fn expect_str(self) -> Result<LitStr>;
}

impl ExpectLit for Lit {
	fn expect_bool(self) -> Result<LitBool> {
		match self {
			Self::Bool(bool) => Ok(bool),
			_ => Err(Error::new(self.span(), "Expected boolean literal"))
		}
	}

	fn expect_str(self) -> Result<LitStr> {
		match self {
			Self::Str(str) => Ok(str),
			_ => Err(Error::new(self.span(), "Expected string literal"))
		}
	}
}

pub(crate) fn remove_parens(input: TokenStream) -> TokenStream {
	let iter = input.into_iter().flat_map(|tt| {
		if let TokenTree::Group(group) = &tt {
			if group.delimiter() == Delimiter::Parenthesis {
				return Box::new(group.stream().into_iter()) as Box<dyn Iterator<Item = TokenTree>>;
			}
		}
		Box::new(iter::once(tt))
	});
	iter.collect()
}