1+ use std:: collections:: HashSet ;
2+
13use proc_macro2:: Ident ;
24use proc_macro2:: TokenStream ;
35use quote:: format_ident;
46use quote:: quote;
57use syn:: Field ;
68use syn:: ImplGenerics ;
79use syn:: ItemStruct ;
10+ use syn:: WherePredicate ;
811use syn:: parse_quote;
912
1013use crate :: dir_structure_core:: DirStructureCoreInfo ;
@@ -13,7 +16,9 @@ use crate::dir_structure_core::compile_attrs;
1316
1417struct DirStructureForField {
1518 read_code : TokenStream ,
19+ read_bounds : Vec < WherePredicate > ,
1620 write_code : TokenStream ,
21+ write_bounds : Vec < WherePredicate > ,
1722}
1823
1924fn expand_dir_structure_for_field (
@@ -50,48 +55,89 @@ fn expand_dir_structure_for_field(
5055 PathSpec :: SelfPath => quote ! { #path_param_name } ,
5156 } ;
5257 let actual_field_ty_perform = with_newtype. as_ref ( ) . unwrap_or ( field_ty) ;
53- let read_code = if self_path {
58+ let ( read_code, read_bounds ) = if self_path {
5459 // self_path field, just use the path directly
55- quote ! {
56- #field_ty:: from( :: dir_structure:: traits:: vfs:: PathType :: owned( #path_param_name) )
57- }
60+ (
61+ quote ! {
62+ #field_ty:: from( :: dir_structure:: traits:: vfs:: PathType :: owned( #path_param_name) )
63+ } ,
64+ vec ! [ parse_quote! {
65+ #field_ty: :: std:: convert:: From <<<Vfs as :: dir_structure:: traits:: vfs:: VfsCore >:: Path as :: dir_structure:: traits:: vfs:: PathType >:: OwnedPath >
66+ } ] ,
67+ )
5868 } else {
5969 let value_name = format_ident ! ( "__value" ) ;
60- let end_expr = match & with_newtype {
61- Some ( nt) => quote ! {
62- <#nt as :: dir_structure:: traits:: sync:: NewtypeToInner >:: into_inner( #value_name)
63- } ,
64- None => quote ! {
65- #value_name
66- } ,
70+ let ( end_expr, read_bounds) = match & with_newtype {
71+ Some ( nt) => (
72+ quote ! {
73+ <#nt as :: dir_structure:: traits:: sync:: NewtypeToInner >:: into_inner( #value_name)
74+ } ,
75+ vec ! [
76+ parse_quote! {
77+ #nt: :: dir_structure:: traits:: sync:: NewtypeToInner <Inner = #field_ty>
78+ } ,
79+ parse_quote! {
80+ #nt: :: dir_structure:: traits:: sync:: ReadFrom <' vfs, Vfs >
81+ } ,
82+ ] ,
83+ ) ,
84+ None => (
85+ quote ! {
86+ #value_name
87+ } ,
88+ vec ! [ parse_quote! {
89+ #field_ty: :: dir_structure:: traits:: sync:: ReadFrom <' vfs, Vfs >
90+ } ] ,
91+ ) ,
6792 } ;
6893
69- quote ! { {
70- let #value_name = <#actual_field_ty_perform as :: dir_structure:: traits:: sync:: ReadFrom <Vfs >>:: read_from( #actual_path_expr, #vfs_param_name) ?;
71- #end_expr
72- } }
94+ (
95+ quote ! { {
96+ let #value_name = <#actual_field_ty_perform as :: dir_structure:: traits:: sync:: ReadFrom <Vfs >>:: read_from( #actual_path_expr, #vfs_param_name) ?;
97+ #end_expr
98+ } } ,
99+ read_bounds,
100+ )
73101 } ;
74102
75- let write_code = if self_path {
103+ let ( write_code, write_bounds ) = if self_path {
76104 // self_path does not need to write anything
77- quote ! { }
105+ ( quote ! { } , vec ! [ ] )
78106 } else {
79- let writer = match & with_newtype {
80- Some ( nt) => {
81- quote ! { & <#nt as :: dir_structure:: traits:: sync:: FromRefForWriter <' _, ' _, Vfs >>:: from_ref_for_writer( & self . #field_name) }
82- }
83- None => quote ! { & self . #field_name } ,
107+ let ( writer, write_bounds) = match & with_newtype {
108+ Some ( nt) => (
109+ quote ! { & <#nt as :: dir_structure:: traits:: sync:: FromRefForWriter <' _, ' _, Vfs >>:: from_ref_for_writer( & self . #field_name) } ,
110+ vec ! [
111+ parse_quote! {
112+ for <' a> #nt: :: dir_structure:: traits:: sync:: FromRefForWriter <' a, ' vfs, Vfs , Inner = #field_ty>
113+ } ,
114+ parse_quote! {
115+ #nt: :: dir_structure:: traits:: sync:: WriteTo <' vfs, Vfs >
116+ } ,
117+ ] ,
118+ ) ,
119+ None => (
120+ quote ! { & self . #field_name } ,
121+ vec ! [ parse_quote! {
122+ #field_ty: :: dir_structure:: traits:: sync:: WriteTo <' vfs, Vfs >
123+ } ] ,
124+ ) ,
84125 } ;
85- quote ! {
86- :: dir_structure:: traits:: sync:: WriteTo :: write_to( #writer, #actual_path_expr, #vfs_param_name) ?;
87- }
126+ (
127+ quote ! {
128+ :: dir_structure:: traits:: sync:: WriteTo :: write_to( #writer, #actual_path_expr, #vfs_param_name) ?;
129+ } ,
130+ write_bounds,
131+ )
88132 } ;
89133
90134 Ok ( DirStructureForField {
91135 read_code : quote ! {
92136 #field_name: #read_code
93137 } ,
138+ read_bounds,
94139 write_code,
140+ write_bounds,
95141 } )
96142}
97143
@@ -174,11 +220,15 @@ pub fn expand_dir_structure(st: ItemStruct) -> syn::Result<TokenStream> {
174220
175221 let mut field_read_impls = Vec :: new ( ) ;
176222 let mut field_write_impls = Vec :: new ( ) ;
223+ let mut read_bounds_b = HashSet :: new ( ) ;
224+ let mut write_bounds_b = HashSet :: new ( ) ;
177225
178226 for field in & st. fields {
179227 let DirStructureForField {
180228 read_code,
229+ read_bounds,
181230 write_code,
231+ write_bounds,
182232 } = expand_dir_structure_for_field (
183233 ( & impl_generics, name, & ty_generics, where_clause) ,
184234 & path_param_name,
@@ -187,12 +237,17 @@ pub fn expand_dir_structure(st: ItemStruct) -> syn::Result<TokenStream> {
187237 ) ?;
188238 field_read_impls. push ( read_code) ;
189239 field_write_impls. push ( write_code) ;
240+
241+ read_bounds_b. extend ( read_bounds) ;
242+ write_bounds_b. extend ( write_bounds) ;
190243 }
191244
192- #[ cfg_attr( not( feature = "resolve-path" ) , expect( unused_mut) ) ]
193- let mut expanded = quote ! {
245+ let where_read_clause = merge_where_clauses ( where_clause, read_bounds_b) ;
246+ let where_write_clause = merge_where_clauses ( where_clause, write_bounds_b) ;
247+
248+ let expanded = quote ! {
194249 #[ automatically_derived]
195- impl #read_impl_generics :: dir_structure:: traits:: sync:: ReadFrom <' vfs, Vfs > for #name #ty_generics #where_clause {
250+ impl #read_impl_generics :: dir_structure:: traits:: sync:: ReadFrom <' vfs, Vfs > for #name #ty_generics #where_read_clause {
196251 fn read_from( #path_param_name: & Vfs :: Path , #vfs_param_name: :: std:: pin:: Pin <& ' vfs Vfs >) -> :: dir_structure:: error:: Result <Self , <Vfs :: Path as :: dir_structure:: traits:: vfs:: PathType >:: OwnedPath >
197252 where
198253 Self : Sized ,
@@ -203,7 +258,7 @@ pub fn expand_dir_structure(st: ItemStruct) -> syn::Result<TokenStream> {
203258 }
204259 }
205260 #[ automatically_derived]
206- impl #write_impl_generics :: dir_structure:: traits:: sync:: WriteTo <' vfs, Vfs > for #name #ty_generics #where_clause {
261+ impl #write_impl_generics :: dir_structure:: traits:: sync:: WriteTo <' vfs, Vfs > for #name #ty_generics #where_write_clause {
207262 fn write_to( & self , #path_param_name: & Vfs :: Path , #vfs_param_name: :: std:: pin:: Pin <& ' vfs Vfs >) -> :: dir_structure:: error:: Result <( ) , <Vfs :: Path as :: dir_structure:: traits:: vfs:: PathType >:: OwnedPath > {
208263 #( #field_write_impls) *
209264 Ok ( ( ) )
@@ -215,3 +270,26 @@ pub fn expand_dir_structure(st: ItemStruct) -> syn::Result<TokenStream> {
215270
216271 Ok ( expanded)
217272}
273+
274+ fn merge_where_clauses (
275+ original : Option < & syn:: WhereClause > ,
276+ additional : HashSet < WherePredicate > ,
277+ ) -> Option < syn:: WhereClause > {
278+ if original. is_none ( ) && additional. is_empty ( ) {
279+ return None ;
280+ }
281+ let mut predicates = if let Some ( wc) = original {
282+ wc. predicates . clone ( )
283+ } else {
284+ syn:: punctuated:: Punctuated :: new ( )
285+ } ;
286+ for p in additional {
287+ if !predicates. iter ( ) . any ( |q| q == & p) {
288+ predicates. push ( p) ;
289+ }
290+ }
291+ Some ( syn:: WhereClause {
292+ where_token : Default :: default ( ) ,
293+ predicates,
294+ } )
295+ }
0 commit comments