use std::{
collections::HashMap,
fmt::Write,
sync::{Arc, Mutex},
};
use solana_idl::{Idl, IdlTypeDefinitionTy};
use super::{
discriminator::JsonAccountsDiscriminator, JsonTypeDefinitionDeserializerMap,
};
use crate::{
deserializer::DeserializeProvider,
discriminator::discriminator_from_data,
errors::ChainparserResult,
idl::IdlProvider,
json::{JsonIdlTypeDefinitionDeserializer, JsonSerializationOpts},
};
pub struct JsonAccountsDeserializer<'opts> {
pub discriminator: JsonAccountsDiscriminator<'opts>,
pub serialization_opts: &'opts JsonSerializationOpts,
pub type_de_map: JsonTypeDefinitionDeserializerMap<'opts>,
}
impl<'opts> JsonAccountsDeserializer<'opts> {
pub fn try_from_idl(
json: &str,
provider: IdlProvider,
serialization_opts: &'opts JsonSerializationOpts,
) -> ChainparserResult<Self> {
let idl: Idl = serde_json::from_str(json)?;
let de_resolver = DeserializeProvider::try_from(&idl)?;
Ok(Self::from_idl(
&idl,
de_resolver,
provider,
serialization_opts,
))
}
pub fn from_idl(
idl: &Idl,
de_provider: DeserializeProvider,
provider: IdlProvider,
serialization_opts: &'opts JsonSerializationOpts,
) -> Self {
let type_de_map = Arc::new(Mutex::new(HashMap::new()));
let mut type_map = HashMap::<String, &IdlTypeDefinitionTy>::new();
for type_definition in &idl.types {
type_map.insert(type_definition.name.clone(), &type_definition.ty);
let instance = JsonIdlTypeDefinitionDeserializer::new(
type_definition,
type_de_map.clone(),
serialization_opts,
);
type_de_map
.lock()
.unwrap()
.insert(instance.name.clone(), instance);
}
let discriminator = JsonAccountsDiscriminator::new(
de_provider,
provider,
idl,
&type_map,
type_de_map.clone(),
serialization_opts,
);
Self {
serialization_opts,
discriminator,
type_de_map,
}
}
pub fn deserialize_account_data<W: Write>(
&self,
account_data: &mut &[u8],
f: &mut W,
) -> ChainparserResult<()> {
use JsonAccountsDiscriminator::*;
match &self.discriminator {
PrefixDiscriminator(disc) => {
disc.deserialize_account_data(account_data, f)
}
MatchDiscriminator(disc) => {
disc.deserialize_account_data(account_data, f)
}
}
}
pub fn deserialize_account_data_by_name<W: Write>(
&self,
account_data: &mut &[u8],
account_name: &str,
f: &mut W,
) -> ChainparserResult<()> {
use JsonAccountsDiscriminator::*;
match &self.discriminator {
PrefixDiscriminator(disc) => disc.deserialize_account_data_by_name(
account_data,
account_name,
f,
),
MatchDiscriminator(disc) => disc.deserialize_account_data_by_name(
account_data,
account_name,
f,
),
}
}
pub fn account_name(&self, account_data: &[u8]) -> Option<&str> {
use JsonAccountsDiscriminator::*;
match &self.discriminator {
PrefixDiscriminator(disc) => {
if account_data.len() < 8 {
return None;
}
let discriminator =
discriminator_from_data(&account_data[0..8]);
disc.account_name(&discriminator)
}
MatchDiscriminator(disc) => disc.account_name(account_data),
}
}
}
impl Drop for JsonAccountsDeserializer<'_> {
fn drop(&mut self) {
self.type_de_map.lock().unwrap().clear();
}
}