use std::fmt::Debug;
use crate::{
env::EnvClient,
external::{
read_account_from_ledger, read_contract_data_entry_by_contract_id_and_key, read_contract_entries_by_contract, read_contract_entries_by_contract_to_env, read_contract_instance
},
ContractDataEntry, ContractDataEntryStellarXDR, SdkError,
};
use rs_zephyr_common::{wrapping::WrappedMaxBytes, Account};
use serde::Deserialize;
use soroban_sdk::xdr::{LedgerEntryData, Limits, ScVal, WriteXdr};
use soroban_sdk::{Map, TryFromVal, Val};
impl EnvClient {
fn express_and_deser_entry<'a, D: Deserialize<'a> + Into<O>, O>(
status: i64,
offset: i64,
size: i64,
) -> Result<Option<O>, SdkError> {
SdkError::express_from_status(status)?;
let memory: *const u8 = offset as *const u8;
let slice = unsafe { core::slice::from_raw_parts(memory, size as usize) };
let deser = bincode::deserialize::<Option<D>>(slice)
.map_err(|_| SdkError::Conversion)?;
if deser.is_none() {
return Ok(None);
}
Ok(Some(deser.unwrap().into()))
}
pub fn read_contract_instance(
&self,
contract: [u8; 32],
) -> Result<Option<ContractDataEntry>, SdkError> {
let contract_parts = WrappedMaxBytes::array_to_max_parts::<4>(&contract);
let (status, offset, size) = unsafe {
read_contract_instance(
contract_parts[0],
contract_parts[1],
contract_parts[2],
contract_parts[3],
)
};
Self::express_and_deser_entry::<ContractDataEntryStellarXDR, ContractDataEntry>(status, offset, size)
}
pub fn read_contract_entry_by_scvalkey(
&self,
contract: [u8; 32],
key: ScVal,
) -> Result<Option<ContractDataEntry>, SdkError> {
let key_bytes = key.to_xdr(Limits::none()).unwrap();
let (offset, size) = (key_bytes.as_ptr() as i64, key_bytes.len() as i64);
let contract_parts = WrappedMaxBytes::array_to_max_parts::<4>(&contract);
let (status, inbound_offset, inbound_size) = unsafe {
read_contract_data_entry_by_contract_id_and_key(
contract_parts[0],
contract_parts[1],
contract_parts[2],
contract_parts[3],
offset,
size,
)
};
Self::express_and_deser_entry::<ContractDataEntryStellarXDR, ContractDataEntry>(status, inbound_offset, inbound_size)
}
pub fn read_full_contract_entry_by_key<
T: soroban_sdk::TryIntoVal<soroban_sdk::Env, soroban_sdk::Val>,
>(
&self,
contract: [u8; 32],
val: T,
) -> Result<Option<ContractDataEntry>, SdkError> {
let key = self.to_scval(val);
let key_bytes = key.to_xdr(Limits::none()).unwrap();
let (offset, size) = (key_bytes.as_ptr() as i64, key_bytes.len() as i64);
let contract_parts = WrappedMaxBytes::array_to_max_parts::<4>(&contract);
let (status, inbound_offset, inbound_size) = unsafe {
read_contract_data_entry_by_contract_id_and_key(
contract_parts[0],
contract_parts[1],
contract_parts[2],
contract_parts[3],
offset,
size,
)
};
Self::express_and_deser_entry::<ContractDataEntryStellarXDR, ContractDataEntry>(status, inbound_offset, inbound_size)
}
pub fn read_contract_entry_by_key<
T: soroban_sdk::TryIntoVal<soroban_sdk::Env, soroban_sdk::Val>,
R: soroban_sdk::TryFromVal<soroban_sdk::Env, soroban_sdk::Val> + Debug,
>(
&self,
contract: [u8; 32],
val: T,
) -> Result<Option<R>, SdkError> {
let key = self.to_scval(val);
let key_bytes = key.to_xdr(Limits::none()).unwrap();
let (offset, size) = (key_bytes.as_ptr() as i64, key_bytes.len() as i64);
let contract_parts = WrappedMaxBytes::array_to_max_parts::<4>(&contract);
let (status, inbound_offset, inbound_size) = unsafe {
read_contract_data_entry_by_contract_id_and_key(
contract_parts[0],
contract_parts[1],
contract_parts[2],
contract_parts[3],
offset,
size,
)
};
let resp = Self::express_and_deser_entry::<ContractDataEntryStellarXDR, ContractDataEntry>(status, inbound_offset, inbound_size)?;
if resp.is_none() {
return Ok(None);
}
let LedgerEntryData::ContractData(data) = resp.unwrap().entry.data else {
panic!()
};
Ok(Some(self.from_scval::<R>(&data.val)))
}
pub fn read_contract_entries(
&self,
contract: [u8; 32],
) -> Result<Vec<ContractDataEntry>, SdkError> {
let contract_parts = WrappedMaxBytes::array_to_max_parts::<4>(&contract);
let (status, offset, size) = unsafe {
read_contract_entries_by_contract(
contract_parts[0],
contract_parts[1],
contract_parts[2],
contract_parts[3],
)
};
SdkError::express_from_status(status)?;
let memory: *const u8 = offset as *const u8;
let slice = unsafe { core::slice::from_raw_parts(memory, size as usize) };
let deser = bincode::deserialize::<Vec<ContractDataEntryStellarXDR>>(slice)
.map_err(|_| SdkError::Conversion)?;
Ok(deser.iter().map(|entry| entry.clone().into()).collect())
}
pub fn read_contract_entries_to_env(
&self,
env: &soroban_sdk::Env,
contract: [u8; 32],
) -> Result<Map<Val, Val>, SdkError> {
let contract_parts = WrappedMaxBytes::array_to_max_parts::<4>(&contract);
let (status, mapobject) = unsafe {
read_contract_entries_by_contract_to_env(
contract_parts[0],
contract_parts[1],
contract_parts[2],
contract_parts[3],
)
};
SdkError::express_from_status(status)?;
let map = Map::try_from_val(env, &Val::from_payload(mapobject as u64)).unwrap();
Ok(map)
}
pub fn read_account_from_ledger(&self, account: [u8;32]) -> Result<Option<Account>, SdkError> {
let account_parts = WrappedMaxBytes::array_to_max_parts::<4>(&account);
let (status, offset, size) = unsafe {
read_account_from_ledger(
account_parts[0],
account_parts[1],
account_parts[2],
account_parts[3],
)
};
Self::express_and_deser_entry::<Account, Account>(status, offset, size)
}
}