Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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