Skip to content

Commit c499bff

Browse files
committed
generate as_variant methods for downcasting
1 parent ddbb916 commit c499bff

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

crates/formality-macros/src/cast.rs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use proc_macro2::TokenStream;
2-
use quote::quote;
1+
use convert_case::{Case, Casing};
2+
use proc_macro2::{Ident, TokenStream};
3+
use quote::{quote, quote_spanned};
34
use syn::Type;
45
use synstructure::VariantInfo;
56

@@ -79,7 +80,7 @@ fn downcast_to_variant(s: &synstructure::Structure, v: &VariantInfo) -> TokenStr
7980
}
8081
});
8182

82-
s.gen_impl(quote! {
83+
let mut ts = s.gen_impl(quote! {
8384
use formality_core::{DowncastTo};
8485

8586
gen impl DowncastTo<(#(#binding_tys),*)> for @Self {
@@ -89,5 +90,44 @@ fn downcast_to_variant(s: &synstructure::Structure, v: &VariantInfo) -> TokenStr
8990
}
9091
}
9192
}
92-
})
93+
});
94+
95+
if binding_tys.len() == 1 && matches!(s.ast().data, syn::Data::Enum(_)) {
96+
let binding_ty = &binding_tys[0];
97+
let type_name = &s.ast().ident;
98+
let variant_name = &v.ast().ident;
99+
let as_method_name = Ident::new(
100+
&format!("as_{}", variant_name.to_string().to_case(Case::Snake)),
101+
v.ast().ident.span(),
102+
);
103+
let (impl_generics, type_generics, where_clauses) = s.ast().generics.split_for_impl();
104+
105+
let match_arms = s.each_variant(|variant_info| {
106+
if variant_info.ast().ident == v.ast().ident {
107+
let bindings = variant_info.bindings();
108+
let binding_idents: Vec<&syn::Ident> =
109+
bindings.iter().map(|b| &b.binding).collect();
110+
quote! { Some((#(#binding_idents),*)) }
111+
} else {
112+
quote! { None }
113+
}
114+
});
115+
116+
let as_impl = quote_spanned! { v.ast().ident.span() =>
117+
#[allow(dead_code)]
118+
impl #impl_generics #type_name #type_generics
119+
where #where_clauses
120+
{
121+
pub fn #as_method_name(&self) -> Option<& #binding_ty> {
122+
match self {
123+
#match_arms
124+
}
125+
}
126+
}
127+
};
128+
129+
ts.extend(as_impl);
130+
}
131+
132+
ts
93133
}

crates/formality-macros/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use spec::FormalitySpec;
55

66
extern crate proc_macro;
77

8+
mod as_methods;
89
mod attrs;
910
mod cast;
1011
mod custom;

0 commit comments

Comments
 (0)