use std::collections::HashMap;
use solana_instruction::AccountMeta;
use solana_pubkey::Pubkey;
use crate::{DecodedInstruction, InstructionDecoder};
pub struct DecoderRegistry {
decoders: HashMap<Pubkey, Box<dyn InstructionDecoder>>,
}
impl std::fmt::Debug for DecoderRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DecoderRegistry")
.field("decoder_count", &self.decoders.len())
.field("program_ids", &self.decoders.keys().collect::<Vec<_>>())
.finish()
}
}
impl DecoderRegistry {
pub fn new() -> Self {
let mut registry = Self {
decoders: HashMap::new(),
};
registry.register(Box::new(crate::programs::ComputeBudgetInstructionDecoder));
registry.register(Box::new(crate::programs::SplTokenInstructionDecoder));
registry.register(Box::new(crate::programs::Token2022InstructionDecoder));
registry.register(Box::new(crate::programs::SystemInstructionDecoder));
#[cfg(feature = "light-protocol")]
{
registry.register(Box::new(crate::programs::LightSystemInstructionDecoder));
registry.register(Box::new(
crate::programs::AccountCompressionInstructionDecoder,
));
registry.register(Box::new(crate::programs::CTokenInstructionDecoder));
registry.register(Box::new(crate::programs::RegistryInstructionDecoder));
}
registry
}
pub fn register(&mut self, decoder: Box<dyn InstructionDecoder>) {
self.decoders.insert(decoder.program_id(), decoder);
}
pub fn register_all(&mut self, decoders: Vec<Box<dyn InstructionDecoder>>) {
for decoder in decoders {
self.register(decoder);
}
}
pub fn decode(
&self,
program_id: &Pubkey,
data: &[u8],
accounts: &[AccountMeta],
) -> Option<(DecodedInstruction, &dyn InstructionDecoder)> {
self.decoders.get(program_id).and_then(|decoder| {
decoder
.decode(data, accounts)
.map(|d| (d, decoder.as_ref()))
})
}
pub fn get_decoder(&self, program_id: &Pubkey) -> Option<&dyn InstructionDecoder> {
self.decoders.get(program_id).map(|d| d.as_ref())
}
pub fn has_decoder(&self, program_id: &Pubkey) -> bool {
self.decoders.contains_key(program_id)
}
}
impl Default for DecoderRegistry {
fn default() -> Self {
Self::new()
}
}