carbon_macros/
try_decode_ixs.rs

1//! # Instruction Decoding Module
2//!
3//! The `try_decode_ix` module provides the `try_decode_instructions!` macro, a
4//! flexible and powerful tool for dynamically decoding instructions into
5//! multiple potential types.
6//!
7//! ## Usage
8//!
9//! To use the `try_decode_instructions!` macro, specify the instruction to
10//! decode along with a series of variant-type pairs. The macro attempts to
11//! decode the instruction into each type sequentially, returning the first
12//! successful match. If no match is found, `None` is returned.
13
14/// Attempts to decode an instruction into a specific variant type.
15///
16/// The `try_decode_instructions!` macro takes an instruction and tries to
17/// decode it into one of the provided variant types. If decoding is successful,
18/// it returns a `DecodedInstruction` object with the decoded data wrapped in
19/// the specified variant. If none of the variant types match, it returns
20/// `None`.
21///
22/// This macro is useful for handling multiple potential instruction types
23/// dynamically, enabling streamlined processing of instructions without
24/// manually matching each type.
25///
26/// # Syntax
27///
28/// ```ignore
29/// try_decode_instructions!(instruction, VariantA => TypeA, VariantB => TypeB, ...);
30/// ```
31///
32/// - `$instruction`: The instruction to decode.
33/// - `$variant`: The enum variant to wrap the decoded instruction data.
34/// - `$ty`: The type to which the instruction data should be deserialized.
35///
36/// # Example
37///
38/// ```ignore
39///use carbon_macros::try_decode_instructions;
40///
41/// let instruction = Instruction { /* initialize with program_id, accounts, and data */ };
42///
43/// let decoded = try_decode_instructions!(
44///     instruction,
45///     MyEnum::VariantOne => TypeOne,
46///     MyEnum::VariantTwo => TypeTwo,
47/// );
48/// ```
49///
50/// # Parameters
51///
52/// - `$instruction`: The instruction being decoded, which must include
53///   `program_id`, `accounts`, and `data` fields. The `data` field should be a
54///   byte slice compatible with the deserialization process.
55/// - `$variant`: Enum variants that wrap the deserialized data. These variants
56///   should correspond to valid instruction types within the context.
57/// - `$ty`: The type for each variant, which must implement a `deserialize`
58///   method to convert the instruction data into the appropriate form.
59///
60/// # Returns
61///
62/// Returns an `Option<DecodedInstruction>` that contains the decoded
63/// instruction wrapped in the specified variant type if decoding is successful.
64/// If no variant type matches, it returns `None`.
65///
66/// # Notes
67///
68/// - Ensure that each `$ty` type implements a `deserialize` method, as this is
69///   necessary for the macro to attempt decoding. The deserialization method
70///   should handle byte slices.
71/// - The macro iterates over each variant type sequentially, returning the
72///   first successful match. If no types match, `None` is returned.
73/// - This macro is especially useful for processing complex transactions where
74///   multiple instruction types are possible, improving flexibility and
75///   reducing boilerplate code.
76#[macro_export]
77macro_rules! try_decode_instructions {
78    ($instruction:expr, $($variant:path => $ty:ty),* $(,)?) => {{
79        use carbon_core::deserialize::CarbonDeserialize;
80        $(
81            if let Some(decoded_instruction) = <$ty>::deserialize($instruction.data.as_slice()) {
82                Some(carbon_core::instruction::DecodedInstruction {
83                    program_id: $instruction.program_id,
84                    accounts: $instruction.accounts.clone(),
85                    data: $variant(decoded_instruction),
86                })
87            } else
88        )*
89        {
90            None
91        }
92    }};
93}