diff options
Diffstat (limited to 'syrette_macros/src/injectable_impl.rs')
-rw-r--r-- | syrette_macros/src/injectable_impl.rs | 245 |
1 files changed, 0 insertions, 245 deletions
diff --git a/syrette_macros/src/injectable_impl.rs b/syrette_macros/src/injectable_impl.rs deleted file mode 100644 index 3000253..0000000 --- a/syrette_macros/src/injectable_impl.rs +++ /dev/null @@ -1,245 +0,0 @@ -use quote::{quote, ToTokens}; -use syn::parse::{Parse, ParseStream}; -use syn::{ - parse_str, punctuated::Punctuated, token::Comma, ExprMethodCall, FnArg, - GenericArgument, Ident, ImplItem, ImplItemMethod, ItemImpl, Path, PathArguments, - Type, TypePath, -}; - -const DI_CONTAINER_VAR_NAME: &str = "di_container"; - -pub struct InjectableImpl -{ - pub dependency_types: Vec<Type>, - pub self_type: Type, - pub original_impl: ItemImpl, -} - -impl Parse for InjectableImpl -{ - fn parse(input: ParseStream) -> syn::Result<Self> - { - match input.parse::<ItemImpl>() { - Ok(impl_parsed_input) => { - match Self::_get_dependency_types(&impl_parsed_input) { - Ok(dependency_types) => Ok(Self { - dependency_types, - self_type: impl_parsed_input.self_ty.as_ref().clone(), - original_impl: impl_parsed_input, - }), - Err(error_msg) => Err(input.error(error_msg)), - } - } - Err(_) => Err(input.error("Expected an impl")), - } - } -} - -impl InjectableImpl -{ - pub fn expand(&self) -> proc_macro2::TokenStream - { - let original_impl = &self.original_impl; - let self_type = &self.self_type; - - let di_container_var: Ident = parse_str(DI_CONTAINER_VAR_NAME).unwrap(); - - let get_dependencies = Self::_create_get_dependencies(&self.dependency_types); - - quote! { - #original_impl - - impl syrette::interfaces::injectable::Injectable for #self_type { - fn resolve( - #di_container_var: &syrette::DIContainer - ) -> error_stack::Result< - syrette::ptr::InterfacePtr<Self>, - syrette::errors::injectable::ResolveError> - { - use error_stack::ResultExt; - - return Ok(syrette::ptr::InterfacePtr::new(Self::new( - #(#get_dependencies - .change_context(syrette::errors::injectable::ResolveError) - .attach_printable( - format!( - "Unable to resolve a dependency of {}", - std::any::type_name::<#self_type>() - ) - )? - ),* - ))); - } - } - } - } - - fn _create_get_dependencies(dependency_types: &[Type]) -> Vec<ExprMethodCall> - { - dependency_types - .iter() - .filter_map(|dep_type| match dep_type { - Type::TraitObject(dep_type_trait) => Some( - parse_str( - format!( - "{}.get::<{}>()", - DI_CONTAINER_VAR_NAME, - dep_type_trait.to_token_stream() - ) - .as_str(), - ) - .unwrap(), - ), - Type::Path(dep_type_path) => { - let dep_type_path_str = Self::_path_to_string(&dep_type_path.path); - - let get_method_name = if dep_type_path_str.ends_with("Factory") { - "get_factory" - } else { - "get" - }; - - Some( - parse_str( - format!( - "{}.{}::<{}>()", - DI_CONTAINER_VAR_NAME, get_method_name, dep_type_path_str - ) - .as_str(), - ) - .unwrap(), - ) - } - &_ => None, - }) - .collect() - } - - fn _find_method_by_name<'impl_lt>( - item_impl: &'impl_lt ItemImpl, - method_name: &'static str, - ) -> Option<&'impl_lt ImplItemMethod> - { - let impl_items = &item_impl.items; - - impl_items - .iter() - .filter_map(|impl_item| match impl_item { - ImplItem::Method(method_item) => Some(method_item), - &_ => None, - }) - .find(|method_item| method_item.sig.ident == method_name) - } - - #[allow(clippy::match_wildcard_for_single_variants)] - fn get_has_fn_args_self(fn_args: &Punctuated<FnArg, Comma>) -> bool - { - fn_args.iter().any(|arg| match arg { - FnArg::Receiver(_) => true, - &_ => false, - }) - } - - fn _get_fn_arg_type_paths(fn_args: &Punctuated<FnArg, Comma>) -> Vec<&TypePath> - { - fn_args - .iter() - .filter_map(|arg| match arg { - FnArg::Typed(typed_fn_arg) => match typed_fn_arg.ty.as_ref() { - Type::Path(arg_type_path) => Some(arg_type_path), - Type::Reference(ref_type_path) => match ref_type_path.elem.as_ref() { - Type::Path(arg_type_path) => Some(arg_type_path), - &_ => None, - }, - &_ => None, - }, - FnArg::Receiver(_receiver_fn_arg) => None, - }) - .collect() - } - - fn _path_to_string(path: &Path) -> String - { - path.segments - .pairs() - .fold(String::new(), |mut acc, segment_pair| { - let segment_ident = &segment_pair.value().ident; - - acc.push_str(segment_ident.to_string().as_str()); - - let opt_colon_two = segment_pair.punct(); - - match opt_colon_two { - Some(colon_two) => { - acc.push_str(colon_two.to_token_stream().to_string().as_str()); - } - None => {} - } - - acc - }) - } - - fn _is_type_path_ptr(type_path: &TypePath) -> bool - { - let arg_type_path_string = Self::_path_to_string(&type_path.path); - - arg_type_path_string == "InterfacePtr" - || arg_type_path_string == "ptr::InterfacePtr" - || arg_type_path_string == "syrrete::ptr::InterfacePtr" - || arg_type_path_string == "FactoryPtr" - || arg_type_path_string == "ptr::FactoryPtr" - || arg_type_path_string == "syrrete::ptr::FactoryPtr" - } - - fn _get_dependency_types(item_impl: &ItemImpl) -> Result<Vec<Type>, &'static str> - { - let new_method_impl_item = match Self::_find_method_by_name(item_impl, "new") { - Some(method_item) => Ok(method_item), - None => Err("Missing a 'new' method"), - }?; - - let new_method_args = &new_method_impl_item.sig.inputs; - - if Self::get_has_fn_args_self(new_method_args) { - return Err("Unexpected self argument in 'new' method"); - } - - let new_method_arg_type_paths = Self::_get_fn_arg_type_paths(new_method_args); - - if new_method_arg_type_paths - .iter() - .any(|arg_type_path| !Self::_is_type_path_ptr(arg_type_path)) - { - return Err("All argument types in 'new' method must ptr types"); - } - - Ok(new_method_arg_type_paths - .iter() - .filter_map(|arg_type_path| { - // Assume the type path has a last segment. - let last_path_segment = arg_type_path.path.segments.last().unwrap(); - - match &last_path_segment.arguments { - PathArguments::AngleBracketed(angle_bracketed_generic_args) => { - let generic_args = &angle_bracketed_generic_args.args; - - let opt_first_generic_arg = generic_args.first(); - - // Assume a first generic argument exists because InterfacePtr and - // FactoryPtr requires one - let first_generic_arg = opt_first_generic_arg.as_ref().unwrap(); - - match first_generic_arg { - GenericArgument::Type(first_generic_arg_type) => { - Some(first_generic_arg_type.clone()) - } - &_ => None, - } - } - &_ => None, - } - }) - .collect()) - } -} |