Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ version = "=27.0.0"
#rev = "a749b69b3471aec0c20ec431b0297f3414d66421"
default-features = false

#[patch.crates-io]
[patch.crates-io]
# Pending https://github.com/stellar/rs-stellar-xdr/pull/562, which adds the
# borrowing `*Ref` types and their const XDR serializers that the contract spec
# generation in soroban-sdk-macros builds on.
stellar-xdr = { git = "https://github.com/stellar/rs-stellar-xdr", rev = "0c7bcaa9145d40de52d6592a1df785c2a4d0f1dc" }
#soroban-env-common = { path = "../rs-soroban-env/soroban-env-common" }
#soroban-env-guest = { path = "../rs-soroban-env/soroban-env-guest" }
#soroban-env-host = { path = "../rs-soroban-env/soroban-env-host" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,12 @@ fn derive(args: &Args) -> Result<TokenStream2, Error> {
Some(trait_ident),
&args.client_name,
));
output.extend(derive_fns_spec(&args.spec_name, &fns, spec_export));
output.extend(derive_fns_spec(
&args.crate_path,
&args.spec_name,
&fns,
spec_export,
));
output.extend(derive_client_impl(
&args.crate_path,
&args.client_name,
Expand Down
17 changes: 8 additions & 9 deletions soroban-sdk-macros/src/derive_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,28 +145,27 @@ pub fn derive_type_enum(
return quote! { #(#compile_errors)* };
}

// Compute spec XDR once if spec is enabled.
let spec_xdr = if spec {
let spec_entry = ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 {
// Build the spec entry once if spec is enabled.
let spec_entry = if spec {
Some(ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: enum_ident.unraw().to_string().try_into().unwrap(),
cases: spec_cases.try_into().unwrap(),
});
Some(spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap())
}))
} else {
None
};

// Generated code spec.
let spec_gen = spec_xdr
let spec_gen = spec_entry
.as_ref()
.map(|spec_xdr| spec::type_spec(enum_ident, spec_xdr));
.map(|spec_entry| spec::type_spec(path, enum_ident, spec_entry));

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
spec_xdr.as_ref().map(|spec_xdr| {
spec_entry.as_ref().map(|spec_entry| {
// Flatten all variant field types for shaking calls, deduplicating
// to avoid redundant calls for types that appear in multiple variants.
let all_field_types =
Expand All @@ -176,7 +175,7 @@ pub fn derive_type_enum(
shaking::generate_marker_impl(
path,
quote!(#enum_ident),
spec_xdr,
&spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap(),
all_field_types.cloned(),
None,
None,
Expand Down
17 changes: 8 additions & 9 deletions soroban-sdk-macros/src/derive_enum_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,31 @@ pub fn derive_type_enum_int(
return quote! { #(#compile_errors)* };
}

// Compute spec XDR once if spec is enabled.
let spec_xdr = if spec {
let spec_entry = ScSpecEntry::UdtEnumV0(ScSpecUdtEnumV0 {
// Build the spec entry once if spec is enabled.
let spec_entry = if spec {
Some(ScSpecEntry::UdtEnumV0(ScSpecUdtEnumV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: enum_ident.unraw().to_string().try_into().unwrap(),
cases: spec_cases.try_into().unwrap(),
});
Some(spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap())
}))
} else {
None
};

// Generated code spec.
let spec_gen = spec_xdr
let spec_gen = spec_entry
.as_ref()
.map(|spec_xdr| spec::type_spec(enum_ident, spec_xdr));
.map(|spec_entry| spec::type_spec(path, enum_ident, spec_entry));

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
spec_xdr.as_ref().map(|spec_xdr| {
spec_entry.as_ref().map(|spec_entry| {
shaking::generate_marker_impl(
path,
quote!(#enum_ident),
spec_xdr,
&spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap(),
std::iter::empty(),
None,
None,
Expand Down
17 changes: 8 additions & 9 deletions soroban-sdk-macros/src/derive_error_enum_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,32 +64,31 @@ pub fn derive_type_error_enum_int(
return quote! { #(#compile_errors)* };
}

// Compute spec XDR once if spec is enabled.
let spec_xdr = if spec {
let spec_entry = ScSpecEntry::UdtErrorEnumV0(ScSpecUdtErrorEnumV0 {
// Build the spec entry once if spec is enabled.
let spec_entry = if spec {
Some(ScSpecEntry::UdtErrorEnumV0(ScSpecUdtErrorEnumV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: enum_ident.unraw().to_string().try_into().unwrap(),
cases: spec_cases.try_into().unwrap(),
});
Some(spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap())
}))
} else {
None
};

// Generated code spec.
let spec_gen = spec_xdr
let spec_gen = spec_entry
.as_ref()
.map(|spec_xdr| spec::type_spec(enum_ident, spec_xdr));
.map(|spec_entry| spec::type_spec(path, enum_ident, spec_entry));

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
spec_xdr.as_ref().map(|spec_xdr| {
spec_entry.as_ref().map(|spec_entry| {
shaking::generate_marker_impl(
path,
quote!(#enum_ident),
spec_xdr,
&spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap(),
std::iter::empty(),
None,
None,
Expand Down
18 changes: 10 additions & 8 deletions soroban-sdk-macros/src/derive_event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
attribute::remove_attributes_from_item, default_crate_path, doc::docs_from_attrs,
export_arg_v2_deprecation, map_type::map_type, shaking, symbol, DEFAULT_XDR_RW_LIMITS,
export_arg_v2_deprecation, map_type::map_type, shaking, spec_ref, symbol,
DEFAULT_XDR_RW_LIMITS,
};
use darling::{ast::NestedMeta, Error, FromMeta};
use heck::ToSnakeCase;
Expand Down Expand Up @@ -197,9 +198,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
.try_into()
.unwrap(),
});
let spec_xdr = spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap();
let spec_xdr_lit = proc_macro2::Literal::byte_string(spec_xdr.as_slice());
let spec_xdr_len = spec_xdr.len();
let spec_ref = spec_ref::spec_entry(path, &spec_entry);
let spec_ident = format_ident!(
"__SPEC_XDR_EVENT_{}",
input.ident.unraw().to_string().to_uppercase()
Expand All @@ -213,11 +212,14 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
// Generated code spec.
let spec_gen = quote! {
#export_gen
pub static #spec_ident: [u8; #spec_xdr_len] = #ident::spec_xdr();
pub static #spec_ident: [u8; #ident::__SPEC_XDR_REF.const_xdr_len()] = #ident::spec_xdr();

impl #gen_impl #ident #gen_types #gen_where {
pub const fn spec_xdr() -> [u8; #spec_xdr_len] {
*#spec_xdr_lit
#[doc(hidden)]
pub const __SPEC_XDR_REF: #path::xdr::ScSpecEntryRef<'static> = #spec_ref;

pub const fn spec_xdr() -> [u8; #ident::__SPEC_XDR_REF.const_xdr_len()] {
#ident::__SPEC_XDR_REF.const_to_xdr()
}
}
};
Expand All @@ -228,7 +230,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
Some(shaking::generate_marker_impl(
path,
quote!(#ident),
&spec_xdr,
&spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap(),
field_types.iter().cloned(),
Some(quote!(#gen_impl)),
Some(quote!(#gen_types)),
Expand Down
29 changes: 19 additions & 10 deletions soroban-sdk-macros/src/derive_spec_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,32 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use stellar_xdr::{
ScSpecEntry, ScSpecFunctionInputV0, ScSpecFunctionV0, ScSpecTypeDef, ScSymbol, StringM,
WriteXdr, SCSYMBOL_LIMIT,
SCSYMBOL_LIMIT,
};
use syn::TypeReference;
use syn::{
ext::IdentExt as _, punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Error,
FnArg, Ident, Pat, ReturnType, Type, TypePath,
FnArg, Ident, Pat, Path, ReturnType, Type, TypePath,
};

use crate::attribute::pass_through_attr_to_gen_code;
use crate::syn_ext::{self, ty_to_safe_ident_str};
use crate::{doc::docs_from_attrs, map_type::map_type, DEFAULT_XDR_RW_LIMITS};
use crate::{doc::docs_from_attrs, map_type::map_type, spec_ref};

pub fn derive_fns_spec<'a>(
path: &Path,
ty: &Type,
fns: impl IntoIterator<Item = &'a syn_ext::Fn>,
export: bool,
) -> Result<TokenStream2, TokenStream2> {
fns.into_iter()
.map(|f| derive_fn_spec(ty, &f.ident, &f.attrs, &f.inputs, &f.output, export))
.map(|f| derive_fn_spec(path, ty, &f.ident, &f.attrs, &f.inputs, &f.output, export))
.collect()
}

#[allow(clippy::too_many_arguments)]
pub fn derive_fn_spec(
path: &Path,
ty: &Type,
ident: &Ident,
attrs: &[Attribute],
Expand Down Expand Up @@ -158,10 +160,12 @@ pub fn derive_fn_spec(
inputs: spec_args.try_into().unwrap(),
outputs: spec_result.try_into().unwrap(),
});
let spec_xdr = spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap();
let spec_xdr_lit = proc_macro2::Literal::byte_string(spec_xdr.as_slice());
let spec_xdr_len = spec_xdr.len();
let spec_ref = spec_ref::spec_entry(path, &spec_entry);
let spec_ident = format_ident!("__SPEC_XDR_FN_{}", ident.unraw().to_string().to_uppercase());
// Keeps the fn name's case, because unlike #spec_ident this const shares a
// scope with every other fn's, and fn names differing only in case must not
// collide.
let spec_ref_ident = format_ident!("__SPEC_XDR_REF_{}", ident);
let spec_fn_ident = format_ident!("spec_xdr_{}", ident);

// If errors have occurred, render them instead.
Expand Down Expand Up @@ -189,7 +193,7 @@ pub fn derive_fn_spec(
#[allow(non_upper_case_globals)]
#(#attrs)*
#[cfg_attr(target_family = "wasm", link_section = "contractspecv0")]
pub static #spec_ident: [u8; #spec_xdr_len] = super::#ty::#spec_fn_ident();
pub static #spec_ident: [u8; super::#ty::#spec_ref_ident.const_xdr_len()] = super::#ty::#spec_fn_ident();
}
})
} else {
Expand All @@ -201,10 +205,15 @@ pub fn derive_fn_spec(
#exported

impl #ty {
#[doc(hidden)]
#[allow(non_upper_case_globals)]
#(#attrs)*
pub const #spec_ref_ident: #path::xdr::ScSpecEntryRef<'static> = #spec_ref;

#[allow(non_snake_case)]
#(#attrs)*
pub const fn #spec_fn_ident() -> [u8; #spec_xdr_len] {
*#spec_xdr_lit
pub const fn #spec_fn_ident() -> [u8; #ty::#spec_ref_ident.const_xdr_len()] {
#ty::#spec_ref_ident.const_to_xdr()
}
}
})
Expand Down
17 changes: 8 additions & 9 deletions soroban-sdk-macros/src/derive_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,32 +74,31 @@ pub fn derive_type_struct(
return quote! { #(#compile_errors)* };
}

// Compute spec XDR once if spec is enabled.
let spec_xdr = if spec {
let spec_entry = ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 {
// Build the spec entry once if spec is enabled.
let spec_entry = if spec {
Some(ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: ident.unraw().to_string().try_into().unwrap(),
fields: spec_fields.try_into().unwrap(),
});
Some(spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap())
}))
} else {
None
};

// Generated code spec.
let spec_gen = spec_xdr
let spec_gen = spec_entry
.as_ref()
.map(|spec_xdr| spec::type_spec(ident, spec_xdr));
.map(|spec_entry| spec::type_spec(path, ident, spec_entry));

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
spec_xdr.as_ref().map(|spec_xdr| {
spec_entry.as_ref().map(|spec_entry| {
shaking::generate_marker_impl(
path,
quote!(#ident),
spec_xdr,
&spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap(),
field_types.iter().cloned(),
None,
None,
Expand Down
17 changes: 8 additions & 9 deletions soroban-sdk-macros/src/derive_struct_tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,31 @@ pub fn derive_type_struct_tuple(
return quote! { #(#compile_errors)* };
}

// Compute spec XDR once if spec is enabled.
let spec_xdr = if spec {
let spec_entry = ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 {
// Build the spec entry once if spec is enabled.
let spec_entry = if spec {
Some(ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: ident.unraw().to_string().try_into().unwrap(),
fields: field_specs.try_into().unwrap(),
});
Some(spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap())
}))
} else {
None
};

// Generated code spec.
let spec_gen = spec_xdr
let spec_gen = spec_entry
.as_ref()
.map(|spec_xdr| spec::type_spec(ident, spec_xdr));
.map(|spec_entry| spec::type_spec(path, ident, spec_entry));

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
spec_xdr.as_ref().map(|spec_xdr| {
spec_entry.as_ref().map(|spec_entry| {
shaking::generate_marker_impl(
path,
quote!(#ident),
spec_xdr,
&spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap(),
field_types.iter().cloned(),
None,
None,
Expand Down
2 changes: 1 addition & 1 deletion soroban-sdk-macros/src/derive_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn derive_or_err(metadata: TokenStream2, input: TokenStream2) -> Result<TokenStr

Ok(quote! {
pub struct #spec_ident;
#[#path::contractspecfn(name = #spec_name, export = #spec_export)]
#[#path::contractspecfn(crate_path = #path, name = #spec_name, export = #spec_export)]
#[#path::contractargs(name = #args_name)]
#[#path::contractclient(crate_path = #path, name = #client_name)]
#[#path::contractimpl_trait_macro(crate_path = #path)]
Expand Down
Loading
Loading