@@ -62,11 +62,6 @@ struct TraitMeta {
6262 abi_convention : Option < syn:: Path > ,
6363}
6464
65- #[ derive( Debug , FromMeta ) ]
66- enum ItemFnMeta {
67- Export ,
68- }
69-
7065#[ derive( Debug , FromMeta ) ]
7166struct ImplTraitForContractMeta {
7267 /// Fully qualified path of the trait.
@@ -143,9 +138,33 @@ pub fn casper(attrs: TokenStream, item: TokenStream) -> TokenStream {
143138 generate_impl_for_contract ( entry_points)
144139 }
145140 } else if let Ok ( func) = syn:: parse :: < ItemFn > ( item. clone ( ) ) {
146- let func_meta = ItemFnMeta :: from_list ( & attr_args) . unwrap ( ) ;
147- match func_meta {
148- ItemFnMeta :: Export => generate_export_function ( & func) ,
141+ let mut is_export = false ;
142+ let mut abi_convention: Option < syn:: Path > = None ;
143+ for meta in & attr_args {
144+ match meta {
145+ ast:: NestedMeta :: Meta ( syn:: Meta :: Path ( path) ) => {
146+ if path. is_ident ( "export" ) {
147+ is_export = true ;
148+ }
149+ }
150+ ast:: NestedMeta :: Meta ( syn:: Meta :: NameValue ( nv) ) => {
151+ if nv. path . is_ident ( "abi_convention" ) {
152+ if let syn:: Expr :: Path ( expr_path) = & nv. value {
153+ abi_convention = Some ( expr_path. path . clone ( ) ) ;
154+ }
155+ }
156+ }
157+ _ => { }
158+ }
159+ }
160+ if is_export {
161+ generate_export_function ( & func, abi_convention)
162+ } else {
163+ let err = syn:: Error :: new (
164+ Span :: call_site ( ) ,
165+ "Unsupported function attribute; expected #[casper(export ...)]" ,
166+ ) ;
167+ TokenStream :: from ( err. to_compile_error ( ) )
149168 }
150169 } else {
151170 let err = syn:: Error :: new (
@@ -248,7 +267,7 @@ fn process_casper_message_for_struct(
248267 . into ( )
249268}
250269
251- fn generate_export_function ( func : & ItemFn ) -> TokenStream {
270+ fn generate_export_function ( func : & ItemFn , abi_convention : Option < syn :: Path > ) -> TokenStream {
252271 let func_name = & func. sig . ident ;
253272 let mut arg_names = Vec :: new ( ) ;
254273 let mut arg_types = Vec :: new ( ) ;
@@ -271,6 +290,42 @@ fn generate_export_function(func: &ItemFn) -> TokenStream {
271290 syn:: ReturnType :: Type ( _, ty) => quote ! { #ty } ,
272291 } ;
273292
293+ let resolve_abi_convention = match abi_convention {
294+ Some ( convention_path) => quote ! { #convention_path } ,
295+ None => quote ! { casper_contract_sdk:: serializers:: AbiConvention :: Positional } ,
296+ } ;
297+
298+ // Generate return handling tokens
299+ let handle_ret = match & func. sig . output {
300+ syn:: ReturnType :: Default => {
301+ quote ! {
302+ match resolved_abi_convention {
303+ casper_contract_sdk:: serializers:: AbiConvention :: Positional => {
304+ casper_contract_sdk:: casper:: ret( flags, None )
305+ }
306+ casper_contract_sdk:: serializers:: AbiConvention :: Named => {
307+ let ret_bytes = casper_contract_sdk:: serializers:: borsh:: to_vec( & casper_contract_sdk:: compat:: types:: CLValue :: UNIT ) . expect( "Failed to serialize return CLValue" ) ;
308+ casper_contract_sdk:: casper:: ret( flags, Some ( & ret_bytes) )
309+ }
310+ }
311+ }
312+ }
313+ syn:: ReturnType :: Type ( _, _ty) => {
314+ quote ! {
315+ let ret_bytes = match resolved_abi_convention {
316+ casper_contract_sdk:: serializers:: AbiConvention :: Positional => {
317+ casper_contract_sdk:: serializers:: borsh:: to_vec( & _ret) . expect( "Failed to serialize return value" )
318+ }
319+ casper_contract_sdk:: serializers:: AbiConvention :: Named => {
320+ let ret_clvalue = casper_contract_sdk:: compat:: types:: CLValue :: from_t( & _ret) . expect( "Failed to convert return value to CLValue" ) ;
321+ casper_contract_sdk:: serializers:: borsh:: to_vec( & ret_clvalue) . expect( "Failed to serialize return CLValue" )
322+ }
323+ } ;
324+ casper_contract_sdk:: casper:: ret( flags, Some ( & ret_bytes) )
325+ }
326+ }
327+ } ;
328+
274329 let _ctor_name = format_ident ! ( "{func_name}_ctor" ) ;
275330
276331 let exported_func_name = format_ident ! ( "__casper_export_{func_name}" ) ;
@@ -288,9 +343,38 @@ fn generate_export_function(func: &ItemFn) -> TokenStream {
288343 struct Arguments {
289344 #( #arg_names: #arg_types, ) *
290345 }
346+
347+ let mut flags = casper_contract_sdk:: common:: flags:: ReturnFlags :: empty( ) ;
291348 let input = casper_contract_sdk:: prelude:: casper:: copy_input( ) ;
292- let args: Arguments = casper_contract_sdk:: serializers:: borsh:: from_slice( & input) . unwrap( ) ;
349+ let resolved_abi_convention = #resolve_abi_convention;
350+ let args: Arguments = {
351+ match resolved_abi_convention {
352+ casper_contract_sdk:: serializers:: AbiConvention :: Positional => {
353+ casper_contract_sdk:: serializers:: borsh:: from_slice( & input) . unwrap( )
354+ }
355+ casper_contract_sdk:: serializers:: AbiConvention :: Named => {
356+ let runtime_args: casper_contract_sdk:: compat:: types:: RuntimeArgs =
357+ casper_contract_sdk:: serializers:: borsh:: from_slice( & input) . unwrap( ) ;
358+ #(
359+ let #arg_names: #arg_types = {
360+ let cl_value = runtime_args. get( stringify!( #arg_names) ) . unwrap_or_else( || panic!( concat!( "Failed to get named argument \" " , stringify!( #arg_names) , "\" " ) ) ) ;
361+ cl_value. to_t:: <#arg_types>( ) . unwrap_or_else( |error| {
362+ panic!( concat!( "Failed to convert named argument \" " , stringify!( #arg_names) , "\" : {}" ) , error)
363+ } )
364+ } ;
365+ ) *
366+ Arguments {
367+ #(
368+ #arg_names,
369+ ) *
370+ }
371+ }
372+ }
373+ } ;
374+
293375 let _ret = #func_name( #( args. #arg_names, ) * ) ;
376+
377+ #handle_ret
294378 }
295379
296380 #[ cfg( not( target_arch = "wasm32" ) ) ]
@@ -324,7 +408,7 @@ fn generate_export_function(func: &ItemFn) -> TokenStream {
324408 } ,
325409 ) *
326410 ] ,
327- abi_convention: casper_contract_sdk :: serializers :: AbiConvention :: Positional , // todo
411+ abi_convention: #resolve_abi_convention ,
328412 result_decl: {
329413 casper_contract_sdk:: abi:: collector:: AbiType {
330414 type_name: core:: any:: type_name:: <#ret>,
@@ -511,7 +595,7 @@ fn generate_impl_for_contract(mut entry_points: ItemImpl) -> TokenStream {
511595 Some ( quote ! {
512596 match #resolve_abi_convention {
513597 casper_contract_sdk:: serializers:: AbiConvention :: Positional => {
514- // Do nothing as lack of ret is synonymous with returning empty bytes (unit serializes to empty buffer )
598+ casper_contract_sdk :: casper :: ret( flags , None )
515599 }
516600 casper_contract_sdk:: serializers:: AbiConvention :: Named => {
517601 // For a named ABI convention we'd always ret with the bytes of unit CLValue.
@@ -1204,7 +1288,7 @@ fn casper_trait_definition(mut item_trait: ItemTrait, trait_meta: TraitMeta) ->
12041288 Some ( quote ! {
12051289 match #resolve_abi_convention {
12061290 casper_contract_sdk:: serializers:: AbiConvention :: Positional => {
1207- // Do nothing as lack of ret is synonymous with returning empty bytes (unit serializes to empty buffer )
1291+ casper_contract_sdk :: casper :: ret( flags , None )
12081292 }
12091293 casper_contract_sdk:: serializers:: AbiConvention :: Named => {
12101294 // For a named ABI convention we'd always ret with the bytes of unit CLValue.
0 commit comments