From e0f90a8e384615c79d7d51c66d19294d75e79391 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 27 Aug 2022 23:41:41 +0200 Subject: feat: implement named bindings --- macros/src/dependency.rs | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 macros/src/dependency.rs (limited to 'macros/src/dependency.rs') diff --git a/macros/src/dependency.rs b/macros/src/dependency.rs new file mode 100644 index 0000000..d20af90 --- /dev/null +++ b/macros/src/dependency.rs @@ -0,0 +1,81 @@ +use std::error::Error; + +use proc_macro2::Ident; +use syn::{parse2, FnArg, GenericArgument, LitStr, PathArguments, Type}; + +use crate::named_attr_input::NamedAttrInput; +use crate::util::syn_path::syn_path_to_string; + +pub struct Dependency +{ + pub interface: Type, + pub ptr: Ident, + pub name: Option, +} + +impl Dependency +{ + pub fn build(new_method_arg: &FnArg) -> Result> + { + let typed_new_method_arg = match new_method_arg { + FnArg::Typed(typed_arg) => Ok(typed_arg), + FnArg::Receiver(_) => Err("Unexpected self argument in 'new' method"), + }?; + + let ptr_type_path = match typed_new_method_arg.ty.as_ref() { + Type::Path(arg_type_path) => Ok(arg_type_path), + Type::Reference(ref_type_path) => match ref_type_path.elem.as_ref() { + Type::Path(arg_type_path) => Ok(arg_type_path), + &_ => Err("Unexpected reference to non-path type"), + }, + &_ => Err("Expected a path or a reference type"), + }?; + + let ptr_path_segment = ptr_type_path.path.segments.last().map_or_else( + || Err("Expected pointer type path to have a last segment"), + Ok, + )?; + + let ptr = ptr_path_segment.ident.clone(); + + let ptr_path_generic_args = &match &ptr_path_segment.arguments { + PathArguments::AngleBracketed(generic_args) => Ok(generic_args), + &_ => Err("Expected pointer type to have a generic type argument"), + }? + .args; + + let interface = if let Some(GenericArgument::Type(interface)) = + ptr_path_generic_args.first() + { + Ok(interface.clone()) + } else { + Err("Expected pointer type to have a generic type argument") + }?; + + let arg_attrs = &typed_new_method_arg.attrs; + + let opt_named_attr = arg_attrs.iter().find(|attr| { + attr.path.get_ident().map_or_else( + || false, + |attr_ident| attr_ident.to_string().as_str() == "named", + ) || syn_path_to_string(&attr.path) == "syrette::named" + }); + + let opt_named_attr_tokens = opt_named_attr.map(|attr| &attr.tokens); + + let opt_named_attr_input = + if let Some(named_attr_tokens) = opt_named_attr_tokens { + Some(parse2::(named_attr_tokens.clone()).map_err( + |err| format!("Invalid input for 'named' attribute. {}", err), + )?) + } else { + None + }; + + Ok(Self { + interface, + ptr, + name: opt_named_attr_input.map(|named_attr_input| named_attr_input.name), + }) + } +} -- cgit v1.2.3-18-g5258