use {
super::AssociatedTypes,
crate::{
core::{
Result,
constants::macros::KIND_MACRO,
},
generate_name,
},
proc_macro2::TokenStream,
quote::quote,
syn::{
AngleBracketedGenericArguments,
Ident,
Token,
Type,
parse::{
Parse,
ParseStream,
},
},
};
#[derive(Debug)]
pub struct ApplyInput {
pub brand: Type,
pub kind_input: AssociatedTypes,
pub assoc_name: Ident,
pub args: AngleBracketedGenericArguments,
}
impl Parse for ApplyInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
input.parse::<Token![<]>()?;
let brand: Type = input.parse()?;
input.parse::<Token![as]>()?;
let kind_ident: Ident = input.parse()?;
if kind_ident != KIND_MACRO {
return Err(syn::Error::new(kind_ident.span(), format!("expected `{KIND_MACRO}`")));
}
input.parse::<Token![!]>()?;
let content;
syn::parenthesized!(content in input);
let kind_input: AssociatedTypes = content.parse()?;
input.parse::<Token![>]>()?;
input.parse::<Token![::]>()?;
let assoc_name: Ident = input.parse()?;
let args: AngleBracketedGenericArguments = input.parse()?;
Ok(ApplyInput {
brand,
kind_input,
assoc_name,
args,
})
}
}
pub fn apply_worker(input: ApplyInput) -> Result<TokenStream> {
let brand = &input.brand;
let kind_name = generate_name(&input.kind_input)?;
let assoc_name = &input.assoc_name;
let args = &input.args;
Ok(quote! {
<#brand as #kind_name>::#assoc_name #args
})
}
#[cfg(test)]
#[expect(clippy::expect_used, reason = "Tests use panicking operations for brevity and clarity")]
mod tests {
use {
super::*,
syn::parse_str,
};
#[test]
fn test_parse_apply_new_syntax() {
let input = "<OptionBrand as Kind!(type Of<'a, T>: 'a;)>::Of<'static, i32>";
let parsed: ApplyInput = parse_str(input).expect("Failed to parse ApplyInput");
assert_eq!(parsed.assoc_name.to_string(), "Of");
assert_eq!(parsed.kind_input.associated_types.len(), 1);
assert_eq!(parsed.args.args.len(), 2);
}
#[test]
fn test_apply_generation_new_syntax() {
let input = "<OptionBrand as Kind!(type Of<'a, T>: 'a;)>::Of<'static, i32>";
let parsed: ApplyInput = parse_str(input).expect("Failed to parse ApplyInput");
let output = apply_worker(parsed).expect("apply_worker failed");
let output_str = output.to_string();
assert!(output_str.contains("< OptionBrand as Kind_"));
assert!(output_str.contains(":: Of < 'static , i32 >"));
}
}