use crate::{account::KeyedAccount, instruction::InstructionError, pubkey::Pubkey}; use num_traits::{FromPrimitive, ToPrimitive}; // All native programs export a symbol named process() pub const ENTRYPOINT: &str = "process"; // Native program ENTRYPOINT prototype pub type Entrypoint = unsafe extern "C" fn( program_id: &Pubkey, keyed_accounts: &mut [KeyedAccount], data: &[u8], ) -> Result<(), InstructionError>; // Convenience macro to define the native program entrypoint. Supply a fn to this macro that // conforms to the `Entrypoint` type signature. #[macro_export] macro_rules! solana_entrypoint( ($entrypoint:ident) => ( #[no_mangle] pub extern "C" fn process( program_id: &$crate::pubkey::Pubkey, keyed_accounts: &mut [$crate::account::KeyedAccount], data: &[u8], ) -> Result<(), $crate::instruction::InstructionError> { $entrypoint(program_id, keyed_accounts, data) } ) ); impl From for InstructionError where T: ToPrimitive, { fn from(error: T) -> Self { InstructionError::CustomError(error.to_u32().unwrap_or(0xbad_c0de)) } } /// Return the next KeyedAccount or a NotEnoughAccountKeys instruction error pub fn next_keyed_account(iter: &mut I) -> Result { iter.next().ok_or(InstructionError::NotEnoughAccountKeys) } pub trait DecodeError { fn decode_custom_error_to_enum(custom: u32) -> Option where E: FromPrimitive, { E::from_u32(custom) } fn type_of() -> &'static str; } #[cfg(test)] mod tests { use super::*; use num_derive::FromPrimitive; #[test] fn test_decode_custom_error_to_enum() { #[derive(Debug, FromPrimitive, PartialEq)] enum TestEnum { A, B, C, } impl DecodeError for TestEnum { fn type_of() -> &'static str { "TestEnum" } } assert_eq!(TestEnum::decode_custom_error_to_enum(0), Some(TestEnum::A)); assert_eq!(TestEnum::decode_custom_error_to_enum(1), Some(TestEnum::B)); assert_eq!(TestEnum::decode_custom_error_to_enum(2), Some(TestEnum::C)); let option: Option = TestEnum::decode_custom_error_to_enum(3); assert_eq!(option, None); } }