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
75
76
77
78
79
use proc_macro2::Ident;
use syn::{spanned::Spanned as _, Error, Expr, 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;

	#[allow(clippy::manual_try_fold)] // false positive
	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"))
		}
	}
}

fn expect_lit(expr: Expr) -> syn::Result<Lit> {
	match expr {
		Expr::Lit(lit) => Ok(lit.lit),
		_ => Err(syn::Error::new(expr.span(), "Expected literal"))
	}
}

impl ExpectLit for Expr {
	fn expect_bool(self) -> syn::Result<LitBool> {
		expect_lit(self)?.expect_bool()
	}

	fn expect_str(self) -> syn::Result<LitStr> {
		expect_lit(self)?.expect_str()
	}
}