@@ -2,7 +2,7 @@ use crate::parsing::*;
2
2
use convert_case:: { Case , Casing } ;
3
3
use proc_macro_crate:: FoundCrate ;
4
4
use proc_macro2:: TokenStream as TokenStream2 ;
5
- use quote:: { format_ident, quote} ;
5
+ use quote:: { format_ident, quote, quote_spanned } ;
6
6
use std:: sync:: atomic:: AtomicU64 ;
7
7
use syn:: punctuated:: Punctuated ;
8
8
use syn:: spanned:: Spanned ;
@@ -134,14 +134,22 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
134
134
let number_min_values: Vec < _ > = fields
135
135
. iter ( )
136
136
. map ( |field| match field {
137
- ParsedField :: Regular { number_min : Some ( number_min) , .. } => quote ! ( Some ( #number_min) ) ,
137
+ ParsedField :: Regular { number_soft_min, number_hard_min, .. } => match ( number_soft_min, number_hard_min) {
138
+ ( Some ( soft_min) , _) => quote ! ( Some ( #soft_min) ) ,
139
+ ( None , Some ( hard_min) ) => quote ! ( Some ( #hard_min) ) ,
140
+ ( None , None ) => quote ! ( None ) ,
141
+ } ,
138
142
_ => quote ! ( None ) ,
139
143
} )
140
144
. collect ( ) ;
141
145
let number_max_values: Vec < _ > = fields
142
146
. iter ( )
143
147
. map ( |field| match field {
144
- ParsedField :: Regular { number_max : Some ( number_max) , .. } => quote ! ( Some ( #number_max) ) ,
148
+ ParsedField :: Regular { number_soft_max, number_hard_max, .. } => match ( number_soft_max, number_hard_max) {
149
+ ( Some ( soft_max) , _) => quote ! ( Some ( #soft_max) ) ,
150
+ ( None , Some ( hard_max) ) => quote ! ( Some ( #hard_max) ) ,
151
+ ( None , None ) => quote ! ( None ) ,
152
+ } ,
145
153
_ => quote ! ( None ) ,
146
154
} )
147
155
. collect ( ) ;
@@ -175,6 +183,33 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
175
183
}
176
184
} ) ;
177
185
186
+ let min_max_args = fields. iter ( ) . map ( |field| match field {
187
+ ParsedField :: Regular {
188
+ pat_ident,
189
+ number_hard_min,
190
+ number_hard_max,
191
+ ..
192
+ } => {
193
+ let name = & pat_ident. ident ;
194
+ let mut tokens = quote ! ( ) ;
195
+ if let Some ( min) = number_hard_min {
196
+ tokens. extend ( quote_spanned ! { min. span( ) =>
197
+ let #name = #graphene_core:: misc:: Clampable :: clamp_hard_min( #name, #min) ;
198
+ } ) ;
199
+ }
200
+
201
+ if let Some ( max) = number_hard_max {
202
+ tokens. extend ( quote_spanned ! { max. span( ) =>
203
+ let #name = #graphene_core:: misc:: Clampable :: clamp_hard_max( #name, #max) ;
204
+ } ) ;
205
+ }
206
+ tokens
207
+ }
208
+ ParsedField :: Node { .. } => {
209
+ quote ! ( )
210
+ }
211
+ } ) ;
212
+
178
213
let all_implementation_types = fields. iter ( ) . flat_map ( |field| match field {
179
214
ParsedField :: Regular { implementations, .. } => implementations. into_iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ,
180
215
ParsedField :: Node { implementations, .. } => implementations
@@ -186,13 +221,27 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
186
221
187
222
let input_type = & parsed. input . ty ;
188
223
let mut clauses = Vec :: new ( ) ;
224
+ let mut clampable_clauses = Vec :: new ( ) ;
225
+
189
226
for ( field, name) in fields. iter ( ) . zip ( struct_generics. iter ( ) ) {
190
227
clauses. push ( match ( field, * is_async) {
191
- ( ParsedField :: Regular { ty, .. } , _) => {
228
+ (
229
+ ParsedField :: Regular {
230
+ ty, number_hard_min, number_hard_max, ..
231
+ } ,
232
+ _,
233
+ ) => {
192
234
let all_lifetime_ty = substitute_lifetimes ( ty. clone ( ) , "all" ) ;
193
235
let id = future_idents. len ( ) ;
194
236
let fut_ident = format_ident ! ( "F{}" , id) ;
195
237
future_idents. push ( fut_ident. clone ( ) ) ;
238
+
239
+ // Add Clampable bound if this field uses hard_min or hard_max
240
+ if number_hard_min. is_some ( ) || number_hard_max. is_some ( ) {
241
+ // The bound applies to the Output type of the future, which is #ty
242
+ clampable_clauses. push ( quote ! ( #ty: #graphene_core:: misc:: Clampable ) ) ;
243
+ }
244
+
196
245
quote ! (
197
246
#fut_ident: core:: future:: Future <Output = #ty> + #graphene_core:: WasmNotSend + ' n,
198
247
for <' all> #all_lifetime_ty: #graphene_core:: WasmNotSend ,
@@ -220,6 +269,7 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
220
269
let mut struct_where_clause = where_clause. clone ( ) ;
221
270
let extra_where: Punctuated < WherePredicate , Comma > = parse_quote ! (
222
271
#( #clauses, ) *
272
+ #( #clampable_clauses, ) *
223
273
#output_type: ' n,
224
274
) ;
225
275
struct_where_clause. predicates . extend ( extra_where) ;
@@ -236,7 +286,10 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
236
286
#[ inline]
237
287
fn eval( & ' n self , __input: #input_type) -> Self :: Output {
238
288
Box :: pin( async move {
289
+ use #graphene_core:: misc:: Clampable ;
290
+
239
291
#( #eval_args) *
292
+ #( #min_max_args) *
240
293
self :: #fn_name( __input #( , #field_names) * ) #await_keyword
241
294
} )
242
295
}
0 commit comments