diff --git a/soroban-sdk-macros/src/arbitrary.rs b/soroban-sdk-macros/src/arbitrary.rs index 5369f0d7d..07044aba7 100644 --- a/soroban-sdk-macros/src/arbitrary.rs +++ b/soroban-sdk-macros/src/arbitrary.rs @@ -312,15 +312,11 @@ fn quote_arbitrary( arbitrary_type_decl: TokenStream2, arbitrary_ctor: TokenStream2, ) -> TokenStream2 { - if !cfg!(any(test, feature = "testutils")) { - return quote!(); - } quote! { // This allows us to create a scope to import std and arbitrary, while // also keeping everything from the current scope. This is better than a // module because: modules inside functions have surprisingly // inconsistent scoping rules and visibility management is harder. - #[cfg(any(test, feature = "testutils"))] const _: () = { // derive(Arbitrary) expects these two to be in scope use #path::testutils::arbitrary::std; diff --git a/soroban-sdk-macros/src/derive_client.rs b/soroban-sdk-macros/src/derive_client.rs index 74c14fab8..07a0504e1 100644 --- a/soroban-sdk-macros/src/derive_client.rs +++ b/soroban-sdk-macros/src/derive_client.rs @@ -9,119 +9,124 @@ pub fn derive_client_type(crate_path: &Path, ty: &str, name: &str) -> TokenStrea // Render the Client. let client_doc = format!("{name} is a client for calling the contract defined in {ty_str}."); let client_ident = format_ident!("{}", name); - quote! { - #[doc = #client_doc] - pub struct #client_ident<'a> { - pub env: #crate_path::Env, - pub address: #crate_path::Address, - #[doc(hidden)] - #[cfg(not(any(test, feature = "testutils")))] - _phantom: core::marker::PhantomData<&'a ()>, - #[doc(hidden)] - #[cfg(any(test, feature = "testutils"))] - set_auths: Option<&'a [#crate_path::xdr::SorobanAuthorizationEntry]>, - #[doc(hidden)] - #[cfg(any(test, feature = "testutils"))] - mock_auths: Option<&'a [#crate_path::testutils::MockAuth<'a>]>, - #[doc(hidden)] - #[cfg(any(test, feature = "testutils"))] - mock_all_auths: bool, - #[doc(hidden)] - #[cfg(any(test, feature = "testutils"))] - allow_non_root_auth: bool, - } + if cfg!(not(feature = "testutils")) { + quote! { + #[doc = #client_doc] + pub struct #client_ident<'a> { + pub env: #crate_path::Env, + pub address: #crate_path::Address, + #[doc(hidden)] + _phantom: core::marker::PhantomData<&'a ()>, + } - impl<'a> #client_ident<'a> { - pub fn new(env: &#crate_path::Env, address: &#crate_path::Address) -> Self { - Self { - env: env.clone(), - address: address.clone(), - #[cfg(not(any(test, feature = "testutils")))] - _phantom: core::marker::PhantomData, - #[cfg(any(test, feature = "testutils"))] - set_auths: None, - #[cfg(any(test, feature = "testutils"))] - mock_auths: None, - #[cfg(any(test, feature = "testutils"))] - mock_all_auths: false, - #[cfg(any(test, feature = "testutils"))] - allow_non_root_auth: false, + impl<'a> #client_ident<'a> { + pub fn new(env: &#crate_path::Env, address: &#crate_path::Address) -> Self { + Self { + env: env.clone(), + address: address.clone(), + _phantom: core::marker::PhantomData, + } } } + } + } else { + quote! { + #[doc = #client_doc] + pub struct #client_ident<'a> { + pub env: #crate_path::Env, + pub address: #crate_path::Address, + #[doc(hidden)] + set_auths: Option<&'a [#crate_path::xdr::SorobanAuthorizationEntry]>, + #[doc(hidden)] + mock_auths: Option<&'a [#crate_path::testutils::MockAuth<'a>]>, + #[doc(hidden)] + mock_all_auths: bool, + #[doc(hidden)] + allow_non_root_auth: bool, + } - /// Set authorizations in the environment which will be consumed by - /// contracts when they invoke `Address::require_auth` or - /// `Address::require_auth_for_args` functions. - /// - /// Requires valid signatures for the authorization to be successful. - /// To mock auth without requiring valid signatures, use `mock_auths`. - /// - /// See `soroban_sdk::Env::set_auths` for more details and examples. - #[cfg(any(test, feature = "testutils"))] - pub fn set_auths(&self, auths: &'a [#crate_path::xdr::SorobanAuthorizationEntry]) -> Self { - Self { - env: self.env.clone(), - address: self.address.clone(), - set_auths: Some(auths), - mock_auths: self.mock_auths.clone(), - mock_all_auths: false, - allow_non_root_auth: false, + impl<'a> #client_ident<'a> { + pub fn new(env: &#crate_path::Env, address: &#crate_path::Address) -> Self { + Self { + env: env.clone(), + address: address.clone(), + set_auths: None, + mock_auths: None, + mock_all_auths: false, + allow_non_root_auth: false, + } } - } - /// Mock authorizations in the environment which will cause matching invokes - /// of `Address::require_auth` and `Address::require_auth_for_args` to - /// pass. - /// - /// See `soroban_sdk::Env::set_auths` for more details and examples. - #[cfg(any(test, feature = "testutils"))] - pub fn mock_auths(&self, mock_auths: &'a [#crate_path::testutils::MockAuth<'a>]) -> Self { - Self { - env: self.env.clone(), - address: self.address.clone(), - set_auths: self.set_auths.clone(), - mock_auths: Some(mock_auths), - mock_all_auths: false, - allow_non_root_auth: false, + /// Set authorizations in the environment which will be consumed by + /// contracts when they invoke `Address::require_auth` or + /// `Address::require_auth_for_args` functions. + /// + /// Requires valid signatures for the authorization to be successful. + /// To mock auth without requiring valid signatures, use `mock_auths`. + /// + /// See `soroban_sdk::Env::set_auths` for more details and examples. + pub fn set_auths(&self, auths: &'a [#crate_path::xdr::SorobanAuthorizationEntry]) -> Self { + Self { + env: self.env.clone(), + address: self.address.clone(), + set_auths: Some(auths), + mock_auths: self.mock_auths.clone(), + mock_all_auths: false, + allow_non_root_auth: false, + } } - } - /// Mock all calls to the `Address::require_auth` and - /// `Address::require_auth_for_args` functions in invoked contracts, - /// having them succeed as if authorization was provided. - /// - /// See `soroban_sdk::Env::mock_all_auths` for more details and - /// examples. - #[cfg(any(test, feature = "testutils"))] - pub fn mock_all_auths(&self) -> Self { - Self { - env: self.env.clone(), - address: self.address.clone(), - set_auths: None, - mock_auths: None, - mock_all_auths: true, - allow_non_root_auth: false, + /// Mock authorizations in the environment which will cause matching invokes + /// of `Address::require_auth` and `Address::require_auth_for_args` to + /// pass. + /// + /// See `soroban_sdk::Env::set_auths` for more details and examples. + pub fn mock_auths(&self, mock_auths: &'a [#crate_path::testutils::MockAuth<'a>]) -> Self { + Self { + env: self.env.clone(), + address: self.address.clone(), + set_auths: self.set_auths.clone(), + mock_auths: Some(mock_auths), + mock_all_auths: false, + allow_non_root_auth: false, + } } - } - /// A version of `mock_all_auths` that allows authorizations that - /// are not present in the root invocation. - /// - /// Refer to `mock_all_auths` documentation for details and - /// prefer using `mock_all_auths` unless non-root authorization is - /// required. - /// - /// See `soroban_sdk::Env::mock_all_auths_allowing_non_root_auth` - /// for more details and examples. - #[cfg(any(test, feature = "testutils"))] - pub fn mock_all_auths_allowing_non_root_auth(&self) -> Self { - Self { - env: self.env.clone(), - address: self.address.clone(), - set_auths: None, - mock_auths: None, - mock_all_auths: true, - allow_non_root_auth: true, + /// Mock all calls to the `Address::require_auth` and + /// `Address::require_auth_for_args` functions in invoked contracts, + /// having them succeed as if authorization was provided. + /// + /// See `soroban_sdk::Env::mock_all_auths` for more details and + /// examples. + pub fn mock_all_auths(&self) -> Self { + Self { + env: self.env.clone(), + address: self.address.clone(), + set_auths: None, + mock_auths: None, + mock_all_auths: true, + allow_non_root_auth: false, + } + } + + /// A version of `mock_all_auths` that allows authorizations that + /// are not present in the root invocation. + /// + /// Refer to `mock_all_auths` documentation for details and + /// prefer using `mock_all_auths` unless non-root authorization is + /// required. + /// + /// See `soroban_sdk::Env::mock_all_auths_allowing_non_root_auth` + /// for more details and examples. + pub fn mock_all_auths_allowing_non_root_auth(&self) -> Self { + Self { + env: self.env.clone(), + address: self.address.clone(), + set_auths: None, + mock_auths: None, + mock_all_auths: true, + allow_non_root_auth: true, + } } } } @@ -193,74 +198,94 @@ pub fn derive_client_impl(crate_path: &Path, name: &str, fns: &[syn_ext::Fn]) -> let fn_output = f.output(); let fn_try_output = f.try_output(crate_path); let fn_attrs = f.attrs; - quote! { - #(#fn_attrs)* - pub fn #fn_ident(&self, #(#fn_input_types),*) -> #fn_output { - use core::ops::Not; - #[cfg(any(test, feature = "testutils"))] - let old_auth_manager = self.env.in_contract().not().then(|| - self.env.host().snapshot_auth_manager().unwrap() - ); - #[cfg(any(test, feature = "testutils"))] - { - if let Some(set_auths) = self.set_auths { - self.env.set_auths(set_auths); - } - if let Some(mock_auths) = self.mock_auths { - self.env.mock_auths(mock_auths); - } - if self.mock_all_auths { - if self.allow_non_root_auth { - self.env.mock_all_auths_allowing_non_root_auth(); - } else { - self.env.mock_all_auths(); - } - } + if cfg!(not(feature = "testutils")) { + quote! { + #(#fn_attrs)* + pub fn #fn_ident(&self, #(#fn_input_types),*) -> #fn_output { + use core::ops::Not; + use #crate_path::{IntoVal,FromVal}; + let res = self.env.invoke_contract( + &self.address, + &#fn_name_symbol, + #crate_path::vec![&self.env, #(#fn_input_names.into_val(&self.env)),*], + ); + res } - use #crate_path::{IntoVal,FromVal}; - let res = self.env.invoke_contract( - &self.address, - &#fn_name_symbol, - #crate_path::vec![&self.env, #(#fn_input_names.into_val(&self.env)),*], - ); - #[cfg(any(test, feature = "testutils"))] - if let Some(old_auth_manager) = old_auth_manager { - self.env.host().set_auth_manager(old_auth_manager).unwrap(); + + #(#fn_attrs)* + pub fn #fn_try_ident(&self, #(#fn_input_types),*) -> #fn_try_output { + use #crate_path::{IntoVal,FromVal}; + let res = self.env.try_invoke_contract( + &self.address, + &#fn_name_symbol, + #crate_path::vec![&self.env, #(#fn_input_names.into_val(&self.env)),*], + ); + res } - res } - - #(#fn_attrs)* - pub fn #fn_try_ident(&self, #(#fn_input_types),*) -> #fn_try_output { - #[cfg(any(test, feature = "testutils"))] - use core::ops::Not; - #[cfg(any(test, feature = "testutils"))] - let old_auth_manager = self.env.in_contract().not().then(|| - self.env.host().snapshot_auth_manager().unwrap() - ); - #[cfg(any(test, feature = "testutils"))] - { - if let Some(set_auths) = self.set_auths { - self.env.set_auths(set_auths); - } - if let Some(mock_auths) = self.mock_auths { - self.env.mock_auths(mock_auths); + } else { + quote! { + #(#fn_attrs)* + pub fn #fn_ident(&self, #(#fn_input_types),*) -> #fn_output { + use core::ops::Not; + let old_auth_manager = self.env.in_contract().not().then(|| + self.env.host().snapshot_auth_manager().unwrap() + ); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + if self.allow_non_root_auth { + self.env.mock_all_auths_allowing_non_root_auth(); + } else { + self.env.mock_all_auths(); + } + } } - if self.mock_all_auths { - self.env.mock_all_auths(); + use #crate_path::{IntoVal,FromVal}; + let res = self.env.invoke_contract( + &self.address, + &#fn_name_symbol, + #crate_path::vec![&self.env, #(#fn_input_names.into_val(&self.env)),*], + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); } + res } - use #crate_path::{IntoVal,FromVal}; - let res = self.env.try_invoke_contract( - &self.address, - &#fn_name_symbol, - #crate_path::vec![&self.env, #(#fn_input_names.into_val(&self.env)),*], - ); - #[cfg(any(test, feature = "testutils"))] - if let Some(old_auth_manager) = old_auth_manager { - self.env.host().set_auth_manager(old_auth_manager).unwrap(); + + #(#fn_attrs)* + pub fn #fn_try_ident(&self, #(#fn_input_types),*) -> #fn_try_output { + use core::ops::Not; + let old_auth_manager = self.env.in_contract().not().then(|| + self.env.host().snapshot_auth_manager().unwrap() + ); + { + if let Some(set_auths) = self.set_auths { + self.env.set_auths(set_auths); + } + if let Some(mock_auths) = self.mock_auths { + self.env.mock_auths(mock_auths); + } + if self.mock_all_auths { + self.env.mock_all_auths(); + } + } + use #crate_path::{IntoVal,FromVal}; + let res = self.env.try_invoke_contract( + &self.address, + &#fn_name_symbol, + #crate_path::vec![&self.env, #(#fn_input_names.into_val(&self.env)),*], + ); + if let Some(old_auth_manager) = old_auth_manager { + self.env.host().set_auth_manager(old_auth_manager).unwrap(); + } + res } - res } } }) diff --git a/soroban-sdk-macros/src/derive_enum.rs b/soroban-sdk-macros/src/derive_enum.rs index 5222a43a4..5f4b8f50e 100644 --- a/soroban-sdk-macros/src/derive_enum.rs +++ b/soroban-sdk-macros/src/derive_enum.rs @@ -162,10 +162,8 @@ pub fn derive_type_enum( None }; - let arbitrary_tokens = crate::arbitrary::derive_arbitrary_enum(path, vis, enum_ident, data); - // Output. - quote! { + let mut output = quote! { #spec_gen impl #path::TryFromVal<#path::Env, #path::Val> for #enum_ident { @@ -194,81 +192,82 @@ pub fn derive_type_enum( } } } + }; - #[cfg(any(test, feature = "testutils"))] - impl #path::TryFromVal<#path::Env, #path::xdr::ScVec> for #enum_ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVec) -> Result { - use #path::xdr::Validate; - use #path::TryIntoVal; + // Additional output when testutils are enabled. + if cfg!(feature = "testutils") { + let arbitrary_tokens = crate::arbitrary::derive_arbitrary_enum(path, vis, enum_ident, data); + output.extend(quote! { + impl #path::TryFromVal<#path::Env, #path::xdr::ScVec> for #enum_ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVec) -> Result { + use #path::xdr::Validate; + use #path::TryIntoVal; - let vec = val; - let mut iter = vec.iter(); - let discriminant: #path::xdr::ScSymbol = iter.next().ok_or(#path::xdr::Error::Invalid)?.clone().try_into().map_err(|_| #path::xdr::Error::Invalid)?; - let discriminant_name: &str = &discriminant.to_utf8_string()?; + let vec = val; + let mut iter = vec.iter(); + let discriminant: #path::xdr::ScSymbol = iter.next().ok_or(#path::xdr::Error::Invalid)?.clone().try_into().map_err(|_| #path::xdr::Error::Invalid)?; + let discriminant_name: &str = &discriminant.to_utf8_string()?; - Ok(match discriminant_name { - #(#try_from_xdrs,)* - _ => Err(#path::xdr::Error::Invalid)?, - }) + Ok(match discriminant_name { + #(#try_from_xdrs,)* + _ => Err(#path::xdr::Error::Invalid)?, + }) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #enum_ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { - if let #path::xdr::ScVal::Vec(Some(vec)) = val { - <_ as #path::TryFromVal<_, _>>::try_from_val(env, vec) - } else { - Err(#path::xdr::Error::Invalid) + impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #enum_ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { + if let #path::xdr::ScVal::Vec(Some(vec)) = val { + <_ as #path::TryFromVal<_, _>>::try_from_val(env, vec) + } else { + Err(#path::xdr::Error::Invalid) + } } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<&#enum_ident> for #path::xdr::ScVec { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: &#enum_ident) -> Result { - extern crate alloc; - Ok(match val { - #(#into_xdrs,)* - }) + impl TryFrom<&#enum_ident> for #path::xdr::ScVec { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: &#enum_ident) -> Result { + extern crate alloc; + Ok(match val { + #(#into_xdrs,)* + }) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<#enum_ident> for #path::xdr::ScVec { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: #enum_ident) -> Result { - (&val).try_into() + impl TryFrom<#enum_ident> for #path::xdr::ScVec { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: #enum_ident) -> Result { + (&val).try_into() + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<&#enum_ident> for #path::xdr::ScVal { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: &#enum_ident) -> Result { - Ok(#path::xdr::ScVal::Vec(Some(val.try_into()?))) + impl TryFrom<&#enum_ident> for #path::xdr::ScVal { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: &#enum_ident) -> Result { + Ok(#path::xdr::ScVal::Vec(Some(val.try_into()?))) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<#enum_ident> for #path::xdr::ScVal { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: #enum_ident) -> Result { - (&val).try_into() + impl TryFrom<#enum_ident> for #path::xdr::ScVal { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: #enum_ident) -> Result { + (&val).try_into() + } } - } - #arbitrary_tokens + #arbitrary_tokens + }); } + output } struct VariantTokens { diff --git a/soroban-sdk-macros/src/derive_enum_int.rs b/soroban-sdk-macros/src/derive_enum_int.rs index 6eaf4ec27..6cc326c16 100644 --- a/soroban-sdk-macros/src/derive_enum_int.rs +++ b/soroban-sdk-macros/src/derive_enum_int.rs @@ -91,10 +91,8 @@ pub fn derive_type_enum_int( None }; - let arbitrary_tokens = crate::arbitrary::derive_arbitrary_enum_int(path, vis, enum_ident, data); - // Output. - quote! { + let mut output = quote! { #spec_gen const _: () = { fn assert_copy(v: #enum_ident) -> impl Copy { v } }; @@ -120,41 +118,46 @@ pub fn derive_type_enum_int( }) } } + }; - #[cfg(any(test, feature = "testutils"))] - impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #enum_ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { - if let #path::xdr::ScVal::U32(discriminant) = val { - Ok(match *discriminant { - #(#try_froms,)* - _ => Err(#path::xdr::Error::Invalid)?, - }) - } else { - Err(#path::xdr::Error::Invalid) + // Additional output when testutils are enabled. + if cfg!(feature = "testutils") { + let arbitrary_tokens = + crate::arbitrary::derive_arbitrary_enum_int(path, vis, enum_ident, data); + output.extend(quote! { + impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #enum_ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { + if let #path::xdr::ScVal::U32(discriminant) = val { + Ok(match *discriminant { + #(#try_froms,)* + _ => Err(#path::xdr::Error::Invalid)?, + }) + } else { + Err(#path::xdr::Error::Invalid) + } } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryInto<#path::xdr::ScVal> for &#enum_ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_into(self) -> Result<#path::xdr::ScVal, #path::xdr::Error> { - Ok((*self as u32).into()) + impl TryInto<#path::xdr::ScVal> for &#enum_ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_into(self) -> Result<#path::xdr::ScVal, #path::xdr::Error> { + Ok((*self as u32).into()) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryInto<#path::xdr::ScVal> for #enum_ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_into(self) -> Result<#path::xdr::ScVal, #path::xdr::Error> { - Ok((self as u32).into()) + impl TryInto<#path::xdr::ScVal> for #enum_ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_into(self) -> Result<#path::xdr::ScVal, #path::xdr::Error> { + Ok((self as u32).into()) + } } - } - #arbitrary_tokens + #arbitrary_tokens + }); } + output } diff --git a/soroban-sdk-macros/src/derive_fn.rs b/soroban-sdk-macros/src/derive_fn.rs index 8b347892f..168d8b0fc 100644 --- a/soroban-sdk-macros/src/derive_fn.rs +++ b/soroban-sdk-macros/src/derive_fn.rs @@ -181,7 +181,6 @@ pub fn derive_contract_function_registration_ctor<'a>( let ctor_ident = format_ident!("__{ty_str}_{trait_str}_{methods_hash}_ctor"); quote! { - #[cfg(any(test, feature = "testutils"))] #[doc(hidden)] #[#crate_path::reexports_for_macros::ctor::ctor] fn #ctor_ident() { diff --git a/soroban-sdk-macros/src/derive_struct.rs b/soroban-sdk-macros/src/derive_struct.rs index c50e9ed76..729a57022 100644 --- a/soroban-sdk-macros/src/derive_struct.rs +++ b/soroban-sdk-macros/src/derive_struct.rs @@ -100,10 +100,8 @@ pub fn derive_type_struct( None }; - let arbitrary_tokens = crate::arbitrary::derive_arbitrary_struct(path, vis, ident, data); - // Output. - quote! { + let mut output = quote! { #spec_gen impl #path::TryFromVal<#path::Env, #path::Val> for #ident { @@ -131,78 +129,79 @@ pub fn derive_type_struct( Ok(env.map_new_from_slices(&KEYS, &vals).map_err(|_| ConversionError)?.into()) } } + }; - #[cfg(any(test, feature = "testutils"))] - impl #path::TryFromVal<#path::Env, #path::xdr::ScMap> for #ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from_val(env: &#path::Env, val: &#path::xdr::ScMap) -> Result { - use #path::xdr::Validate; - use #path::TryIntoVal; - let map = val; - if map.len() != #field_count_usize { - return Err(#path::xdr::Error::Invalid); + // Additional output when testutils are enabled. + if cfg!(feature = "testutils") { + let arbitrary_tokens = crate::arbitrary::derive_arbitrary_struct(path, vis, ident, data); + output.extend(quote!{ + impl #path::TryFromVal<#path::Env, #path::xdr::ScMap> for #ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from_val(env: &#path::Env, val: &#path::xdr::ScMap) -> Result { + use #path::xdr::Validate; + use #path::TryIntoVal; + let map = val; + if map.len() != #field_count_usize { + return Err(#path::xdr::Error::Invalid); + } + map.validate()?; + Ok(Self{ + #(#try_from_xdrs,)* + }) } - map.validate()?; - Ok(Self{ - #(#try_from_xdrs,)* - }) } - } - #[cfg(any(test, feature = "testutils"))] - impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { - if let #path::xdr::ScVal::Map(Some(map)) = val { - <_ as #path::TryFromVal<_, _>>::try_from_val(env, map) - } else { - Err(#path::xdr::Error::Invalid) + impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { + if let #path::xdr::ScVal::Map(Some(map)) = val { + <_ as #path::TryFromVal<_, _>>::try_from_val(env, map) + } else { + Err(#path::xdr::Error::Invalid) + } } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<&#ident> for #path::xdr::ScMap { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: &#ident) -> Result { - extern crate alloc; - use #path::TryFromVal; - #path::xdr::ScMap::sorted_from(alloc::vec![ - #(#try_into_xdrs,)* - ]) + impl TryFrom<&#ident> for #path::xdr::ScMap { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: &#ident) -> Result { + extern crate alloc; + use #path::TryFromVal; + #path::xdr::ScMap::sorted_from(alloc::vec![ + #(#try_into_xdrs,)* + ]) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<#ident> for #path::xdr::ScMap { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: #ident) -> Result { - (&val).try_into() + impl TryFrom<#ident> for #path::xdr::ScMap { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: #ident) -> Result { + (&val).try_into() + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<&#ident> for #path::xdr::ScVal { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: &#ident) -> Result { - Ok(#path::xdr::ScVal::Map(Some(val.try_into()?))) + impl TryFrom<&#ident> for #path::xdr::ScVal { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: &#ident) -> Result { + Ok(#path::xdr::ScVal::Map(Some(val.try_into()?))) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<#ident> for #path::xdr::ScVal { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: #ident) -> Result { - (&val).try_into() + impl TryFrom<#ident> for #path::xdr::ScVal { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: #ident) -> Result { + (&val).try_into() + } } - } - #arbitrary_tokens + #arbitrary_tokens + }); } + output } diff --git a/soroban-sdk-macros/src/derive_struct_tuple.rs b/soroban-sdk-macros/src/derive_struct_tuple.rs index ee0e5a604..cdfcbc137 100644 --- a/soroban-sdk-macros/src/derive_struct_tuple.rs +++ b/soroban-sdk-macros/src/derive_struct_tuple.rs @@ -89,10 +89,8 @@ pub fn derive_type_struct_tuple( None }; - let arbitrary_tokens = crate::arbitrary::derive_arbitrary_struct_tuple(path, vis, ident, data); - // Output. - quote! { + let mut output = quote! { #spec_gen impl #path::TryFromVal<#path::Env, #path::Val> for #ident { @@ -120,77 +118,79 @@ pub fn derive_type_struct_tuple( Ok(env.vec_new_from_slice(&vals).map_err(|_| ConversionError)?.into()) } } + }; - #[cfg(any(test, feature = "testutils"))] - impl #path::TryFromVal<#path::Env, #path::xdr::ScVec> for #ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVec) -> Result { - use #path::xdr::Validate; - use #path::TryIntoVal; - let vec = val; - if vec.len() != #field_count_usize { - return Err(#path::xdr::Error::Invalid); + // Additional output when testutils are enabled. + if cfg!(feature = "testutils") { + let arbitrary_tokens = + crate::arbitrary::derive_arbitrary_struct_tuple(path, vis, ident, data); + output.extend(quote! { + impl #path::TryFromVal<#path::Env, #path::xdr::ScVec> for #ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVec) -> Result { + use #path::xdr::Validate; + use #path::TryIntoVal; + let vec = val; + if vec.len() != #field_count_usize { + return Err(#path::xdr::Error::Invalid); + } + Ok(Self{ + #(#try_from_xdrs,)* + }) } - Ok(Self{ - #(#try_from_xdrs,)* - }) } - } - #[cfg(any(test, feature = "testutils"))] - impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #ident { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { - if let #path::xdr::ScVal::Vec(Some(vec)) = val { - <_ as #path::TryFromVal<_, _>>::try_from_val(env, vec) - } else { - Err(#path::xdr::Error::Invalid) + impl #path::TryFromVal<#path::Env, #path::xdr::ScVal> for #ident { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from_val(env: &#path::Env, val: &#path::xdr::ScVal) -> Result { + if let #path::xdr::ScVal::Vec(Some(vec)) = val { + <_ as #path::TryFromVal<_, _>>::try_from_val(env, vec) + } else { + Err(#path::xdr::Error::Invalid) + } } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<&#ident> for #path::xdr::ScVec { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: &#ident) -> Result { - extern crate alloc; - use #path::TryFromVal; - Ok(#path::xdr::ScVec(alloc::vec![ - #(#try_into_xdrs,)* - ].try_into()?)) + impl TryFrom<&#ident> for #path::xdr::ScVec { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: &#ident) -> Result { + extern crate alloc; + use #path::TryFromVal; + Ok(#path::xdr::ScVec(alloc::vec![ + #(#try_into_xdrs,)* + ].try_into()?)) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<#ident> for #path::xdr::ScVec { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: #ident) -> Result { - (&val).try_into() + impl TryFrom<#ident> for #path::xdr::ScVec { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: #ident) -> Result { + (&val).try_into() + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<&#ident> for #path::xdr::ScVal { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: &#ident) -> Result { - Ok(#path::xdr::ScVal::Vec(Some(val.try_into()?))) + impl TryFrom<&#ident> for #path::xdr::ScVal { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: &#ident) -> Result { + Ok(#path::xdr::ScVal::Vec(Some(val.try_into()?))) + } } - } - #[cfg(any(test, feature = "testutils"))] - impl TryFrom<#ident> for #path::xdr::ScVal { - type Error = #path::xdr::Error; - #[inline(always)] - fn try_from(val: #ident) -> Result { - (&val).try_into() + impl TryFrom<#ident> for #path::xdr::ScVal { + type Error = #path::xdr::Error; + #[inline(always)] + fn try_from(val: #ident) -> Result { + (&val).try_into() + } } - } - #arbitrary_tokens + #arbitrary_tokens + }); } + output } diff --git a/soroban-sdk-macros/src/lib.rs b/soroban-sdk-macros/src/lib.rs index 863d42b73..daae39714 100644 --- a/soroban-sdk-macros/src/lib.rs +++ b/soroban-sdk-macros/src/lib.rs @@ -137,40 +137,42 @@ pub fn contract(metadata: TokenStream, input: TokenStream) -> TokenStream { let fn_set_registry_ident = format_ident!("__{ty_str}_fn_set_registry"); let crate_path = &args.crate_path; let client = derive_client_type(&args.crate_path, &ty_str, &client_ident); - quote! { + let mut output = quote! { #input2 #client + }; + if cfg!(feature = "testutils") { + output.extend(quote! { + mod #fn_set_registry_ident { + use super::*; - #[cfg(any(test, feature = "testutils"))] - mod #fn_set_registry_ident { - use super::*; + extern crate std; + use std::sync::Mutex; + use std::collections::BTreeMap; - extern crate std; - use std::sync::Mutex; - use std::collections::BTreeMap; + type F = dyn Send + Sync + Fn(#crate_path::Env, &[#crate_path::Val]) -> #crate_path::Val; - type F = dyn Send + Sync + Fn(#crate_path::Env, &[#crate_path::Val]) -> #crate_path::Val; + static FUNCS: Mutex> = Mutex::new(BTreeMap::new()); - static FUNCS: Mutex> = Mutex::new(BTreeMap::new()); + pub(crate) fn register(name: &'static str, func: &'static F) { + FUNCS.lock().unwrap().insert(name, func); + } - pub(crate) fn register(name: &'static str, func: &'static F) { - FUNCS.lock().unwrap().insert(name, func); + pub(crate) fn call(name: &str, env: #crate_path::Env, args: &[#crate_path::Val]) -> Option<#crate_path::Val> { + let fopt: Option<&'static F> = FUNCS.lock().unwrap().get(name).map(|f| f.clone()); + fopt.map(|f| f(env, args)) + } } - pub(crate) fn call(name: &str, env: #crate_path::Env, args: &[#crate_path::Val]) -> Option<#crate_path::Val> { - let fopt: Option<&'static F> = FUNCS.lock().unwrap().get(name).map(|f| f.clone()); - fopt.map(|f| f(env, args)) - } - } - - #[cfg(any(test, feature = "testutils"))] - #[doc(hidden)] - impl #crate_path::testutils::ContractFunctionSet for #ty { - fn call(&self, func: &str, env: #crate_path::Env, args: &[#crate_path::Val]) -> Option<#crate_path::Val> { - #fn_set_registry_ident::call(func, env, args) + #[doc(hidden)] + impl #crate_path::testutils::ContractFunctionSet for #ty { + fn call(&self, func: &str, env: #crate_path::Env, args: &[#crate_path::Val]) -> Option<#crate_path::Val> { + #fn_set_registry_ident::call(func, env, args) + } } - } - }.into() + }); + } + output.into() } #[derive(Debug, FromMeta)] @@ -231,20 +233,22 @@ pub fn contractimpl(metadata: TokenStream, input: TokenStream) -> TokenStream { match derived { Ok(derived_ok) => { - let cfs = derive_contract_function_registration_ctor( - crate_path, - ty, - trait_ident, - pub_methods.into_iter(), - ); - quote! { + let mut output = quote! { #[#crate_path::contractclient(crate_path = #crate_path_str, name = #client_ident, impl_only = true)] #[#crate_path::contractspecfn(name = #ty_str)] #imp #derived_ok - #cfs + }; + if cfg!(feature = "testutils") { + let cfs = derive_contract_function_registration_ctor( + crate_path, + ty, + trait_ident, + pub_methods.into_iter(), + ); + output.extend(quote! { #cfs }); } - .into() + output.into() } Err(derived_err) => quote! { #imp