solana_decode_error/
lib.rs

1//! Converting custom error codes to enums.
2
3use num_traits::FromPrimitive;
4
5/// Allows custom errors to be decoded back to their original enum.
6///
7/// Some Solana error enums, like [`ProgramError`], include a `Custom` variant,
8/// like [`ProgramError::Custom`], that contains a `u32` error code. This code
9/// may represent any error that is not covered by the error enum's named
10/// variants. It is common for programs to convert their own error enums to an
11/// error code and store it in the `Custom` variant, possibly with the help of
12/// the [`ToPrimitive`] trait.
13///
14/// This trait builds on the [`FromPrimitive`] trait to help convert those error
15/// codes to the original error enum they represent.
16///
17/// As this allows freely converting `u32` to any type that implements
18/// `FromPrimitive`, it is only used correctly when the caller is certain of the
19/// original error type.
20///
21/// [`ProgramError`]: https://docs.rs/solana-program-error/latest/solana_program_error/enum.ProgramError.html
22/// [`ProgramError::Custom`]: https://docs.rs/solana-program-error/latest/solana_program_error/enum.ProgramError.html#variant.Custom
23/// [`ToPrimitive`]: num_traits::ToPrimitive
24pub trait DecodeError<E> {
25    fn decode_custom_error_to_enum(custom: u32) -> Option<E>
26    where
27        E: FromPrimitive,
28    {
29        E::from_u32(custom)
30    }
31    fn type_of() -> &'static str;
32}
33
34#[cfg(test)]
35mod tests {
36    use {super::*, num_derive::FromPrimitive};
37
38    #[test]
39    fn test_decode_custom_error_to_enum() {
40        #[derive(Debug, FromPrimitive, PartialEq, Eq)]
41        enum TestEnum {
42            A,
43            B,
44            C,
45        }
46        impl<T> DecodeError<T> for TestEnum {
47            fn type_of() -> &'static str {
48                "TestEnum"
49            }
50        }
51        assert_eq!(TestEnum::decode_custom_error_to_enum(0), Some(TestEnum::A));
52        assert_eq!(TestEnum::decode_custom_error_to_enum(1), Some(TestEnum::B));
53        assert_eq!(TestEnum::decode_custom_error_to_enum(2), Some(TestEnum::C));
54        let option: Option<TestEnum> = TestEnum::decode_custom_error_to_enum(3);
55        assert_eq!(option, None);
56    }
57}