carbon_macros/
schemas.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! # Schema Module
//!
//! The `schema` module provides macros for constructing and organizing transaction schemas
//! in a hierarchical manner. These macros are designed to simplify the creation of complex
//! transaction structures by allowing inline specification of schema elements, which represent instructions
//! within transactions.
//!
//! ## Overview
//!
//! This module includes two primary macros:
//! - **`schema!`**: The main macro for constructing a `TransactionSchema`, which is a hierarchical
//!   schema representation.
//! - **`schema_inner!`**: A helper macro, used internally by `schema!` for recursive schema node construction.
//!
//! Together, these macros enable you to define schema nodes in a flexible and intuitive manner,
//! allowing for combinations of `Any` and `Instruction` nodes with optional nested instructions.
//!
//! ## Key Macros
//!
//! ### `schema!`
//!
//! The `schema!` macro is the primary entry point for constructing a `TransactionSchema`.
//! It parses provided tokens into a `TransactionSchema` object, allowing inline definition
//! of various schema elements in a tree-like structure. This macro supports keywords like
//! `any` to create branches that can match multiple instruction types.
//!
//! #### Example
//!
//! ```rust
//! use your_crate::schema;
//!
//! let transaction_schema = schema![
//!     any,
//!     [
//!         AllInstructionTypes::JupSwap(JupiterInstructionType::SwapEvent),
//!         "jup_swap_event",
//!         []
//!     ],
//!     any,
//! ];
//! ```
//!
//! This example defines a schema with an `any` branch, an `Instruction` node with nested
//! instructions, and another `any` branch, creating a flexible transaction structure.
//! In practical terms, this means that the schema represents a transaction that has a Jupiter Swap Event
//! instruction anywhere within the transaction.
//!
//! ### `schema_inner!`
//!
//! This macro is used internally by `schema!` to build out individual `SchemaNode` elements.
//! It supports three main syntax patterns: `any`, single `Instruction` nodes, and nested `Instruction`
//! nodes. Users typically don’t need to interact with this macro directly, as it’s invoked by `schema!`
//! to handle recursive node construction.
//!
//! #### Supported Syntax Patterns
//!
//! 1. **`any`**: Adds an `Any` node, which can match any instruction type, multiple times.
//! 2. **`[$ix_type:expr, $name:expr]`**: Adds an `Instruction` node without nested instructions.
//! 3. **`[$ix_type:expr, $name:expr, [$($inner:tt)*]]`**: Adds an `Instruction` node with nested inner instructions.
//!
//! ## Notes
//!
//! - The `schema!` macro relies on `schema_inner!` for recursive parsing and node creation.
//! - When using the `schema!` macro, ensure that all instruction types and identifiers correspond
//!   to valid values expected by the `TransactionSchema` to avoid compilation errors.
//!
//! ## Crate Dependencies
//!
//! This module relies on components like `SchemaNode` and `InstructionSchemaNode` to build the schema tree.
//! Make sure these types are defined and accessible within the scope of the module’s usage.
//!

/// Constructs a `TransactionSchema` from provided tokens.
///
/// The `schema!` macro facilitates the creation of a `TransactionSchema` by parsing
/// the provided tokens and assembling the structure. This macro simplifies schema
/// construction by allowing inline specification of schema elements, including
/// instruction types and associated names.
///
/// # Syntax
///
/// The `schema!` macro uses a flexible token-based syntax, enabling you to define
/// schema nodes inline. Nodes are defined in a hierarchical manner, with keywords
/// like `any` indicating schema branches, followed by instruction types, string
/// identifiers, and additional attributes or sub-nodes as needed.
///
/// # Example
///
/// ```rust
///
/// let transaction_schema = schema![
///     any
///     [
///         AllInstructionTypes::JupSwap(JupiterInstructionType::SwapEvent),
///         "jup_swap_event",
///         []
///     ]
///     any
/// ];
///
/// ```
///
/// # Parameters
///
/// - `$tt`: The token stream passed to the macro, which may include multiple schema
///   nodes and attributes. These tokens are parsed to construct the schema tree,
///   forming a `TransactionSchema` object with a root node containing the specified
///   elements.
///
/// # Returns
///
/// This macro returns a `TransactionSchema` instance with the constructed schema
/// tree based on the tokens provided. The schema is organized with nodes added
/// to the root, allowing for complex, multi-layered transaction structures, which represent
/// real transaction instructions, in order.
///
/// # Notes
///
/// - This macro requires that the inner macro `schema_inner!` is also defined,
///   as it handles the recursive parsing and node addition to the schema.
/// - Ensure that types and keywords used within the schema correspond to valid
///   identifiers and instructions expected by `TransactionSchema`. Inconsistent
///   tokens may lead to compilation errors or incorrect schema construction.
///
#[macro_export]
macro_rules! schema {
    ($($tt:tt)*) => {{
        let mut nodes = Vec::new();
        schema_inner!(&mut nodes, $($tt)*);
        carbon_core::schema::TransactionSchema { root: nodes }
    }};
}

