codama_syn_helpers/extensions/
meta_list.rs

1use crate::Meta;
2use syn::{punctuated::Punctuated, MetaList};
3
4pub trait MetaListExtension {
5    fn get_self(&self) -> &MetaList;
6
7    /// Iterate over all metas in the list.
8    fn each(&self, logic: impl FnMut(Meta) -> syn::Result<()>) -> syn::Result<()> {
9        self.parse_metas()?.into_iter().try_for_each(logic)
10    }
11
12    /// Parse all metas in the list.
13    fn parse_metas(&self) -> syn::Result<Vec<Meta>> {
14        self.parse_comma_args::<Meta>()
15    }
16
17    /// Parse all arguments as comma-separated types.
18    fn parse_comma_args<T: syn::parse::Parse>(&self) -> syn::Result<Vec<T>> {
19        self.get_self()
20            .parse_args_with(Punctuated::<T, syn::Token![,]>::parse_terminated)
21            .map(|metas| metas.into_iter().collect::<Vec<_>>())
22    }
23}
24
25impl MetaListExtension for MetaList {
26    fn get_self(&self) -> &MetaList {
27        self
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34    use crate::extensions::*;
35
36    #[test]
37    fn each() {
38        let list = syn::parse_str::<MetaList>("foo(one, two, three = 42)").unwrap();
39        let mut items = Vec::new();
40        list.each(|meta| {
41            items.push(meta);
42            Ok(())
43        })
44        .unwrap();
45
46        assert_eq!(items.len(), 3);
47        assert!(items[0].as_path().unwrap().is_strict("one"));
48        assert!(items[1].as_path().unwrap().is_strict("two"));
49        let meta = items[2].as_path_value().unwrap();
50        let expr = meta.value.as_expr().unwrap();
51        assert!(meta.path.is_strict("three"));
52        assert_eq!(expr.as_unsigned_integer::<usize>().unwrap(), 42);
53    }
54}