aboutsummaryrefslogtreecommitdiff
path: root/src/parse_attrs.rs
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2021-11-25 08:49:47 +0100
committerMartin Fischer <martin@push-f.com>2021-11-25 09:34:50 +0100
commit06a384000b0a6c7b657e4f8a9145b3d4357f3d70 (patch)
treedd28fbfc23d7067d07285f9528d097bcf3ca8899 /src/parse_attrs.rs
parent0acd72140f5e1b854d6a30d27de11785b0be8a63 (diff)
refactor: factor out parse_attrs module
Diffstat (limited to 'src/parse_attrs.rs')
-rw-r--r--src/parse_attrs.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/parse_attrs.rs b/src/parse_attrs.rs
new file mode 100644
index 0000000..03b5377
--- /dev/null
+++ b/src/parse_attrs.rs
@@ -0,0 +1,93 @@
+use std::collections::HashMap;
+
+use proc_macro2::{Group, TokenStream};
+use quote::quote;
+use syn::{parenthesized, parse::Parse, Attribute, Error, Ident, LitInt, Token};
+
+struct Collection {
+ pub id: Ident,
+ pub count: usize,
+}
+
+impl Parse for Collection {
+ fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let inner;
+ parenthesized!(inner in input);
+
+ let id: Ident = inner.parse()?;
+ let _: Token![,] = inner.parse()?;
+ let count_lit: LitInt = inner.parse()?;
+ let count: usize = count_lit.base10_parse()?;
+ if count < 1 {
+ return Err(Error::new(
+ count_lit.span(),
+ "number of type parameters must be >= 1",
+ ));
+ }
+ Ok(Self { id, count })
+ }
+}
+
+#[derive(Default)]
+pub struct TraitAttrs {
+ pub blanket_impl_attrs: Vec<TokenStream>,
+ pub dyn_trait_attrs: Vec<TokenStream>,
+ pub collections: HashMap<Ident, usize>,
+}
+
+impl TraitAttrs {
+ pub fn parse(attrs: &mut Vec<Attribute>) -> Result<Self, Error> {
+ let mut parsed = TraitAttrs::default();
+ // FUTURE: use Vec::drain_filter once it's stable
+ let mut i = 0;
+ while i < attrs.len() {
+ if attrs[i].path.is_ident("blanket_impl_attr") {
+ let attr = attrs.remove(i);
+ let group: Group = match syn::parse2(attr.tokens) {
+ Ok(g) => g,
+ Err(err) => {
+ return Err(Error::new(
+ err.span(),
+ "expected parenthesis: #[blanket_impl_attr(...)]",
+ ))
+ }
+ };
+ let tokens = group.stream();
+ parsed.blanket_impl_attrs.push(quote! {#[#tokens]});
+ } else if attrs[i].path.is_ident("dyn_trait_attr") {
+ let attr = attrs.remove(i);
+ let group: Group = match syn::parse2(attr.tokens) {
+ Ok(g) => g,
+ Err(err) => {
+ return Err(Error::new(
+ err.span(),
+ "expected parenthesis: #[dyn_trait_attr(...)]",
+ ))
+ }
+ };
+ let tokens = group.stream();
+ parsed.dyn_trait_attrs.push(quote! {#[#tokens]});
+ } else if attrs[i].path.is_ident("collection") {
+ let attr = attrs.remove(i);
+ let coll: Collection = syn::parse2(attr.tokens)?;
+
+ if parsed
+ .collections
+ .insert(coll.id.clone(), coll.count)
+ .is_some()
+ {
+ return Err(Error::new(
+ coll.id.span(),
+ format_args!(
+ "collection `{}` is defined multiple times for this trait",
+ coll.id
+ ),
+ ));
+ }
+ } else {
+ i += 1;
+ }
+ }
+ Ok(parsed)
+ }
+}