pub fn type_to_string(ty: &syn::Type) -> String {
quote::quote!(#ty).to_string().replace(' ', "")
}
fn is_known_arc_path(path: &syn::Path) -> bool {
let s: Vec<String> = path
.segments
.iter()
.map(|seg| seg.ident.to_string())
.collect();
match s.as_slice() {
[a] => a == "Arc",
[a, b] => a == "sync" && b == "Arc",
[a, b, c] => (a == "std" || a == "alloc") && b == "sync" && c == "Arc",
_ => false,
}
}
fn is_known_inject_path(path: &syn::Path) -> bool {
let s: Vec<String> = path
.segments
.iter()
.map(|seg| seg.ident.to_string())
.collect();
match s.as_slice() {
[a] => a == "Inject",
[a, b] => (a == "injectable" || a == "injectable_rs_runtime") && b == "Inject",
_ => false,
}
}
fn extract_first_generic_type(segment: &syn::PathSegment) -> Option<syn::Type> {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
return Some(inner_ty.clone());
}
}
None
}
pub fn extract_arc_inner(ty: &syn::Type) -> Option<syn::Type> {
if let syn::Type::Path(type_path) = ty {
if is_known_arc_path(&type_path.path) {
let last = type_path.path.segments.last()?;
return extract_first_generic_type(last);
}
}
None
}
pub fn extract_arc_inner_str(ty: &syn::Type) -> Option<String> {
extract_arc_inner(ty).map(|inner| type_to_string(&inner))
}
pub fn extract_inject_inner(ty: &syn::Type) -> Option<String> {
if let syn::Type::Path(type_path) = ty {
if is_known_inject_path(&type_path.path) {
let last = type_path.path.segments.last()?;
return extract_first_generic_type(last).map(|t| type_to_string(&t));
}
}
None
}
pub fn extract_inject_dyn_inner(ty: &syn::Type) -> Option<syn::Type> {
if let syn::Type::Path(type_path) = ty {
if is_known_inject_path(&type_path.path) {
let last = type_path.path.segments.last()?;
let inner = extract_first_generic_type(last)?;
if matches!(inner, syn::Type::TraitObject(_)) {
return Some(inner);
}
}
}
None
}
pub fn extract_option_inject_dyn_inner(ty: &syn::Type) -> Option<syn::Type> {
if let syn::Type::Path(tp) = ty {
let segs: Vec<_> = tp
.path
.segments
.iter()
.map(|s| s.ident.to_string())
.collect();
let is_option =
matches!(segs.last().map(String::as_str), Some("Option")) && segs.len() <= 3;
if is_option {
let last = tp.path.segments.last()?;
let inner = extract_first_generic_type(last)?;
return extract_inject_dyn_inner(&inner);
}
}
None
}