Skip to content
Merged
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
6 changes: 4 additions & 2 deletions soroban-sdk-macros/src/attribute.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use syn::{punctuated::Punctuated, Attribute, Data, Fields, FieldsNamed, FieldsUnnamed};
use syn::{
ext::IdentExt as _, punctuated::Punctuated, Attribute, Data, Fields, FieldsNamed, FieldsUnnamed,
};

/// Returns true if the attribute is a doc attribute.
pub fn is_attr_doc(attr: &Attribute) -> bool {
Expand Down Expand Up @@ -31,7 +33,7 @@ pub fn remove_attributes_from_item(data: &mut Data, attrs: &[&str]) {
!attr
.path()
.get_ident()
.is_some_and(|ident| attrs.contains(&ident.to_string().as_str()))
.is_some_and(|ident| attrs.contains(&ident.unraw().to_string().as_str()))
});
}
}
Expand Down
12 changes: 8 additions & 4 deletions soroban-sdk-macros/src/derive_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{Error, FnArg, LitStr, Path, Type, TypePath, TypeReference};

use syn::ext::IdentExt as _;

use crate::{
attribute::pass_through_attr_to_gen_code, map_type::map_type, stellar_xdr::ScSpecTypeDef,
symbol, syn_ext,
Expand Down Expand Up @@ -155,13 +157,15 @@ pub fn derive_client_impl(crate_path: &Path, name: &str, fns: &[syn_ext::Fn]) ->
// Skip generating client functions for calling contract functions
// that start with '__', because the Soroban Env won't let those
// functions be invoked directly as they're reserved for callbacks
// and hooks.
!f.ident.to_string().starts_with("__")
// and hooks. Check the Soroban-facing name so a raw-identifier
// spelling like `r#__check_auth` can't slip past this filter and then
// still export as `__check_auth`.
!f.ident.unraw().to_string().starts_with("__")
})
.map(|f| {
let fn_ident = &f.ident;
let fn_try_ident = format_ident!("try_{}", &f.ident);
let fn_name = fn_ident.to_string();
let fn_name = fn_ident.unraw().to_string();
let fn_try_ident = format_ident!("try_{}", &fn_name);
let fn_name_symbol = symbol::short_or_long(
crate_path,
quote!(&self.env),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use darling::{ast::NestedMeta, Error, FromMeta};
use proc_macro2::{Ident, TokenStream as TokenStream2};
use quote::quote;
use std::collections::HashSet;
use syn::{LitStr, Path, Type};
use syn::{ext::IdentExt as _, LitStr, Path, Type};

// See soroban-sdk/docs/contracttrait.md for documentation on how this works.

Expand Down Expand Up @@ -59,7 +59,7 @@ fn derive(args: &Args) -> Result<TokenStream2, Error> {
// overridden in the input fns.
let fns = trait_default_fns
.into_iter()
.filter(|f| !impl_fn_idents.contains(&f.ident.to_string()))
.filter(|f| !impl_fn_idents.contains(&f.ident.unraw().to_string()))
.collect::<Vec<_>>();

let mut output = quote! {};
Expand Down
6 changes: 3 additions & 3 deletions soroban-sdk-macros/src/derive_contractimpl_trait_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use heck::ToSnakeCase;
use proc_macro2::{Ident, TokenStream as TokenStream2};
use quote::ToTokens;
use quote::{format_ident, quote};
use syn::{parse2, ImplItemFn, ItemTrait, Path, TraitItem, TraitItemFn, Type};
use syn::{ext::IdentExt as _, parse2, ImplItemFn, ItemTrait, Path, TraitItem, TraitItemFn, Type};

// See soroban-sdk/docs/contracttrait.md for documentation on how this works.

Expand Down Expand Up @@ -98,7 +98,7 @@ pub fn generate_call_to_contractimpl_for_trait(
args_ident: &str,
spec_ident: &str,
) -> TokenStream2 {
let impl_fn_idents = pub_methods.iter().map(|f| f.sig.ident.to_string());
let impl_fn_idents = pub_methods.iter().map(|f| f.sig.ident.unraw().to_string());
quote! {
#trait_ident!(
#trait_ident,
Expand All @@ -112,6 +112,6 @@ pub fn generate_call_to_contractimpl_for_trait(
}

fn macro_ident(trait_ident: &Ident) -> Ident {
let lower = trait_ident.to_string().to_snake_case();
let lower = trait_ident.unraw().to_string().to_snake_case();
format_ident!("__contractimpl_for_{lower}")
}
14 changes: 10 additions & 4 deletions soroban-sdk-macros/src/derive_enum.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use itertools::MultiUnzip;
use proc_macro2::{Literal, TokenStream as TokenStream2};
use quote::{format_ident, quote, ToTokens};
use syn::{spanned::Spanned, Attribute, DataEnum, Error, Fields, Ident, Path, Visibility};
use syn::{
ext::IdentExt as _, spanned::Spanned, Attribute, DataEnum, Error, Fields, Ident, Path,
Visibility,
};

use stellar_xdr::curr as stellar_xdr;
use stellar_xdr::{
Expand Down Expand Up @@ -48,7 +51,7 @@ pub fn derive_type_enum(
// TODO: Choose discriminant type based on repr type of enum.
// TODO: Use attributes tagged on variant to control whether field is included.
let case_ident = &variant.ident;
let case_name = &case_ident.to_string();
let case_name = &case_ident.unraw().to_string();
let case_name_str_lit = Literal::string(case_name);
let case_num_lit = Literal::usize_unsuffixed(case_num);
if case_name.len() > SCSYMBOL_LIMIT as usize {
Expand Down Expand Up @@ -151,7 +154,7 @@ pub fn derive_type_enum(
let spec_entry = ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: enum_ident.to_string().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())
Expand All @@ -163,7 +166,10 @@ pub fn derive_type_enum(
let spec_gen = if let Some(ref spec_xdr) = spec_xdr {
let spec_xdr_lit = proc_macro2::Literal::byte_string(spec_xdr.as_slice());
let spec_xdr_len = spec_xdr.len();
let spec_ident = format_ident!("__SPEC_XDR_TYPE_{}", enum_ident.to_string().to_uppercase());
let spec_ident = format_ident!(
"__SPEC_XDR_TYPE_{}",
enum_ident.unraw().to_string().to_uppercase()
);
Some(quote! {
#[cfg_attr(target_family = "wasm", link_section = "contractspecv0")]
pub static #spec_ident: [u8; #spec_xdr_len] = #enum_ident::spec_xdr();
Expand Down
14 changes: 10 additions & 4 deletions soroban-sdk-macros/src/derive_enum_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use stellar_xdr::curr as stellar_xdr;
use stellar_xdr::{ScSpecUdtEnumV0, StringM};
use syn::{spanned::Spanned, Attribute, DataEnum, Error, ExprLit, Ident, Lit, Path, Visibility};
use syn::{
ext::IdentExt as _, spanned::Spanned, Attribute, DataEnum, Error, ExprLit, Ident, Lit, Path,
Visibility,
};

use stellar_xdr::{ScSpecEntry, ScSpecUdtEnumCaseV0, WriteXdr};

Expand All @@ -28,7 +31,7 @@ pub fn derive_type_enum_int(
.iter()
.map(|v| {
let ident = &v.ident;
let name = &ident.to_string();
let name = &ident.unraw().to_string();
let discriminant: u32 = if let syn::Expr::Lit(ExprLit {
lit: Lit::Int(ref lit_int),
..
Expand Down Expand Up @@ -70,7 +73,7 @@ pub fn derive_type_enum_int(
let spec_entry = ScSpecEntry::UdtEnumV0(ScSpecUdtEnumV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: enum_ident.to_string().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())
Expand All @@ -82,7 +85,10 @@ pub fn derive_type_enum_int(
let spec_gen = if let Some(ref spec_xdr) = spec_xdr {
let spec_xdr_lit = proc_macro2::Literal::byte_string(spec_xdr.as_slice());
let spec_xdr_len = spec_xdr.len();
let spec_ident = format_ident!("__SPEC_XDR_TYPE_{}", enum_ident.to_string().to_uppercase());
let spec_ident = format_ident!(
"__SPEC_XDR_TYPE_{}",
enum_ident.unraw().to_string().to_uppercase()
);
Some(quote! {
#[cfg_attr(target_family = "wasm", link_section = "contractspecv0")]
pub static #spec_ident: [u8; #spec_xdr_len] = #enum_ident::spec_xdr();
Expand Down
13 changes: 9 additions & 4 deletions soroban-sdk-macros/src/derive_error_enum_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use stellar_xdr::curr as stellar_xdr;
use stellar_xdr::{ScSpecEntry, ScSpecUdtErrorEnumCaseV0, ScSpecUdtErrorEnumV0, StringM, WriteXdr};
use syn::{spanned::Spanned, Attribute, DataEnum, Error, ExprLit, Ident, Lit, Path};
use syn::{
ext::IdentExt as _, spanned::Spanned, Attribute, DataEnum, Error, ExprLit, Ident, Lit, Path,
};

use crate::{doc::docs_from_attrs, shaking, spec_shaking_v2_enabled, DEFAULT_XDR_RW_LIMITS};

Expand All @@ -23,7 +25,7 @@ pub fn derive_type_error_enum_int(
.iter()
.map(|v| {
let ident = &v.ident;
let name = &ident.to_string();
let name = &ident.unraw().to_string();
let discriminant: u32 = if let syn::Expr::Lit(ExprLit {
lit: Lit::Int(ref lit_int),
..
Expand Down Expand Up @@ -68,7 +70,7 @@ pub fn derive_type_error_enum_int(
let spec_entry = ScSpecEntry::UdtErrorEnumV0(ScSpecUdtErrorEnumV0 {
doc: docs_from_attrs(attrs),
lib: lib.as_deref().unwrap_or_default().try_into().unwrap(),
name: enum_ident.to_string().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())
Expand All @@ -80,7 +82,10 @@ pub fn derive_type_error_enum_int(
let spec_gen = if let Some(ref spec_xdr) = spec_xdr {
let spec_xdr_lit = proc_macro2::Literal::byte_string(spec_xdr.as_slice());
let spec_xdr_len = spec_xdr.len();
let spec_ident = format_ident!("__SPEC_XDR_TYPE_{}", enum_ident.to_string().to_uppercase());
let spec_ident = format_ident!(
"__SPEC_XDR_TYPE_{}",
enum_ident.unraw().to_string().to_uppercase()
);
Some(quote! {
#[cfg_attr(target_family = "wasm", link_section = "contractspecv0")]
pub static #spec_ident: [u8; #spec_xdr_len] = #enum_ident::spec_xdr();
Expand Down
64 changes: 36 additions & 28 deletions soroban-sdk-macros/src/derive_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ use crate::{
};
use darling::{ast::NestedMeta, Error, FromMeta};
use heck::ToSnakeCase;
use itertools::Itertools as _;
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use stellar_xdr::curr::{
ScSpecEntry, ScSpecEventDataFormat, ScSpecEventParamLocationV0, ScSpecEventParamV0,
ScSpecEventV0, ScSymbol, StringM, WriteXdr,
};
use syn::{parse2, spanned::Spanned, Data, DeriveInput, Fields, LitStr, Path};
use syn::{ext::IdentExt as _, parse2, spanned::Spanned, Data, DeriveInput, Fields, LitStr, Path};

#[derive(Debug, FromMeta)]
struct ContractEventArgs {
Expand Down Expand Up @@ -88,7 +87,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt

// Check event name length
const EVENT_NAME_LENGTH: u32 = 32;
let event_name = input.ident.to_string();
let event_name = input.ident.unraw().to_string();
let event_name_len = event_name.len();
let event_name: StringM<EVENT_NAME_LENGTH> = errors
.handle(event_name.try_into().map_err(|_| {
Expand All @@ -102,7 +101,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
let prefix_topics = if let Some(prefix_topics) = &args.topics {
prefix_topics.iter().map(|t| t.value()).collect()
} else {
vec![input.ident.to_string().to_snake_case()]
vec![input.ident.unraw().to_string().to_snake_case()]
};

let fields =
Expand All @@ -127,8 +126,11 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
// Collect field types for SpecShakingMarker
let field_types: Vec<_> = fields.iter().map(|f| &f.ty).collect();

// Map each field of the struct to a spec for a param.
let params = fields
// Map each field of the struct to a spec for a param, keeping the original Ident
// alongside so it can still be used for `self.#ident` field access in the generated
// code (raw identifiers like `r#type` need to stay raw for Rust, while the spec name
// is the unraw form).
let params_with_idents = fields
.iter()
.map(|field| {
let ident = field.ident.as_ref().unwrap();
Expand All @@ -140,7 +142,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
};
let doc = docs_from_attrs(&field.attrs);
const NAME_LENGTH: u32 = 30;
let name = ident.to_string();
let name = ident.unraw().to_string();
let name_len = name.len();
let name: StringM<NAME_LENGTH> = errors
.handle(name.try_into().map_err(|_| {
Expand All @@ -153,12 +155,15 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
let type_ = errors
.handle_in(|| Ok(map_type(&field.ty, true, false)?))
.unwrap_or_default();
ScSpecEventParamV0 {
location,
doc,
name,
type_,
}
(
ident.clone(),
ScSpecEventParamV0 {
location,
doc,
name,
type_,
},
)
})
.collect::<Vec<_>>();

Expand All @@ -183,9 +188,9 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
.collect::<Vec<_>>()
.try_into()
.unwrap(),
params: params
params: params_with_idents
.iter()
.map(|p| p.clone())
.map(|(_, p)| p.clone())
.collect::<Vec<_>>()
.try_into()
.unwrap(),
Expand All @@ -195,7 +200,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
let spec_xdr_len = spec_xdr.len();
let spec_ident = format_ident!(
"__SPEC_XDR_EVENT_{}",
input.ident.to_string().to_uppercase()
input.ident.unraw().to_string().to_uppercase()
);
let spec_shaking_call = if export && spec_shaking_v2_enabled() {
Some(quote! { <Self as #path::SpecShakingMarker>::spec_shaking_marker(); })
Expand Down Expand Up @@ -239,10 +244,10 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
&LitStr::new(&t, Span::call_site()),
)
});
let topic_idents = params
let topic_idents = params_with_idents
.iter()
.filter(|p| p.location == ScSpecEventParamLocationV0::TopicList)
.map(|p| format_ident!("{}", p.name.to_string()))
.filter(|(_, p)| p.location == ScSpecEventParamLocationV0::TopicList)
.map(|(ident, _)| ident.clone())
.collect::<Vec<_>>();
let topics_to_vec_val = quote! {
use #path::IntoVal;
Expand All @@ -253,14 +258,14 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
};

// Prepare Data Conversion to Val.
let data_params = params
let data_params = params_with_idents
.iter()
.filter(|p| p.location == ScSpecEventParamLocationV0::Data)
.filter(|(_, p)| p.location == ScSpecEventParamLocationV0::Data)
.collect::<Vec<_>>();
let data_params_count = data_params.len();
let data_idents = data_params
.iter()
.map(|p| format_ident!("{}", p.name.to_string()))
.map(|(ident, _)| ident.clone())
.collect::<Vec<_>>();
let data_to_val = match args.data_format {
DataFormat::SingleValue if data_params_count == 0 => quote! {
Expand Down Expand Up @@ -288,15 +293,18 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
).into_val(env)
},
DataFormat::Map => {
// Must be sorted for map_new_from_slices
let data_idents_sorted = data_params
// Must be sorted for map_new_from_slices. Sort by the spec name (the
// Soroban-facing Symbol string), and carry the original Ident alongside so
// that `self.#ident` still uses the raw form where needed.
let mut data_params_sorted = data_params.clone();
data_params_sorted.sort_by_key(|(_, p)| p.name.to_string());
let data_idents_sorted = data_params_sorted
.iter()
.sorted_by_key(|p| p.name.to_string())
.map(|p| format_ident!("{}", p.name.to_string()))
.map(|(ident, _)| ident.clone())
.collect::<Vec<_>>();
let data_strs_sorted = data_idents_sorted
let data_strs_sorted = data_params_sorted
.iter()
.map(|i| i.to_string())
.map(|(_, p)| p.name.to_string())
.collect::<Vec<_>>();
quote! {
use #path::{EnvBase,IntoVal,unwrap::UnwrapInfallible};
Expand Down
Loading
Loading