spl_program_error_derive/
lib.rs

1//! Crate defining a procedural macro for building Solana program errors
2
3// Required to include `#[allow(clippy::integer_arithmetic)]`
4// below since the tokens generated by `quote!` in the implementation
5// for `MacroType::ToStr` and `MacroType::SplProgramError`
6// trigger the lint upstream through `quote_token_with_context` within the
7// `quote` crate
8//
9// Culprit is `macro_impl.rs:66`
10#![allow(clippy::arithmetic_side_effects)]
11#![deny(missing_docs)]
12#![cfg_attr(not(test), forbid(unsafe_code))]
13
14extern crate proc_macro;
15
16mod macro_impl;
17mod parser;
18
19use {
20    crate::parser::SplProgramErrorArgs,
21    macro_impl::MacroType,
22    proc_macro::TokenStream,
23    syn::{parse_macro_input, ItemEnum},
24};
25
26/// Derive macro to add `Into<solana_program_error::ProgramError>`
27/// trait
28#[proc_macro_derive(IntoProgramError)]
29pub fn into_program_error(input: TokenStream) -> TokenStream {
30    let ItemEnum { ident, .. } = parse_macro_input!(input as ItemEnum);
31    MacroType::IntoProgramError { ident }
32        .generate_tokens()
33        .into()
34}
35
36/// Derive macro to add `solana_program_error::ToStr` trait
37#[proc_macro_derive(ToStr)]
38pub fn to_str(input: TokenStream) -> TokenStream {
39    let ItemEnum {
40        ident, variants, ..
41    } = parse_macro_input!(input as ItemEnum);
42    MacroType::ToStr { ident, variants }
43        .generate_tokens()
44        .into()
45}
46
47/// Proc-macro attribute to turn your enum into a Solana Program Error
48///
49/// Adds:
50/// - `Clone`
51/// - `Debug`
52/// - `Eq`
53/// - `PartialEq`
54/// - `thiserror::Error`
55/// - `num_derive::FromPrimitive`
56/// - `Into<solana_program_error::ProgramError>`
57/// - `solana_program_error::ToStr`
58///
59/// Optionally, you can add `hash_error_code_start: u32` argument to create
60/// a unique `u32` _starting_ error codes from the names of the enum variants.
61/// Notes:
62/// - The _error_ variant will start at this value, and the rest will be
63///   incremented by one
64/// - The value provided is only for code readability, the actual error code
65///   will be a hash of the input string and is checked against your input
66///
67/// Syntax: `#[spl_program_error(hash_error_code_start = 1275525928)]`
68/// Hash Input: `spl_program_error:<enum name>:<variant name>`
69/// Value: `u32::from_le_bytes(<hash of input>[13..17])`
70#[proc_macro_attribute]
71pub fn spl_program_error(attr: TokenStream, input: TokenStream) -> TokenStream {
72    let args = parse_macro_input!(attr as SplProgramErrorArgs);
73    let item_enum = parse_macro_input!(input as ItemEnum);
74    MacroType::SplProgramError { args, item_enum }
75        .generate_tokens()
76        .into()
77}