summaryrefslogtreecommitdiff
path: root/src/codegen/from_derive_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/from_derive_impl.rs')
-rw-r--r--src/codegen/from_derive_impl.rs148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/codegen/from_derive_impl.rs b/src/codegen/from_derive_impl.rs
new file mode 100644
index 0000000..d64d9e2
--- /dev/null
+++ b/src/codegen/from_derive_impl.rs
@@ -0,0 +1,148 @@
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+use syn::Ident;
+
+use crate::{
+ ast::Data,
+ codegen::{ExtractAttribute, OuterFromImpl, TraitImpl},
+ options::DeriveInputShapeSet,
+ util::PathList,
+};
+
+use super::ForwardAttrs;
+
+pub struct FromDeriveInputImpl<'a> {
+ pub ident: Option<&'a Ident>,
+ pub generics: Option<&'a Ident>,
+ pub vis: Option<&'a Ident>,
+ pub data: Option<&'a Ident>,
+ pub base: TraitImpl<'a>,
+ pub attr_names: &'a PathList,
+ pub forward_attrs: ForwardAttrs<'a>,
+ pub from_ident: bool,
+ pub supports: Option<&'a DeriveInputShapeSet>,
+}
+
+impl<'a> ToTokens for FromDeriveInputImpl<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let ty_ident = self.base.ident;
+ let input = self.param_name();
+ let post_transform = self.base.post_transform_call();
+
+ if let Data::Struct(ref data) = self.base.data {
+ if data.is_newtype() {
+ self.wrap(
+ quote!{
+ fn from_derive_input(#input: &::darling::export::syn::DeriveInput) -> ::darling::Result<Self> {
+ ::darling::export::Ok(
+ #ty_ident(::darling::FromDeriveInput::from_derive_input(#input)?)
+ ) #post_transform
+ }
+ },
+ tokens,
+ );
+
+ return;
+ }
+ }
+
+ let passed_ident = self
+ .ident
+ .as_ref()
+ .map(|i| quote!(#i: #input.ident.clone(),));
+ let passed_vis = self.vis.as_ref().map(|i| quote!(#i: #input.vis.clone(),));
+ let passed_generics = self
+ .generics
+ .as_ref()
+ .map(|i| quote!(#i: ::darling::FromGenerics::from_generics(&#input.generics)?,));
+ let passed_attrs = self.forward_attrs.as_initializer();
+ let passed_body = self
+ .data
+ .as_ref()
+ .map(|i| quote!(#i: ::darling::ast::Data::try_from(&#input.data)?,));
+
+ let supports = self.supports.map(|i| {
+ quote! {
+ #i
+ __errors.handle(__validate_body(&#input.data));
+ }
+ });
+
+ let inits = self.base.initializers();
+ let default = if self.from_ident {
+ quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
+ } else {
+ self.base.fallback_decl()
+ };
+
+ let grab_attrs = self.extractor();
+
+ let declare_errors = self.base.declare_errors();
+ let require_fields = self.base.require_fields();
+ let check_errors = self.base.check_errors();
+
+ self.wrap(
+ quote! {
+ fn from_derive_input(#input: &::darling::export::syn::DeriveInput) -> ::darling::Result<Self> {
+ #declare_errors
+
+ #grab_attrs
+
+ #supports
+
+ #require_fields
+
+ #check_errors
+
+ #default
+
+ ::darling::export::Ok(#ty_ident {
+ #passed_ident
+ #passed_generics
+ #passed_vis
+ #passed_attrs
+ #passed_body
+ #inits
+ }) #post_transform
+ }
+ },
+ tokens,
+ );
+ }
+}
+
+impl<'a> ExtractAttribute for FromDeriveInputImpl<'a> {
+ fn attr_names(&self) -> &PathList {
+ self.attr_names
+ }
+
+ fn forward_attrs(&self) -> &ForwardAttrs {
+ &self.forward_attrs
+ }
+
+ fn param_name(&self) -> TokenStream {
+ quote!(__di)
+ }
+
+ fn core_loop(&self) -> TokenStream {
+ self.base.core_loop()
+ }
+
+ fn local_declarations(&self) -> TokenStream {
+ self.base.local_declarations()
+ }
+}
+
+impl<'a> OuterFromImpl<'a> for FromDeriveInputImpl<'a> {
+ fn trait_path(&self) -> syn::Path {
+ path!(::darling::FromDeriveInput)
+ }
+
+ fn trait_bound(&self) -> syn::Path {
+ path!(::darling::FromMeta)
+ }
+
+ fn base(&'a self) -> &'a TraitImpl<'a> {
+ &self.base
+ }
+}