From 67301181d8945d4a42abadef189b917ed43acf69 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 1 Feb 2025 02:17:43 +0000 Subject: [PATCH] tweak: Replace eager with preinterpret --- Cargo.lock | 11 + Cargo.toml | 1 + radix-engine/src/system/system_db_reader.rs | 2 +- radix-rust/Cargo.toml | 1 + radix-rust/src/lib.rs | 1 + sbor-derive/src/eager.rs | 345 -------------------- sbor-derive/src/lib.rs | 162 --------- sbor-tests/tests/eager.rs | 30 -- sbor/src/lib.rs | 5 +- sbor/src/versioned.rs | 90 ++--- 10 files changed, 62 insertions(+), 586 deletions(-) delete mode 100644 sbor-derive/src/eager.rs delete mode 100644 sbor-tests/tests/eager.rs diff --git a/Cargo.lock b/Cargo.lock index b8f3dcea5c8..16d39d602e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2136,6 +2136,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "preinterpret" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1727fb2b8bcde3f60a0073507de280c5da6494798be79b4ee412b487e91891b4" +dependencies = [ + "proc-macro2", + "syn 2.0.76", +] + [[package]] name = "prettyplease" version = "0.2.15" @@ -2476,6 +2486,7 @@ version = "1.4.0-dev" dependencies = [ "hashbrown 0.15.2", "indexmap 2.7.0", + "preinterpret", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index c7737a4bae8..ed331c115ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,6 +108,7 @@ ouroboros = { version = "0.17.2" } paste = { version = "1.0.13" } perfcnt = { version = "0.8.0" } plotters = { version = "0.3.4" } +preinterpret = { version = "0.2.0" } proc-macro2 = { version = "1.0.38" } quote = { version = "1.0.18" } radix-wasm-instrument = { version = "1.0.0", default-features = false, features = ["ignore_custom_section"]} diff --git a/radix-engine/src/system/system_db_reader.rs b/radix-engine/src/system/system_db_reader.rs index d588d1d0b29..e1c13330208 100644 --- a/radix-engine/src/system/system_db_reader.rs +++ b/radix-engine/src/system/system_db_reader.rs @@ -872,7 +872,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { payload: &[u8], payload_schema: &'b ResolvedPayloadSchema, depth_limit: usize, - ) -> Result<(), LocatedValidationError> { + ) -> Result<(), LocatedValidationError<'b, ScryptoCustomExtension>> { let validation_context: Box> = Box::new(ValidationPayloadCheckerContext { reader: self, diff --git a/radix-rust/Cargo.toml b/radix-rust/Cargo.toml index da1abdef42f..8cc2fb5f0c9 100644 --- a/radix-rust/Cargo.toml +++ b/radix-rust/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/radixdlt/radixdlt-scrypto" serde = { workspace = true, optional = true } hashbrown = { workspace = true, optional = true } indexmap = { workspace = true } +preinterpret = { workspace = true } [features] default = ["std"] diff --git a/radix-rust/src/lib.rs b/radix-rust/src/lib.rs index 1ef1cdb2af2..fa1e2566350 100644 --- a/radix-rust/src/lib.rs +++ b/radix-rust/src/lib.rs @@ -49,4 +49,5 @@ pub mod prelude { pub use crate::slice::*; pub use crate::assert_matches; + pub use preinterpret::preinterpret; } diff --git a/sbor-derive/src/eager.rs b/sbor-derive/src/eager.rs deleted file mode 100644 index 2422d8b451e..00000000000 --- a/sbor-derive/src/eager.rs +++ /dev/null @@ -1,345 +0,0 @@ -use core::iter; -use proc_macro2::*; -use std::{collections::HashMap, str::FromStr}; -use syn::*; - -type TokenIter = ::IntoIter; -type PeekableTokenIter = iter::Peekable; - -pub(crate) fn replace(token_stream: TokenStream) -> Result { - let mut state = EagerState::new(); - replace_recursive(&mut state, token_stream.into_iter()) -} - -struct EagerState { - variables: HashMap, -} - -impl EagerState { - fn new() -> Self { - Self { - variables: Default::default(), - } - } - - fn set_variable(&mut self, name: String, tokens: TokenStream) { - self.variables.insert(name, tokens); - } - - fn get_variable(&self, name: &str) -> Option<&TokenStream> { - self.variables.get(name) - } -} - -fn replace_recursive(state: &mut EagerState, token_iter: TokenIter) -> Result { - let mut tokens = token_iter.peekable(); - let mut expanded = TokenStream::new(); - loop { - match consume_next_meaningful_token_batch(&mut tokens)? { - MeaningfulTokenBatch::EagerCallStart(call_kind_group, eager_call_intent) => { - let call_output = - execute_eager_call(state, eager_call_intent, call_kind_group.span())?; - expanded.extend(call_output); - } - MeaningfulTokenBatch::EagerVariable { marker, name } => { - let Some(substituted) = state.get_variable(&name.to_string()) else { - let marker = marker.as_char(); - let name_str = name.to_string(); - let name_str = &name_str; - return Err(Error::new( - name.span(), - format!("The variable {marker}{name_str} wasn't set. If this wasn't intended to be a variable, work around this with [!raw! {marker}{name_str}]"), - )); - }; - expanded.extend(substituted.clone()); - } - MeaningfulTokenBatch::Group(group) => { - // If it's a group, run replace on its contents recursively. - expanded.extend(iter::once(TokenTree::Group(Group::new( - group.delimiter(), - replace_recursive(state, group.stream().into_iter())?, - )))); - } - MeaningfulTokenBatch::Leaf(token_tree) => { - expanded.extend(iter::once(token_tree)); - } - MeaningfulTokenBatch::EndOfStream => break, - } - } - return Ok(expanded); -} - -enum MeaningfulTokenBatch { - EagerCallStart(Group, EagerCallIntent), - EagerVariable { marker: Punct, name: Ident }, - Group(Group), - Leaf(TokenTree), - EndOfStream, -} - -fn consume_next_meaningful_token_batch( - tokens: &mut PeekableTokenIter, -) -> Result { - Ok(match tokens.next() { - None => MeaningfulTokenBatch::EndOfStream, - Some(TokenTree::Group(group)) => { - if let Some(eager_call_intent) = denotes_eager_call_intent(&group)? { - MeaningfulTokenBatch::EagerCallStart(group, eager_call_intent) - } else { - MeaningfulTokenBatch::Group(group) - } - } - Some(TokenTree::Punct(punct)) => { - if punct.as_char() == '#' { - if let Some(TokenTree::Ident(_)) = tokens.peek() { - let Some(TokenTree::Ident(name)) = tokens.next() else { - unreachable!(); - }; - MeaningfulTokenBatch::EagerVariable { - marker: punct, - name, - } - } else { - MeaningfulTokenBatch::Leaf(TokenTree::Punct(punct)) - } - } else { - MeaningfulTokenBatch::Leaf(TokenTree::Punct(punct)) - } - } - Some(leaf) => MeaningfulTokenBatch::Leaf(leaf), - }) -} - -enum EagerIntentKind { - Output(EagerFunctionKind), - Set(EagerFunctionKind), -} - -enum EagerFunctionKind { - Stringify, - Concat, - Ident, - Literal, - ProcessedTokens, - RawTokens, -} - -struct EagerCallIntent { - intent_kind: EagerIntentKind, - args: TokenIter, -} - -fn denotes_eager_call_intent<'g>(group: &'g Group) -> Result> { - if group.delimiter() != Delimiter::Bracket { - return Ok(None); - } - - let mut tokens = group.stream().into_iter(); - if consume_expected_punct(&mut tokens, '!').is_none() { - return Ok(None); - } - let Some(TokenTree::Ident(call_ident)) = tokens.next() else { - return Ok(None); - }; - - // We have now checked enough that we're confident the user is pretty intentionally using - // the call convention. Any issues we hit from this point will be a helpful compiler error. - let intent_kind = match call_ident.to_string().as_ref() { - "SET" => { - let Some(TokenTree::Punct(punct)) = tokens.next() else { - return Err(eager_call_intent_error(group.span())); - }; - match punct.as_char() { - '!' => EagerIntentKind::Set(EagerFunctionKind::ProcessedTokens), - ':' => { - let Some(TokenTree::Ident(func_name)) = tokens.next() else { - return Err(eager_call_intent_error(group.span())); - }; - let intent_kind = EagerIntentKind::Set(parse_supported_func_name(&func_name)?); - if consume_expected_punct(&mut tokens, '!').is_none() { - return Err(eager_call_intent_error(group.span())); - } - intent_kind - } - _ => return Err(eager_call_intent_error(group.span())), - } - } - _ => { - let intent_kind = EagerIntentKind::Output(parse_supported_func_name(&call_ident)?); - if consume_expected_punct(&mut tokens, '!').is_none() { - return Err(eager_call_intent_error(group.span())); - } - intent_kind - } - }; - - Ok(Some(EagerCallIntent { - intent_kind, - args: tokens, - })) -} - -fn eager_call_intent_error(span: Span) -> Error { - Error::new( - span, - "Expected `[!! ..]`, `[!SET! #var = ..]` or `[!SET:! #var = ..]` for one of: stringify, concat, ident, literal or raw.", - ) -} - -fn parse_supported_func_name(ident: &Ident) -> Result { - Ok(match ident.to_string().as_ref() { - "stringify" => EagerFunctionKind::Stringify, - "concat" => EagerFunctionKind::Concat, - "ident" => EagerFunctionKind::Ident, - "literal" => EagerFunctionKind::Literal, - "raw" => EagerFunctionKind::RawTokens, - func => { - return Err(Error::new( - ident.span(), - format!("Unknown function: {func}"), - )) - } - }) -} - -fn consume_expected_punct(tokens: &mut TokenIter, char: char) -> Option { - let Some(TokenTree::Punct(punct)) = tokens.next() else { - return None; - }; - if punct.as_char() != char { - return None; - } - Some(punct) -} - -fn execute_eager_call( - state: &mut EagerState, - call_intent: EagerCallIntent, - span: Span, -) -> Result { - match call_intent.intent_kind { - EagerIntentKind::Output(func) => { - execute_eager_function(state, func, span, call_intent.args) - } - EagerIntentKind::Set(func) => { - let mut tokens = call_intent.args; - const SET_ERROR_MESSAGE: &'static str = - "A set call is expected to start with `#VariableName = ..`."; - match consume_expected_punct(&mut tokens, '#') { - Some(_) => {} - _ => return Err(Error::new(span, SET_ERROR_MESSAGE)), - } - let Some(TokenTree::Ident(ident)) = tokens.next() else { - return Err(Error::new(span, SET_ERROR_MESSAGE)); - }; - match consume_expected_punct(&mut tokens, '=') { - Some(_) => {} - _ => return Err(Error::new(span, SET_ERROR_MESSAGE)), - } - - let result_tokens = execute_eager_function(state, func, span, tokens)?; - state.set_variable(ident.to_string(), result_tokens); - - return Ok(TokenStream::new()); - } - } -} - -fn execute_eager_function( - state: &mut EagerState, - function_kind: EagerFunctionKind, - span: Span, - token_iter: TokenIter, -) -> Result { - Ok(match function_kind { - EagerFunctionKind::Stringify => stringify(span, replace_recursive(state, token_iter)?)?, - EagerFunctionKind::Concat => concat(span, replace_recursive(state, token_iter)?)?, - EagerFunctionKind::Ident => concat_ident(span, replace_recursive(state, token_iter)?)?, - EagerFunctionKind::Literal => concat_literal(span, replace_recursive(state, token_iter)?)?, - EagerFunctionKind::ProcessedTokens => replace_recursive(state, token_iter)?, - EagerFunctionKind::RawTokens => token_iter.collect(), - }) -} - -fn stringify(span: Span, arguments: TokenStream) -> Result { - let output = arguments.to_string(); - Ok(str_literal_token_stream(span, &output)) -} - -fn concat(span: Span, arguments: TokenStream) -> Result { - let mut output = String::new(); - concat_recursive_internal(&mut output, arguments); - Ok(str_literal_token_stream(span, &output)) -} - -fn str_literal_token_stream(span: Span, content: &str) -> TokenStream { - let mut literal = Literal::string(content); - literal.set_span(span); - TokenTree::Literal(literal).into() -} - -fn concat_ident(span: Span, arguments: TokenStream) -> Result { - let mut output = String::new(); - concat_recursive_internal(&mut output, arguments); - // As per paste - let ident = match std::panic::catch_unwind(|| Ident::new(&output, span)) { - Ok(literal) => literal, - Err(_) => { - return Err(Error::new( - span, - &format!("`{:?}` is not a valid ident", output), - )); - } - }; - Ok(TokenTree::Ident(ident).into()) -} - -fn concat_literal(span: Span, arguments: TokenStream) -> Result { - let mut output = String::new(); - concat_recursive_internal(&mut output, arguments); - let mut literal = Literal::from_str(&output) - .map_err(|_| Error::new(span, &format!("`{:?}` is not a valid literal", output)))?; - literal.set_span(span); - Ok(TokenTree::Literal(literal).into()) -} - -fn concat_recursive_internal(output: &mut String, arguments: TokenStream) { - for token_tree in arguments { - match token_tree { - TokenTree::Literal(literal) => { - let lit: Lit = parse_quote!(#literal); - match lit { - Lit::Str(lit_str) => output.push_str(&lit_str.value()), - Lit::Char(lit_char) => output.push(lit_char.value()), - _ => { - output.push_str(&literal.to_string()); - } - } - } - TokenTree::Group(group) => match group.delimiter() { - Delimiter::Parenthesis => { - output.push('('); - concat_recursive_internal(output, group.stream()); - output.push(')'); - } - Delimiter::Brace => { - output.push('{'); - concat_recursive_internal(output, group.stream()); - output.push('}'); - } - Delimiter::Bracket => { - output.push('['); - concat_recursive_internal(output, group.stream()); - output.push(']'); - } - Delimiter::None => { - concat_recursive_internal(output, group.stream()); - } - }, - TokenTree::Punct(punct) => { - output.push(punct.as_char()); - } - TokenTree::Ident(ident) => output.push_str(&ident.to_string()), - } - } -} diff --git a/sbor-derive/src/lib.rs b/sbor-derive/src/lib.rs index 5c89517cfb7..56de0dda26d 100644 --- a/sbor-derive/src/lib.rs +++ b/sbor-derive/src/lib.rs @@ -1,6 +1,5 @@ use proc_macro::TokenStream; use std::str::FromStr; -mod eager; /// Derive code that returns the value kind. #[proc_macro_derive(Categorize, attributes(sbor))] @@ -64,167 +63,6 @@ pub fn permit_sbor_attributes(_: TokenStream) -> TokenStream { TokenStream::from_str(&"// Empty PermitSborAttributes expansion").unwrap() } -/// NOTE: This should probably be moved out of sbor to its own crate. -/// -/// This macro is a powerful but simple general-purpose tool to ease building declarative macros which create -/// new types. -/// -/// # Motivation and Examples -/// -/// Effectively it functions as a more powerful version of [paste!](https://github.com/dtolnay/paste), -/// whilst bringing the power of [quote!](https://docs.rs/quote/latest/quote/)'s variable -/// substitution to declarative macros. -/// -/// This approach neatly solves the following cases: -/// 1. Wanting `paste!` to output strings or work with [attributes other than doc](https://github.com/dtolnay/paste/issues/40#issuecomment-2062953012). -/// 2. Improves readability of long procedural macros through substitution of repeated segments. -/// 3. Avoiding defining internal `macro_rules!` to handle instances where you need to do a procedural macro repeat across two conflicting expansions . -/// 4. Alternatives to [meta-variables](https://github.com/rust-lang/rust/issues/83527) such as `$count`, `$index` before -/// they are stabilized, and alternatives to some forms of append-only recursive declarative macros. -/// -/// An example of case 1: -/// ```rust -/// # extern crate sbor_derive; -/// # use sbor_derive::*; -/// # -/// macro_rules! impl_new_type { -/// { -/// $vis:vis $my_type:ident($my_inner_type:ty) -/// } => {eager_replace!{ -/// #[sbor(as_type = [!stringify! $my_inner_type])] -/// $vis struct $my_type($my_inner_type) -/// -/// // ... -/// }} -/// } -/// ``` -/// -/// The following is an example of case 2 and case 3, which creates a much more readable macro. -/// This example is hard to do with a normal macro, because the iteration of the generics in `#ImplGenerics` and `#MyType` wouldn't be compatible with the iteration over `$trait`. -/// Instead, you have to work around it, for example with internal `macro_rules!` definitions [as per this stack overflow post](https://stackoverflow.com/a/73543948). -/// -/// Using the `!SET!` functionality, we can define these token streams earlier and output them in each loop iteration. -/// This also makes the intention of the macro writer much clearer, similar to [quote!](https://docs.rs/quote/latest/quote/) -/// in procedural macros: -/// ```rust -/// # extern crate sbor_derive; -/// # use sbor_derive::*; -/// # -/// macro_rules! impl_marker_traits { -/// { -/// $vis:vis $type_name:ident -/// // Arbitrary generics -/// $(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? $( = $deflt:tt)? ),+ >)? -/// [ -/// $($trait:ident),* -/// $(,)? // Optional trailing comma -/// ] -/// } => {eager_replace!{ -/// [!SET! #ImplGenerics = $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?] -/// [!SET! #TypeGenerics = $(< $( $lt ),+ >)?] -/// [!SET! #MyType = $type_name #TypeGenerics] -/// -/// // Output for each marker trait -/// $( -/// impl #ImplGenerics $trait for #MyType {} -/// )* -/// }} -/// } -/// ``` -/// -/// An example of case 4 - a simple count function, without needing recursive macros: -/// ```rust -/// # extern crate sbor_derive; -/// # use sbor_derive::*; -/// # -/// macro_rules! count_idents { -/// { -/// $($value: ident),* -/// } => {eager_replace!{ -/// [!SET! #index = 0] -/// $( -/// [!SET! #ignored = $value] -/// [!SET! #index = #index + 1] -/// )* -/// #index -/// }} -/// } -/// ``` -/// To quickly work this through, take `count_idents!(a, b, c)`. As a first pass, the declarative macro expands, giving: -/// ```text -/// eager_replace!{ -/// [!SET! #index = 0] -/// [!SET! ignored = a] -/// [!SET! #index = #index + 1] -/// [!SET! ignored = b] -/// [!SET! #index = #index + 1] -/// [!SET! ignored = c] -/// [!SET! #index = #index + 1] -/// #index -/// } -/// ``` -/// Which then evaluates by setting `#index` to the token stream `0 + 1 + 1 + 1`, and then outputting that sum. -/// -/// # Details -/// ## Specific functions -/// -/// * `[!concat! X Y " " Z (Hello World)]` gives `"XY Z(HelloWorld)"` by concatenating each argument without spaces, and recursing inside groups. String and char literals are first unquoted. Spaces can be added with " ". -/// * `[!ident! X Y "Z"]` gives an ident `XYZ`, using the same algorithm as `concat`. -/// * `[!literal! 31 u 32]` gives `31u32`, using the same algorithm as `concat`. -/// * `[!raw! abc #abc [!ident! test]]` outputs its contents without any nested expansion, giving `abc #abc [!ident! test]`. -/// * `[!stringify! X Y " " Z]` gives `"X Y \" \" Z"` - IMPORTANT: This uses `token_stream.into_string()` which is compiler-version dependent. Do not use if that is important. Instead, the output from `concat` should be independent of compiler version. -/// -/// Note that all functions except `raw` resolve in a nested manner as you would expected, e.g. -/// ```rust,ignore -/// [!ident! X Y [!ident! Hello World] Z] // "XYHelloWorldZ" -/// ``` -/// -/// ## Variables -/// -/// You can define variables starting with `#` which can be used outside the set call. -/// All of the following calls don't return anything, but create a variable, which can be embedded later in the macro. -/// -/// * `[!SET! #MyVar = ..]` sets `#MyVar` to the given token stream. -/// * `[!SET:concat! #MyVar = ..]` sets `#MyVar` to the result of applying the `concat` function to the token stream. -/// * `[!SET:ident! #MyVar = ..]` sets `#MyVar` to the result of applying the `ident` function to the token stream. -/// * `[!SET:literal! #MyVar = ..]` sets `#MyVar` to the result of applying the `literal` function to the token stream. -/// * `[!SET:raw! #MyVar = ..]` sets `#MyVar` to the result of applying the `raw` function to the token stream. -/// * `[!SET:stringify! #MyVar = ..]` sets `#MyVar` to the result of applying the `stringify` function to the token stream. -/// -/// # Future extensions -/// ## String case conversion -/// -/// This could in future support case conversion like [paste](https://docs.rs/paste/1.0.15/paste/index.html). -/// e.g. `[!snakecase! ..]`, `[!camelcase! ..]`, `[!uppercase! ..]`, `[!lowercase! ..]`, `[!capitalize! ..]`, `[!decapitalize! ..]`. -/// Which all use the `concat` algorithm to combine inputs, and then apply a string function. -/// -/// These can be composed to achieve things like `UPPER_SNAKE_CASE` or `lowerCamelCase`, -/// -/// # Hypothetical extensions -/// None of these are likely additions, but in theory, this system could be made turing complete to decrease the amount -/// you have to reach for writing your own procedural macros. -/// -/// ## Functions returning literals -/// * Integer functions like `[!sum! a b]`, `[!mod! a b]` which work on integer literal tokens. -/// * Boolean conditionals like `[!eq! a b]`, `[!lt! a b]`, `[!lte! a b]` operating on literals `[!contains! needle (haystack)]` -/// -/// ## Eager expansion of macros -/// When eager expansion of macros returning literals from https://github.com/rust-lang/rust/issues/90765 is stabilized, -/// things like `[!expand_literal_macros! include!("my-poem.txt")]` will be possible. -/// -/// ## Conditions and if statements -/// `[!IF! cond { .. } !ELSE! { .. }]`, for example `[!IF! [!eq! [!mod! $length 2] 0] { "even length" } !ELSE! { "odd length" }]`. -/// -/// ## Labels and gotos -/// `[!LABEL:loop!]` and `[!GOBACKTO:loop!]` would bring turing completeness - although it would need a re-architecture -/// of the token streaming logic to support jumping backwards in the stream. -#[proc_macro] -pub fn eager_replace(token_stream: TokenStream) -> TokenStream { - eager::replace(proc_macro2::TokenStream::from(token_stream)) - .unwrap_or_else(|err| err.to_compile_error()) - .into() -} - const BASIC_CUSTOM_VALUE_KIND: &str = "sbor::NoCustomValueKind"; const BASIC_CUSTOM_TYPE_KIND: &str = "sbor::NoCustomTypeKind"; const BASIC_CUSTOM_SCHEMA: &str = "sbor::NoCustomSchema"; diff --git a/sbor-tests/tests/eager.rs b/sbor-tests/tests/eager.rs deleted file mode 100644 index c80da5a4f19..00000000000 --- a/sbor-tests/tests/eager.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -use sbor::*; - -eager_replace! { - [!SET! #bytes = 32] - [!SET! #postfix = Hello World #bytes] - [!SET:raw! #MyRawVar = Test no #str [!ident! replacement]] - struct MyStruct; - type [!ident! X "Boo" [!concat! Hello 1] #postfix] = MyStruct; - const MY_NUM: u32 = [!literal! 1337u #bytes]; - const MY_CONCAT: &'static str = [!concat! #MyRawVar]; - const MY_STRINGIFY: &'static str = [!stringify! #MyRawVar]; -} - -#[test] -fn complex_example_evaluates_correctly() { - let _x: XBooHello1HelloWorld32 = MyStruct; - assert_eq!(MY_NUM, 1337u32); - assert_eq!(MY_CONCAT, "Testno#str[!ident!replacement]"); - // Note: TokenStream loses information about whether idents are attached to the proceeding punctuation... - // And actually the exact string is compiler-version dependent! - // - // Both of the following have been seen on different test runs on develop/CI: - // * `"Test no # str [! ident! replacement]"` - // * `"Test no # str [!ident! replacement]"` - // - // So instead, let's remove spaces and check it's equivalent to flatten_concat: - assert_eq!(MY_STRINGIFY.replace(" ", ""), MY_CONCAT); -} diff --git a/sbor/src/lib.rs b/sbor/src/lib.rs index c23f2ad2683..33270155bfc 100644 --- a/sbor/src/lib.rs +++ b/sbor/src/lib.rs @@ -68,8 +68,8 @@ pub use versioned::*; // Re-export derives extern crate sbor_derive; pub use sbor_derive::{ - eager_replace, BasicCategorize, BasicDecode, BasicDescribe, BasicEncode, BasicSbor, - BasicSborAssertion, Categorize, Decode, Describe, Encode, PermitSborAttributes, Sbor, + BasicCategorize, BasicDecode, BasicDescribe, BasicEncode, BasicSbor, BasicSborAssertion, + Categorize, Decode, Describe, Encode, PermitSborAttributes, Sbor, }; // extern crate self as X; in lib.rs allows ::X and X to resolve to this crate inside this crate. @@ -100,7 +100,6 @@ pub mod prelude { pub use radix_rust::prelude::*; // Exports from current crate - pub use crate::eager_replace; pub use crate::encoded_wrappers::{RawPayload as SborRawPayload, RawValue as SborRawValue}; pub use crate::enum_variant::SborFixedEnumVariant; pub use crate::path::{SborPath, SborPathBuf}; diff --git a/sbor/src/versioned.rs b/sbor/src/versioned.rs index 30ab0120d26..cf6b0f13541 100644 --- a/sbor/src/versioned.rs +++ b/sbor/src/versioned.rs @@ -350,72 +350,72 @@ macro_rules! define_versioned { ])? $(,)? ) => { - $crate::eager_replace! { - [!SET! #FullGenerics = $(< $( $lt $( : $clt $(+ $dlt )* )? $( = $deflt)? ),+ >)?] - [!SET! #ImplGenerics = $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?] - [!SET! #TypeGenerics = $(< $( $lt ),+ >)?] - [!SET! #VersionedType = $versioned_name $(< $( $lt ),+ >)?] - [!SET! #VersionedTypePath = $versioned_name $(::< $( $lt ),+ >)?] - [!SET! #VersionsType = $versions_name $(< $( $lt ),+ >)?] - [!SET! #VersionsTypePath = $versions_name $(::< $( $lt ),+ >)?] - [!SET:ident! #PermitSborAttributesAlias = $versioned_name _PermitSborAttributes] + $crate::prelude::preinterpret! { + [!set! #full_generics = $(< $( $lt $( : $clt $(+ $dlt )* )? $( = $deflt)? ),+ >)?] + [!set! #impl_generics = $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?] + [!set! #type_generics = $(< $( $lt ),+ >)?] + [!set! #versioned_type = $versioned_name $(< $( $lt ),+ >)?] + [!set! #versioned_type_path = $versioned_name $(::< $( $lt ),+ >)?] + [!set! #versions_type = $versions_name $(< $( $lt ),+ >)?] + [!set! #versions_type_path = $versions_name $(::< $( $lt ),+ >)?] + [!set! #permit_sbor_attribute_alias = [!ident! $versioned_name _PermitSborAttributes]] #[allow(dead_code)] $vis type $latest_version_alias = $latest_version_type; - use $crate::PermitSborAttributes as #PermitSborAttributesAlias; + use $crate::PermitSborAttributes as #permit_sbor_attribute_alias; - #[derive(#PermitSborAttributesAlias)] + #[derive(#permit_sbor_attribute_alias)] $(#[$attributes])* $($(#[$outer_attributes])*)? // Needs to go below $attributes so that a #[derive(Sbor)] in the attributes can see it. - #[sbor(as_type = [!stringify! #VersionsType])] + #[sbor(as_type = [!string! #versions_type])] /// If you wish to get access to match on the versions, use `.as_ref()` or `.as_mut()`. - $vis struct $versioned_name #FullGenerics + $vis struct $versioned_name #full_generics { - inner: Option<#VersionsType>, + inner: Option<#versions_type>, } - impl #ImplGenerics #VersionedType + impl #impl_generics #versioned_type { - pub fn new(inner: #VersionsType) -> Self { + pub fn new(inner: #versions_type) -> Self { Self { inner: Some(inner), } } } - impl #ImplGenerics AsRef<#VersionsType> for #VersionedType + impl #impl_generics AsRef<#versions_type> for #versioned_type { - fn as_ref(&self) -> &#VersionsType { + fn as_ref(&self) -> &#versions_type { self.inner.as_ref().unwrap() } } - impl #ImplGenerics AsMut<#VersionsType> for #VersionedType + impl #impl_generics AsMut<#versions_type> for #versioned_type { - fn as_mut(&mut self) -> &mut #VersionsType { + fn as_mut(&mut self) -> &mut #versions_type { self.inner.as_mut().unwrap() } } - impl #ImplGenerics From<#VersionsType> for #VersionedType + impl #impl_generics From<#versions_type> for #versioned_type { - fn from(value: #VersionsType) -> Self { + fn from(value: #versions_type) -> Self { Self::new(value) } } - impl #ImplGenerics From<#VersionedType> for #VersionsType + impl #impl_generics From<#versioned_type> for #versions_type { - fn from(value: #VersionedType) -> Self { + fn from(value: #versioned_type) -> Self { value.inner.unwrap() } } - impl #ImplGenerics Versioned for #VersionedType + impl #impl_generics Versioned for #versioned_type { - type Versions = #VersionsType; + type Versions = #versions_type; type LatestVersion = $latest_version_type; fn is_fully_updated(&self) -> bool { @@ -464,7 +464,7 @@ macro_rules! define_versioned { } } - [!SET:ident! #discriminators = $versioned_name _discriminators] + [!set! #discriminators = [!ident! $versioned_name _discriminators]] #[allow(non_snake_case)] mod #discriminators { // The initial version of this tool used 0-indexed/off-by-one discriminators accidentally. @@ -476,10 +476,10 @@ macro_rules! define_versioned { pub const LATEST_VERSION: u8 = $latest_version - 1; } - #[derive(#PermitSborAttributesAlias)] + #[derive(#permit_sbor_attribute_alias)] $(#[$attributes])* $($(#[$inner_attributes])*)? - $vis enum $versions_name #FullGenerics + $vis enum $versions_name #full_generics { $($( #[sbor(discriminator(#discriminators::[!ident! VERSION_ $version_num]))] @@ -490,7 +490,7 @@ macro_rules! define_versioned { } #[allow(dead_code)] - impl #ImplGenerics #VersionsType + impl #impl_generics #versions_type { /// Returns if update happened, and the updated versioned enum. fn attempt_single_update(self) -> (bool, Self) { @@ -551,36 +551,36 @@ macro_rules! define_versioned { } } - pub fn into_versioned(self) -> #VersionedType { - #VersionedTypePath::new(self) + pub fn into_versioned(self) -> #versioned_type { + #versioned_type_path::new(self) } } $($( #[allow(dead_code)] - impl #ImplGenerics From<$version_type> for #VersionsType { + impl #impl_generics From<$version_type> for #versions_type { fn from(value: $version_type) -> Self { Self::[!ident! V $version_num](value) } } #[allow(dead_code)] - impl #ImplGenerics From<$version_type> for #VersionedType { + impl #impl_generics From<$version_type> for #versioned_type { fn from(value: $version_type) -> Self { - Self::new(#VersionsTypePath::[!ident! V $version_num](value)) + Self::new(#versions_type_path::[!ident! V $version_num](value)) } } )*)? #[allow(dead_code)] - impl #ImplGenerics From<$latest_version_type> for #VersionsType { + impl #impl_generics From<$latest_version_type> for #versions_type { fn from(value: $latest_version_type) -> Self { Self::[!ident! V $latest_version](value) } } #[allow(dead_code)] - impl #ImplGenerics From<$latest_version_type> for #VersionedType { + impl #impl_generics From<$latest_version_type> for #versioned_type { fn from(value: $latest_version_type) -> Self { Self::new($versions_name::[!ident! V $latest_version](value)) } @@ -588,9 +588,9 @@ macro_rules! define_versioned { // This trait is similar to `SborEnumVariantFor`, but it's nicer to use as // it's got a better name and can be implemented without needing a specific CustomValueKind. - [!SET:ident! #VersionTrait = $versioned_name Version] + [!set! #version_trait = [!ident! $versioned_name Version]] #[allow(dead_code)] - $vis trait #VersionTrait { + $vis trait #version_trait { // Note: We need to use an explicit associated type to capture the generics. type Versioned: sbor::Versioned; @@ -610,9 +610,9 @@ macro_rules! define_versioned { } $($( - impl #ImplGenerics #VersionTrait for $version_type + impl #impl_generics #version_trait for $version_type { - type Versioned = #VersionedType; + type Versioned = #versioned_type; const DISCRIMINATOR: u8 = #discriminators::[!ident! VERSION_ $version_num]; type OwnedSborVariant = sbor::SborFixedEnumVariant::<{ #discriminators::[!ident! VERSION_ $version_num] }, (Self,)>; @@ -627,14 +627,14 @@ macro_rules! define_versioned { } fn into_versioned(self) -> Self::Versioned { - #VersionedTypePath::new(self.into()) + #versioned_type_path::new(self.into()) } } )*)? - impl #ImplGenerics #VersionTrait for $latest_version_type + impl #impl_generics #version_trait for $latest_version_type { - type Versioned = $versioned_name #TypeGenerics; + type Versioned = $versioned_name #type_generics; const DISCRIMINATOR: u8 = #discriminators::LATEST_VERSION; type OwnedSborVariant = sbor::SborFixedEnumVariant::<{ #discriminators::LATEST_VERSION }, (Self,)>; @@ -649,7 +649,7 @@ macro_rules! define_versioned { } fn into_versioned(self) -> Self::Versioned { - #VersionedTypePath::new(self.into()) + #versioned_type_path::new(self.into()) } } }