@@ -181,8 +181,6 @@ fn init_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream>
181
181
let rust_export_fn_name = format_ident ! ( "export_{}" , fn_name) ;
182
182
let wasm_export_fn_name = format ! ( "init_{}" , contract_name) ;
183
183
let amount_ident = format_ident ! ( "amount" ) ;
184
- let exceeded_error_code_limit =
185
- format ! ( "Error code should not exceed {} (i32::MAX)." , i32 :: MAX ) ;
186
184
187
185
// Accumulate a list of required arguments, if the function contains a
188
186
// different number of arguments, than elements in this vector, then the
@@ -198,15 +196,18 @@ fn init_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream>
198
196
#[ export_name = #wasm_export_fn_name]
199
197
pub extern "C" fn #rust_export_fn_name( #amount_ident: Amount ) -> i32 {
200
198
use concordium_std:: { trap, ExternContext , InitContextExtern , ContractState } ;
201
- use concordium_std:: convert:: TryFrom ;
202
199
#setup_fn_optional_args
203
200
let ctx = ExternContext :: <InitContextExtern >:: open( ( ) ) ;
204
201
let mut state = ContractState :: open( ( ) ) ;
205
202
match #fn_name( & ctx, #( #fn_optional_args, ) * & mut state) {
206
203
Ok ( ( ) ) => 0 ,
207
204
Err ( reject) => {
208
- let code = Reject :: from( reject) . error_code;
209
- -i32 :: try_from( code) . expect( #exceeded_error_code_limit)
205
+ let code = Reject :: from( reject) . error_code. get( ) ;
206
+ if code <= i32 :: MAX as u32 {
207
+ - ( code as i32 )
208
+ } else {
209
+ trap( ) // precondition violation
210
+ }
210
211
}
211
212
}
212
213
}
@@ -216,7 +217,6 @@ fn init_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream>
216
217
#[ export_name = #wasm_export_fn_name]
217
218
pub extern "C" fn #rust_export_fn_name( amount: Amount ) -> i32 {
218
219
use concordium_std:: { trap, ExternContext , InitContextExtern , ContractState } ;
219
- use concordium_std:: convert:: TryFrom ;
220
220
#setup_fn_optional_args
221
221
let ctx = ExternContext :: <InitContextExtern >:: open( ( ) ) ;
222
222
match #fn_name( & ctx, #( #fn_optional_args) , * ) {
@@ -228,8 +228,12 @@ fn init_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream>
228
228
0
229
229
}
230
230
Err ( reject) => {
231
- let code = Reject :: from( reject) . error_code;
232
- -i32 :: try_from( code) . expect( #exceeded_error_code_limit)
231
+ let code = Reject :: from( reject) . error_code. get( ) ;
232
+ if code <= i32 :: MAX as u32 {
233
+ - ( code as i32 )
234
+ } else {
235
+ trap( ) // precondition violation
236
+ }
233
237
}
234
238
}
235
239
}
@@ -374,8 +378,6 @@ fn receive_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStre
374
378
let rust_export_fn_name = format_ident ! ( "export_{}" , fn_name) ;
375
379
let wasm_export_fn_name = format ! ( "{}.{}" , contract_name, name) ;
376
380
let amount_ident = format_ident ! ( "amount" ) ;
377
- let exceeded_error_code_limit =
378
- format ! ( "Error code should not exceed {} (i32::MAX)." , i32 :: MAX ) ;
379
381
380
382
// Accumulate a list of required arguments, if the function contains a
381
383
// different number of arguments, than elements in this vector, then the
@@ -391,7 +393,6 @@ fn receive_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStre
391
393
#[ export_name = #wasm_export_fn_name]
392
394
pub extern "C" fn #rust_export_fn_name( #amount_ident: Amount ) -> i32 {
393
395
use concordium_std:: { SeekFrom , ContractState , Logger , ReceiveContextExtern , ExternContext } ;
394
- use concordium_std:: convert:: TryFrom ;
395
396
#setup_fn_optional_args
396
397
let ctx = ExternContext :: <ReceiveContextExtern >:: open( ( ) ) ;
397
398
let mut state = ContractState :: open( ( ) ) ;
@@ -401,8 +402,12 @@ fn receive_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStre
401
402
act. tag( ) as i32
402
403
}
403
404
Err ( reject) => {
404
- let code = Reject :: from( reject) . error_code;
405
- -i32 :: try_from( code) . expect( #exceeded_error_code_limit)
405
+ let code = Reject :: from( reject) . error_code. get( ) ;
406
+ if code <= i32 :: MAX as u32 {
407
+ - ( code as i32 )
408
+ } else {
409
+ trap( ) // precondition violation
410
+ }
406
411
}
407
412
}
408
413
}
@@ -414,7 +419,6 @@ fn receive_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStre
414
419
#[ export_name = #wasm_export_fn_name]
415
420
pub extern "C" fn #rust_export_fn_name( #amount_ident: Amount ) -> i32 {
416
421
use concordium_std:: { SeekFrom , ContractState , Logger , trap} ;
417
- use concordium_std:: convert:: TryFrom ;
418
422
#setup_fn_optional_args
419
423
let ctx = ExternContext :: <ReceiveContextExtern >:: open( ( ) ) ;
420
424
let mut state_bytes = ContractState :: open( ( ) ) ;
@@ -432,8 +436,12 @@ fn receive_worker(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStre
432
436
}
433
437
}
434
438
Err ( reject) => {
435
- let code = Reject :: from( reject) . error_code;
436
- -i32 :: try_from( code) . expect( #exceeded_error_code_limit)
439
+ let code = Reject :: from( reject) . error_code. get( ) ;
440
+ if code <= i32 :: MAX as u32 {
441
+ - ( code as i32 )
442
+ } else {
443
+ trap( ) // precondition violation
444
+ }
437
445
}
438
446
}
439
447
} else {
@@ -1246,10 +1254,12 @@ const RESERVED_ERROR_CODES: i32 = i32::MIN + 100;
1246
1254
/// // TimeExpired(time: Timestamp), /* currently not supported */
1247
1255
/// ...
1248
1256
/// }
1257
+ /// ```
1249
1258
/// ```ignore
1250
1259
/// #[receive(contract = "my_contract", name = "some_receive")]
1251
1260
/// fn receive<A: HasActions>(ctx: &impl HasReceiveContext, state: &mut MyState)
1252
- /// -> Result<A, MyError> {...} ```
1261
+ /// -> Result<A, MyError> {...}
1262
+ /// ```
1253
1263
#[ proc_macro_derive( Reject , attributes( from) ) ]
1254
1264
pub fn reject_derive ( input : TokenStream ) -> TokenStream {
1255
1265
unwrap_or_report ( reject_derive_worker ( input) )
@@ -1277,14 +1287,13 @@ fn reject_derive_worker(input: TokenStream) -> syn::Result<TokenStream> {
1277
1287
}
1278
1288
} ;
1279
1289
1280
- let variant_error_conversions: Vec < _ > =
1281
- generate_variant_error_conversions ( & enum_data, & enum_ident) ;
1290
+ let variant_error_conversions = generate_variant_error_conversions ( & enum_data, & enum_ident) ?;
1282
1291
1283
1292
let gen = quote ! {
1284
1293
impl From <#enum_ident> for Reject {
1285
- #[ inline]
1294
+ #[ inline( always ) ]
1286
1295
fn from( e: #enum_ident) -> Self {
1287
- Reject { error_code: ( e as u32 + 1 ) }
1296
+ Reject { error_code: unsafe { concordium_std :: num :: NonZeroU32 :: new_unchecked ( ( e as u32 + 1 ) ) } }
1288
1297
}
1289
1298
}
1290
1299
@@ -1306,51 +1315,69 @@ fn reject_derive_worker(input: TokenStream) -> syn::Result<TokenStream> {
1306
1315
fn generate_variant_error_conversions (
1307
1316
enum_data : & DataEnum ,
1308
1317
enum_name : & syn:: Ident ,
1309
- ) -> Vec < proc_macro2:: TokenStream > {
1310
- enum_data
1318
+ ) -> syn :: Result < Vec < proc_macro2:: TokenStream > > {
1319
+ Ok ( enum_data
1311
1320
. variants
1312
1321
. iter ( )
1313
- . flat_map ( |variant| {
1322
+ . map ( |variant| {
1323
+ // in the future we might incorporate explicit discriminants,
1324
+ // but the general case of this requires evaluating constant expressions,
1325
+ // which is not easily supported at the moment.
1326
+ if let Some ( ( _, discriminant) ) = variant. discriminant . as_ref ( ) {
1327
+ return Err ( syn:: Error :: new (
1328
+ discriminant. span ( ) ,
1329
+ "Explicit discriminants are not yet supported." ,
1330
+ ) ) ;
1331
+ }
1314
1332
let variant_attributes = variant. attrs . iter ( ) ;
1315
- variant_attributes. flat_map ( move |attr| {
1316
- parse_attr_and_gen_error_conversions ( attr, enum_name, & variant. ident )
1317
- } )
1333
+ variant_attributes
1334
+ . map ( move |attr| {
1335
+ parse_attr_and_gen_error_conversions ( attr, enum_name, & variant. ident )
1336
+ } )
1337
+ . collect :: < syn:: Result < Vec < _ > > > ( )
1318
1338
} )
1319
- . collect ( )
1339
+ . collect :: < syn:: Result < Vec < _ > > > ( ) ?
1340
+ . into_iter ( )
1341
+ . flatten ( )
1342
+ . flatten ( )
1343
+ . collect ( ) )
1320
1344
}
1321
1345
1322
1346
/// Generate error conversion for a given enum variant.
1323
1347
fn parse_attr_and_gen_error_conversions (
1324
1348
attr : & syn:: Attribute ,
1325
1349
enum_name : & syn:: Ident ,
1326
1350
variant_name : & syn:: Ident ,
1327
- ) -> Vec < proc_macro2:: TokenStream > {
1351
+ ) -> syn :: Result < Vec < proc_macro2:: TokenStream > > {
1328
1352
let wrong_from_usage = |x : & dyn Spanned | {
1329
1353
let err = syn:: Error :: new (
1330
1354
x. span ( ) ,
1331
1355
"The `from` attribute expects a list of error types, e.g.: #[from(ParseError)]." ,
1332
1356
) ;
1333
- vec ! [ err. to_compile_error ( ) ]
1357
+ err
1334
1358
} ;
1335
1359
match attr. parse_meta ( ) {
1336
1360
Ok ( syn:: Meta :: List ( list) ) if list. path . is_ident ( "from" ) => {
1337
1361
let mut from_error_names = vec ! [ ] ;
1338
1362
for nested in list. nested . iter ( ) {
1339
- if let syn:: NestedMeta :: Meta ( syn:: Meta :: Path ( from_error) ) = nested {
1340
- match from_error. get_ident ( ) {
1341
- Some ( ident) => {
1363
+ // check that all items in the list are paths
1364
+ match nested {
1365
+ syn:: NestedMeta :: Meta ( meta) => match meta {
1366
+ Meta :: Path ( from_error) => {
1367
+ let ident = from_error
1368
+ . get_ident ( )
1369
+ . ok_or_else ( || wrong_from_usage ( from_error) ) ?;
1342
1370
from_error_names. push ( ident) ;
1343
1371
}
1344
- None => {
1345
- return wrong_from_usage ( from_error) ;
1346
- }
1347
- }
1372
+ other => return Err ( wrong_from_usage ( & other) ) ,
1373
+ } ,
1374
+ syn:: NestedMeta :: Lit ( l) => return Err ( wrong_from_usage ( & l) ) ,
1348
1375
}
1349
1376
}
1350
- from_error_token_stream ( from_error_names, & enum_name, variant_name)
1377
+ Ok ( from_error_token_stream ( & from_error_names, & enum_name, variant_name) . collect ( ) )
1351
1378
}
1352
- Ok ( syn:: Meta :: NameValue ( mnv) ) if mnv. path . is_ident ( "from" ) => wrong_from_usage ( & mnv) ,
1353
- _ => vec ! [ ] ,
1379
+ Ok ( syn:: Meta :: NameValue ( mnv) ) if mnv. path . is_ident ( "from" ) => Err ( wrong_from_usage ( & mnv) ) ,
1380
+ _ => Ok ( vec ! [ ] ) ,
1354
1381
}
1355
1382
}
1356
1383
@@ -1362,23 +1389,20 @@ fn parse_attr_and_gen_error_conversions(
1362
1389
/// }
1363
1390
/// }
1364
1391
/// ```
1365
- fn from_error_token_stream (
1366
- paths : Vec < & syn:: Ident > ,
1367
- enum_name : & syn:: Ident ,
1368
- variant_name : & syn:: Ident ,
1369
- ) -> Vec < proc_macro2:: TokenStream > {
1370
- paths
1371
- . iter ( )
1372
- . map ( |from_error| {
1373
- quote ! {
1374
- impl From <#from_error> for #enum_name {
1375
- #[ inline]
1376
- fn from( fe: #from_error) -> Self {
1377
- #enum_name:: #variant_name
1378
- }
1379
- } }
1380
- } )
1381
- . collect ( )
1392
+ fn from_error_token_stream < ' a > (
1393
+ paths : & ' a [ & ' a syn:: Ident ] ,
1394
+ enum_name : & ' a syn:: Ident ,
1395
+ variant_name : & ' a syn:: Ident ,
1396
+ ) -> impl Iterator < Item = proc_macro2:: TokenStream > + ' a {
1397
+ paths. iter ( ) . map ( move |from_error| {
1398
+ quote ! {
1399
+ impl From <#from_error> for #enum_name {
1400
+ #[ inline]
1401
+ fn from( fe: #from_error) -> Self {
1402
+ #enum_name:: #variant_name
1403
+ }
1404
+ } }
1405
+ } )
1382
1406
}
1383
1407
1384
1408
#[ proc_macro_attribute]
0 commit comments