@@ -699,35 +699,111 @@ pub fn parse_struct_to_schema(
699699}
700700
701701fn substitute_type ( ty : & Type , generic_params : & [ String ] , concrete_types : & [ & Type ] ) -> Type {
702- // Check if this is a generic parameter
703- if let Type :: Path ( type_path) = ty
704- && let Some ( segment) = type_path. path . segments . last ( )
705- {
706- let ident_str = segment. ident . to_string ( ) ;
707- if generic_params. contains ( & ident_str) && segment. arguments . is_none ( ) {
708- // Find the index and substitute
709- if let Some ( index) = generic_params. iter ( ) . position ( |p| p == & ident_str)
710- && let Some ( concrete_ty) = concrete_types. get ( index)
711- {
712- return ( * concrete_ty) . clone ( ) ;
702+ match ty {
703+ Type :: Path ( type_path) => {
704+ let path = & type_path. path ;
705+ if path. segments . is_empty ( ) {
706+ return ty. clone ( ) ;
713707 }
714- }
715- }
716708
717- // For complex types, use quote! to regenerate with substitutions
718- let tokens = quote:: quote! { #ty } ;
719- let mut new_tokens = tokens. to_string ( ) ;
709+ // Check if this is a direct generic parameter (e.g., just "T" with no arguments)
710+ if path. segments . len ( ) == 1 {
711+ let segment = & path. segments [ 0 ] ;
712+ let ident_str = segment. ident . to_string ( ) ;
713+
714+ if let syn:: PathArguments :: None = & segment. arguments {
715+ // Direct generic parameter substitution
716+ if let Some ( index) = generic_params. iter ( ) . position ( |p| p == & ident_str) {
717+ if let Some ( concrete_ty) = concrete_types. get ( index) {
718+ return ( * concrete_ty) . clone ( ) ;
719+ }
720+ }
721+ }
722+ }
720723
721- // Replace generic parameter names with concrete types
722- for ( param, concrete_ty) in generic_params. iter ( ) . zip ( concrete_types. iter ( ) ) {
723- // Replace standalone generic parameter (not part of another identifier)
724- let pattern = format ! ( r"\b{}\b" , param) ;
725- let replacement = quote:: quote! { #concrete_ty } . to_string ( ) ;
726- new_tokens = new_tokens. replace ( & pattern, & replacement) ;
727- }
724+ // For types with generic arguments (e.g., Vec<T>, Option<T>, HashMap<K, V>),
725+ // recursively substitute the type arguments
726+ let mut new_segments = syn:: punctuated:: Punctuated :: new ( ) ;
727+ for segment in & path. segments {
728+ let new_arguments = match & segment. arguments {
729+ syn:: PathArguments :: AngleBracketed ( args) => {
730+ let mut new_args = syn:: punctuated:: Punctuated :: new ( ) ;
731+ for arg in & args. args {
732+ let new_arg = match arg {
733+ syn:: GenericArgument :: Type ( inner_ty) => {
734+ syn:: GenericArgument :: Type ( substitute_type (
735+ inner_ty,
736+ generic_params,
737+ concrete_types,
738+ ) )
739+ }
740+ other => other. clone ( ) ,
741+ } ;
742+ new_args. push ( new_arg) ;
743+ }
744+ syn:: PathArguments :: AngleBracketed ( syn:: AngleBracketedGenericArguments {
745+ colon2_token : args. colon2_token ,
746+ lt_token : args. lt_token ,
747+ args : new_args,
748+ gt_token : args. gt_token ,
749+ } )
750+ }
751+ other => other. clone ( ) ,
752+ } ;
728753
729- // Parse the substituted type
730- syn:: parse_str :: < Type > ( & new_tokens) . unwrap_or_else ( |_| ty. clone ( ) )
754+ new_segments. push ( syn:: PathSegment {
755+ ident : segment. ident . clone ( ) ,
756+ arguments : new_arguments,
757+ } ) ;
758+ }
759+
760+ Type :: Path ( syn:: TypePath {
761+ qself : type_path. qself . clone ( ) ,
762+ path : syn:: Path {
763+ leading_colon : path. leading_colon ,
764+ segments : new_segments,
765+ } ,
766+ } )
767+ }
768+ Type :: Reference ( type_ref) => {
769+ // Handle &T, &mut T
770+ Type :: Reference ( syn:: TypeReference {
771+ and_token : type_ref. and_token ,
772+ lifetime : type_ref. lifetime . clone ( ) ,
773+ mutability : type_ref. mutability ,
774+ elem : Box :: new ( substitute_type ( & type_ref. elem , generic_params, concrete_types) ) ,
775+ } )
776+ }
777+ Type :: Slice ( type_slice) => {
778+ // Handle [T]
779+ Type :: Slice ( syn:: TypeSlice {
780+ bracket_token : type_slice. bracket_token ,
781+ elem : Box :: new ( substitute_type ( & type_slice. elem , generic_params, concrete_types) ) ,
782+ } )
783+ }
784+ Type :: Array ( type_array) => {
785+ // Handle [T; N]
786+ Type :: Array ( syn:: TypeArray {
787+ bracket_token : type_array. bracket_token ,
788+ elem : Box :: new ( substitute_type ( & type_array. elem , generic_params, concrete_types) ) ,
789+ semi_token : type_array. semi_token ,
790+ len : type_array. len . clone ( ) ,
791+ } )
792+ }
793+ Type :: Tuple ( type_tuple) => {
794+ // Handle (T1, T2, ...)
795+ let new_elems = type_tuple
796+ . elems
797+ . iter ( )
798+ . map ( |elem| substitute_type ( elem, generic_params, concrete_types) )
799+ . collect ( ) ;
800+ Type :: Tuple ( syn:: TypeTuple {
801+ paren_token : type_tuple. paren_token ,
802+ elems : new_elems,
803+ } )
804+ }
805+ _ => ty. clone ( ) ,
806+ }
731807}
732808
733809pub ( super ) fn is_primitive_type ( ty : & Type ) -> bool {
0 commit comments