radix_sbor_derive/lib.rs
1mod manifest_categorize;
2mod manifest_decode;
3mod manifest_encode;
4mod manifest_sbor;
5mod scrypto_categorize;
6mod scrypto_decode;
7mod scrypto_describe;
8mod scrypto_encode;
9mod scrypto_event;
10mod scrypto_sbor;
11
12use proc_macro::TokenStream;
13
14/// Derives code for encoding a struct or enum with Manifest value model.
15///
16/// # Example
17///
18/// ```ignore
19/// # // Ignored because the generated code references sbor and radix-common which can't be imported
20/// # // by the doctest framework, because it doesn't know what those crates are
21/// # extern crate radix_sbor_derive;
22/// # use radix_sbor_derive::*;
23/// #
24/// #[derive(ManifestEncode)]
25/// pub struct MyStruct {
26/// pub field_1: u32,
27/// pub field_2: String,
28/// }
29/// ```
30#[proc_macro_derive(ManifestEncode, attributes(sbor))]
31pub fn manifest_encode(input: TokenStream) -> TokenStream {
32 manifest_encode::handle_manifest_encode(proc_macro2::TokenStream::from(input))
33 .unwrap_or_else(|err| err.to_compile_error())
34 .into()
35}
36
37/// Derives code for decoding a struct or enum with Manifest value model.
38///
39/// # Example
40///
41/// ```ignore
42/// # // Ignored because the generated code references sbor and radix-common which can't be imported
43/// # // by the doctest framework, because it doesn't know what those crates are
44/// # extern crate radix_sbor_derive;
45/// # use radix_sbor_derive::*;
46/// #
47/// #[derive(ManifestDecode)]
48/// pub struct MyStruct {
49/// pub field_1: u32,
50/// pub field_2: String,
51/// }
52/// ```
53#[proc_macro_derive(ManifestDecode, attributes(sbor))]
54pub fn manifest_decode(input: TokenStream) -> TokenStream {
55 manifest_decode::handle_manifest_decode(proc_macro2::TokenStream::from(input))
56 .unwrap_or_else(|err| err.to_compile_error())
57 .into()
58}
59
60/// Derives code for categorizing a struct or enum with Manifest value model.
61///
62/// # Example
63///
64/// ```ignore
65/// # // Ignored because the generated code references sbor and radix-common which can't be imported
66/// # // by the doctest framework, because it doesn't know what those crates are
67/// # extern crate radix_sbor_derive;
68/// # use radix_sbor_derive::*;
69/// #
70/// #[derive(ManifestCategorize)]
71/// pub struct MyStruct {
72/// pub field_1: u32,
73/// pub field_2: String,
74/// }
75/// ```
76#[proc_macro_derive(ManifestCategorize, attributes(sbor))]
77pub fn manifest_categorize(input: TokenStream) -> TokenStream {
78 manifest_categorize::handle_manifest_categorize(proc_macro2::TokenStream::from(input))
79 .unwrap_or_else(|err| err.to_compile_error())
80 .into()
81}
82
83/// A shortcut for [`ManifestCategorize`], [`ManifestEncode`] and [`ManifestDecode`] derives.
84#[proc_macro_derive(ManifestSbor, attributes(sbor))]
85pub fn manifest_sbor(input: TokenStream) -> TokenStream {
86 manifest_sbor::handle_manifest_sbor(proc_macro2::TokenStream::from(input))
87 .unwrap_or_else(|err| err.to_compile_error())
88 .into()
89}
90
91/// Derives code for encoding a struct or enum with Scrypto value model.
92///
93/// # Example
94///
95/// ```ignore
96/// # // Ignored because the generated code references sbor and radix-common which can't be imported
97/// # // by the doctest framework, because it doesn't know what those crates are
98/// # extern crate radix_sbor_derive;
99/// # use radix_sbor_derive::*;
100/// #
101/// #[derive(ScryptoEncode)]
102/// pub struct MyStruct {
103/// pub field_1: u32,
104/// pub field_2: String,
105/// }
106/// ```
107#[proc_macro_derive(ScryptoEncode, attributes(sbor))]
108pub fn scrypto_encode(input: TokenStream) -> TokenStream {
109 scrypto_encode::handle_scrypto_encode(proc_macro2::TokenStream::from(input))
110 .unwrap_or_else(|err| err.to_compile_error())
111 .into()
112}
113
114/// Derives code for decoding a struct or enum with Scrypto value model.
115///
116/// # Example
117///
118/// ```ignore
119/// # // Ignored because the generated code references sbor and radix-common which can't be imported
120/// # // by the doctest framework, because it doesn't know what those crates are
121/// # extern crate radix_sbor_derive;
122/// # use radix_sbor_derive::*;
123/// #
124/// #[derive(ScryptoDecode)]
125/// pub struct MyStruct {
126/// pub field_1: u32,
127/// pub field_2: String,
128/// }
129/// ```
130#[proc_macro_derive(ScryptoDecode, attributes(sbor))]
131pub fn scrypto_decode(input: TokenStream) -> TokenStream {
132 scrypto_decode::handle_scrypto_decode(proc_macro2::TokenStream::from(input))
133 .unwrap_or_else(|err| err.to_compile_error())
134 .into()
135}
136
137/// Derives code for categorizing a struct or enum with Scrypto value model.
138///
139/// # Example
140///
141/// ```ignore
142/// # // Ignored because the generated code references sbor and radix-common which can't be imported
143/// # // by the doctest framework, because it doesn't know what those crates are
144/// # extern crate radix_sbor_derive;
145/// # use radix_sbor_derive::*;
146/// #
147/// #[derive(ScryptoCategorize)]
148/// pub struct MyStruct {
149/// pub field_1: u32,
150/// pub field_2: String,
151/// }
152/// ```
153#[proc_macro_derive(ScryptoCategorize, attributes(sbor))]
154pub fn scrypto_categorize(input: TokenStream) -> TokenStream {
155 scrypto_categorize::handle_scrypto_categorize(proc_macro2::TokenStream::from(input))
156 .unwrap_or_else(|err| err.to_compile_error())
157 .into()
158}
159
160/// Derives code for describing a struct or enum with Scrypto schema.
161///
162/// # Example
163///
164/// ```ignore
165/// # // Ignored because the generated code references sbor and radix-common which can't be imported
166/// # // by the doctest framework, because it doesn't know what those crates are
167/// # extern crate radix_sbor_derive;
168/// # use radix_sbor_derive::*;
169/// #
170/// #[derive(ScryptoDescribe)]
171/// pub struct MyStruct {
172/// pub field_1: u32,
173/// pub field_2: String,
174/// }
175/// ```
176#[proc_macro_derive(ScryptoDescribe, attributes(sbor))]
177pub fn scrypto_describe(input: TokenStream) -> TokenStream {
178 scrypto_describe::handle_scrypto_describe(proc_macro2::TokenStream::from(input))
179 .unwrap_or_else(|err| err.to_compile_error())
180 .into()
181}
182
183/// A shortcut for [`ScryptoCategorize`], [`ScryptoEncode`], [`ScryptoDecode`], and [`ScryptoDescribe`] derives.
184///
185/// # Example
186///
187/// ```ignore
188/// # // Ignored because the generated code references sbor and radix-common which can't be imported
189/// # // by the doctest framework, because it doesn't know what those crates are
190/// # extern crate radix_sbor_derive;
191/// # use radix_sbor_derive::*;
192/// #
193/// #[derive(ScryptoSbor)]
194/// pub struct MyStruct {
195/// pub field_1: u32,
196/// pub field_2: String,
197/// }
198/// ```
199#[proc_macro_derive(ScryptoSbor, attributes(sbor))]
200pub fn scrypto_sbor(input: TokenStream) -> TokenStream {
201 scrypto_sbor::handle_scrypto_sbor(proc_macro2::TokenStream::from(input))
202 .unwrap_or_else(|err| err.to_compile_error())
203 .into()
204}
205
206/// A macro for outputting tests and marker traits to assert that a type has maintained its shape over time.
207///
208/// There are two types of assertion modes:
209/// * `fixed` mode is used to ensure that a type is unchanged.
210/// * `backwards_compatible` mode is used when multiple versions of the type are permissible, but
211/// newer versions of the type must be compatible with the older version where they align.
212/// This mode (A) ensures that the type's current schema is equivalent to the latest version, and
213/// (B) ensures that each of the schemas is a strict extension of the previous mode.
214///
215/// ## Initial schema generation and regeneration
216///
217/// To output a generated schema, temporarily add a `generate` parameter or a `regenerate` parameter,
218/// after the `fixed` or `backwards_compatible` parameter, and then run the created test.
219/// If using Rust Analyzer this can be run from the IDE, or it can be run via `cargo test`.
220///
221/// To protect against accidentally doing the wrong thing, `generate` can only be used for initial generation,
222/// whereas `regenerate` can only be used for replacing an existing generation.
223///
224/// If a "FILE:.." path is specified, it will (re)generate that file, else it will output to the console:
225/// * In `fixed` mode, this will (re)generate against the given schema location.
226/// * In `backwards_compatible` mode, this will (re)generate against the latest schema location (the last in the list).
227///
228/// The test will then panic to ensure it fails, and can't be left accidentally in (re)generate state.
229///
230/// ```ignore
231/// # // Ignored because the generated code references sbor and radix-common which can't be imported
232/// # // by the doctest framework, because it doesn't know what those crates are
233/// # extern crate radix_sbor_derive;
234/// # use radix_sbor_derive::*;
235/// #
236/// #[derive(ScryptoSbor, ScryptoSborAssertion)]
237/// #[sbor_assert(fixed("FILE:MyType-schema-v1.bin"), generate)]
238/// struct MyType {
239/// // ...
240/// }
241/// ```
242///
243/// ## Fixed schema verification
244///
245/// To verify the type's schema is unchanged, do:
246/// ```ignore
247/// # // Ignored because the generated code references sbor and radix-common which can't be imported
248/// # // by the doctest framework, because it doesn't know what those crates are
249/// # extern crate radix_sbor_derive;
250/// # use radix_sbor_derive::*;
251/// #
252/// #[derive(ScryptoSbor, ScryptoSborAssertion)]
253/// #[sbor_assert(fixed("FILE:MyType-schema-v1.bin"))]
254/// struct MyType {
255/// // ...
256/// }
257/// ```
258///
259/// Instead of `"FILE:X"`, you can also use `"INLINE:<hex>"`, `"CONST:<Constant>"` or `"EXPR:<Expression>"`
260/// where the expression (such as `generate_schema()`) has to generate a `SingleTypeSchema<NoCustomSchema>`.
261///
262/// ## Backwards compatibility verification
263///
264/// To allow multiple backwards-compatible versions, you can do this:
265/// ```ignore
266/// # // Ignored because the generated code references sbor and radix-common which can't be imported
267/// # // by the doctest framework, because it doesn't know what those crates are
268/// # extern crate radix_sbor_derive;
269/// # use radix_sbor_derive::*;
270/// #
271/// #[derive(ScryptoSbor, ScryptoSborAssertion)]
272/// #[sbor_assert(backwards_compatible(
273/// version1 = "FILE:MyType-schema-v1.bin",
274/// version2 = "FILE:MyType-schema-v2.bin",
275/// ))]
276/// struct MyType {
277/// // ...
278/// }
279/// ```
280///
281/// Instead of `"FILE:X.bin"`, you can also use `"FILE:X.txt"`, `"INLINE:<hex>"`, `"CONST:<Constant>"` or `"EXPR:<Expression>"`
282/// where the expression (such as `generate_schema()`) has to generate a `SingleTypeSchema<ScryptoCustomSchema>`.
283///
284/// If you wish to configure exactly which schemas are used for comparison of the current schema with
285/// the latest named schema; and each named schema with its predecessor, you can use:
286///
287/// ```ignore
288/// # // Ignored because the generated code references sbor and radix-common which can't be imported
289/// # // by the doctest framework, because it doesn't know what those crates are
290/// # extern crate radix_sbor_derive;
291/// # use radix_sbor_derive::*;
292/// #
293/// #[derive(ScryptoSbor, ScryptoSborAssertion)]
294/// #[sbor_assert(backwards_compatible("EXPR:<Expression>"))
295/// struct MyType {
296/// // ...
297/// }
298/// ```
299/// Where the expression (such as `params_builder()`) has to generate a `SingleTypeSchemaCompatibilityParameters<ScryptoCustomSchema>`.
300///
301/// ## Custom settings
302/// By default, the `fixed` mode will use `SchemaComparisonSettings::require_equality()` and
303/// the `backwards_compatible` mode will use `SchemaComparisonSettings::require_equality()` for the check
304/// of `current` aginst the latest version, and `SchemaComparisonSettings::allow_extension()` for the
305/// checks between consecutive versions.
306///
307/// You may wish to change these:
308/// * If you just wish to ignore the equality of metadata such as names, you can use the
309/// `allow_name_changes` flag.
310/// * If you wish to override all settings, you can provide a constant containing your
311/// own SchemaComparisonSettings.
312/// * If you wish to specify a builder for settings, you can provide `"EXPR:|builder| builder.<stuff>"`
313/// * If for `backwards_compatible`, you wish to provide a separate configuration for the "latest" and
314/// "named versions" checks, you can use `settings(comparison_between_versions = \"EXPR:F1\", comparison_between_current_and_latest = \"EXPR:F2\") `
315///
316///
317/// For example:
318/// ```ignore
319/// # // Ignored because the generated code references sbor and radix-common which can't be imported
320/// # // by the doctest framework, because it doesn't know what those crates are
321/// # extern crate radix_sbor_derive;
322/// # use radix_sbor_derive::*;
323/// #
324/// #[derive(ScryptoSbor, ScryptoSborAssertion)]
325/// #[sbor_assert(
326/// fixed("FILE:MyType-schema-v1.bin"),
327/// settings(allow_name_changes),
328/// )]
329/// struct MyType {
330/// // ...
331/// }
332///
333/// #[derive(ScryptoSbor, ScryptoSborAssertion)]
334/// #[sbor_assert(
335/// backwards_compatible(
336/// v1 = "FILE:MyType-schema-v1.bin",
337/// v2 = "FILE:MyType-schema-v2.bin",
338/// ),
339/// settings(
340/// // We allow name changes between versions, but require the current schema to exactly match
341/// // the latest version (v2 in this case).
342/// // This could be useful to e.g. ensure that we have a fixed schema with the latest naming available.
343/// comparison_between_versions = "EXPR: |s| s.allow_all_name_changes()",
344/// comparison_between_current_and_latest = "EXPR: |s| s",
345/// ),
346/// )]
347/// struct MyType {
348/// // ...
349/// }
350/// ```
351#[proc_macro_derive(ScryptoSborAssertion, attributes(sbor_assert))]
352pub fn scrypto_sbor_assertion(input: TokenStream) -> TokenStream {
353 sbor_derive_common::sbor_assert::handle_sbor_assert_derive(
354 proc_macro2::TokenStream::from(input),
355 "radix_common::data::scrypto::ScryptoCustomSchema",
356 )
357 .unwrap_or_else(|err| err.to_compile_error())
358 .into()
359}
360
361/// Derive code for implementing the required logic to mark a type as being an event.
362///
363/// # Example
364///
365/// ```ignore
366/// # // Ignored because the generated code references sbor and radix-common which can't be imported
367/// # // by the doctest framework, because it doesn't know what those crates are
368/// # extern crate radix_sbor_derive;
369/// # use radix_sbor_derive::*;
370/// #
371/// #[derive(ScryptoEvent)]
372/// pub struct MyStruct {
373/// pub field_1: u32,
374/// pub field_2: String,
375/// }
376/// ```
377#[proc_macro_derive(ScryptoEvent)]
378pub fn scrypto_event(input: TokenStream) -> TokenStream {
379 scrypto_event::handle_scrypto_event(proc_macro2::TokenStream::from(input))
380 .unwrap_or_else(|err| err.to_compile_error())
381 .into()
382}