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)*);
}};
}