/// Recursively constructs schema nodes within the `schema!` macro.
///
/// The `schema_inner!` macro is utilized internally by the `schema!` macro to build
/// a `TransactionSchema` structure by parsing tokens into individual `SchemaNode`
/// elements. This macro supports multiple node types, including `Any` nodes and
/// `Instruction` nodes with optional nested instructions. Each parsed node is
/// appended to the provided vector, forming a hierarchical schema structure.
///
/// # Syntax
///
/// This macro supports three main syntax patterns:
///
/// 1. `any`: Adds an `Any` node to the schema, indicating a branch point that
///    accepts multiple instructions of any type.
/// 2. `[$ix_type:expr, $name:expr]`: Adds an `Instruction` node with the
///    specified instruction type and name, without nested instructions.
/// 3. `[$ix_type:expr, $name:expr, [$($inner:tt)*]]`: Adds an `Instruction` node
///    with the specified instruction type and name, including inner instructions
///    which are parsed recursively.
///
/// # Parameters
///
/// - `$nodes`: A mutable reference to a `Vec<SchemaNode>`. This vector accumulates
///   the constructed schema nodes, which can include both `Any` and `Instruction`
///   node variants with nested instructions.
/// - `$ix_type`: The instruction type for the node, provided as an expression.
///   This identifies the specific instruction type in the schema.
/// - `$name`: A string literal representing the name of the instruction.
///   This name is associated with the `Instruction` node for identification.
///
/// # Returns
///
/// This macro modifies the `Vec<SchemaNode>` passed as `$nodes`, adding each
/// parsed `SchemaNode` to the vector. Nodes can be nested, with the structure
/// reflecting any provided inner instructions.
///
/// # Notes
///
/// - This macro is intended for internal use within the `schema!` macro and is
///   not typically called directly by users.
/// - Ensure that each `$ix_type` corresponds to a valid instruction type
///   and that `$name` is a string literal for compatibility with `InstructionSchemaNode`.
/// - The recursive structure allows for complex, multi-level instruction schemas
///   suitable for detailed transaction validation and processing.
///
#[macro_export]
macro_rules! schema_inner {
    ($nodes:expr, ) => {};

    ($nodes:expr, any $($rest:tt)*) => {
        $nodes.push(carbon_core::schema::SchemaNode::Any);
        schema_inner!($nodes, $($rest)*);
    };

    ($nodes:expr, [$ix_type:expr, $name:expr] $($rest:tt)*) => {
        $nodes.push(carbon_core::schema::SchemaNode::Instruction(carbon_core::schema::InstructionSchemaNode {
            ix_type: $ix_type,
            name: $name.to_string(),
            inner_instructions: Vec::new(),
        }));
        schema_inner!($nodes, $($rest)*);
    };

    ($nodes:expr, [$ix_type:expr, $name:expr, [$($inner:tt)*]] $($rest:tt)*) => {{
        let mut inner_nodes = Vec::new();
        schema_inner!(&mut inner_nodes, $($inner)*);
        $nodes.push(carbon_core::schema::SchemaNode::Instruction(carbon_core::schema::InstructionSchemaNode {
            ix_type: $ix_type,
            name: $name.to_string(),
            inner_instructions: inner_nodes,
            }));
        schema_inner!($nodes, $($rest)*);
    }};
}