Skip to content

Commit

Permalink
[Address Macros]: Add an address macros crate.
Browse files Browse the repository at this point in the history
  • Loading branch information
0xOmarA committed Mar 14, 2024
1 parent 8a3047b commit ebda5a1
Show file tree
Hide file tree
Showing 7 changed files with 400 additions and 94 deletions.
14 changes: 13 additions & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ members = [
"libraries/scrypto-interface",
"libraries/ports-interface",
"libraries/scrypto-math",
"libraries/address-macros",
# Tools
"tools/publishing-tool",
# Tests
Expand Down
21 changes: 21 additions & 0 deletions libraries/address-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "address-macros"
version.workspace = true
edition.workspace = true
description = "A crate for decoding addresses at compile-time."

[dependencies]
radix-engine-common = { workspace = true }
radix-engine-interface = { workspace = true }

proc-macro2 = { version = "1.0.76" }
syn = "2.0.52"
quote = "1.0.35"
paste = "1.0.14"

[lib]
doctest = false
proc-macro = true

[lints]
workspace = true
70 changes: 70 additions & 0 deletions libraries/address-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use proc_macro::*;
use radix_engine_interface::prelude::*;

macro_rules! tri {
($expr: expr) => {
match $expr {
Ok(item) => item,
Err(err) => return err.into_compile_error().into(),
}
};
}

macro_rules! impl_address_proc_macro {
(
$type_ident: ident
) => {
paste::paste! {
#[proc_macro]
pub fn [< $type_ident: snake >](item: TokenStream) -> TokenStream {
let literal_string = tri!(syn::parse::<syn::LitStr>(item));
let node_id = tri!(decode_string_into_node_id(&literal_string));
let node_id_bytes = node_id.0;
let _ = tri!($type_ident::try_from(node_id_bytes).map_err(|err| {
syn::Error::new_spanned(&literal_string, format!("{err:?}"))
}));
quote::quote! {
::radix_engine_interface::prelude::$type_ident::new_or_panic(
[ #(#node_id_bytes),* ]
)
}
.into()
}
}
};
}

impl_address_proc_macro!(ComponentAddress);
impl_address_proc_macro!(ResourceAddress);
impl_address_proc_macro!(PackageAddress);
impl_address_proc_macro!(InternalAddress);
impl_address_proc_macro!(GlobalAddress);

#[proc_macro]
pub fn node_id(item: TokenStream) -> TokenStream {
let literal_string = tri!(syn::parse::<syn::LitStr>(item));
let node_id = tri!(decode_string_into_node_id(&literal_string));
let node_id_bytes = node_id.0;

quote::quote! {
::radix_engine_interface::prelude::NodeId([ #(#node_id_bytes),* ])
}
.into()
}

fn decode_string_into_node_id(
address: &syn::LitStr,
) -> Result<NodeId, syn::Error> {
// Attempt to decode the value without network context. Error out if we
// can't decode it.
let (_, _, node_id_bytes) =
AddressBech32Decoder::validate_and_decode_ignore_hrp(&address.value())
.map_err(|err| {
syn::Error::new_spanned(address, format!("{err:?}"))
})?;

// Try to convert this into a NodeId which can fail due to the length.
node_id_bytes.try_into().map(NodeId).map_err(|_| {
syn::Error::new_spanned(address, "Address length is invalid")
})
}
5 changes: 3 additions & 2 deletions testing/stateful-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,16 @@ caviarnine-v1-adapter-v1 = { path = "../../packages/caviarnine-v1-adapter-v1", f
"manifest-builder-stubs"
] }

address-macros = { path = "../../libraries/address-macros" }

package-loader = { path = "../../libraries/package-loader" }
gateway-client = { path = "../../libraries/gateway-client" }
publishing-tool = { path = "../../tools/publishing-tool" }

paste = { version = "1.0.14" }
extend = { version = "1.2.0" }

macro_rules_attribute = { version = "0.2.0" }
lazy_static = "1.4.0"


[lints]
workspace = true
Loading

0 comments on commit ebda5a1

Please sign in to comment.