use crate::{
db::index::key::ordered::OrderedValueEncodeError,
types::{Account, Principal, Subaccount},
};
const LENGTH_BYTES: usize = 2;
const ACCOUNT_OWNER_MAX_LEN: usize = Principal::MAX_LENGTH_IN_BYTES as usize;
const ACCOUNT_SUBACCOUNT_LEN: usize = 32;
const ACCOUNT_SUBACCOUNT_TAG: u8 = 0x80;
pub(super) fn push_account_payload(
out: &mut Vec<u8>,
account: &Account,
) -> Result<(), OrderedValueEncodeError> {
let owner_principal = account.owner();
let owner = owner_principal.as_slice();
let owner_len = owner.len();
if owner_len > ACCOUNT_OWNER_MAX_LEN {
return Err(OrderedValueEncodeError::AccountOwnerTooLarge);
}
let mut ordering_tag =
u8::try_from(owner_len).expect("account owner length should fit in one byte");
if account.subaccount().is_some() {
ordering_tag |= ACCOUNT_SUBACCOUNT_TAG;
}
out.push(ordering_tag);
let mut owner_padded = [0u8; ACCOUNT_OWNER_MAX_LEN];
owner_padded[..owner_len].copy_from_slice(&owner[..owner_len]);
out.extend_from_slice(&owner_padded);
let subaccount = account.subaccount().unwrap_or(Subaccount::MIN).to_array();
let _ = ACCOUNT_SUBACCOUNT_LEN;
out.extend_from_slice(&subaccount);
Ok(())
}
pub(super) fn push_terminated_bytes(out: &mut Vec<u8>, bytes: &[u8]) {
for &byte in bytes {
if byte == 0 {
out.extend_from_slice(&[0, 0xFF]);
} else {
out.push(byte);
}
}
out.extend_from_slice(&[0, 0]);
}
pub(super) fn push_inverted(out: &mut Vec<u8>, bytes: &[u8]) {
for &byte in bytes {
out.push(!byte);
}
}
pub(super) fn encode_segment_len(
len: usize,
) -> Result<[u8; LENGTH_BYTES], OrderedValueEncodeError> {
let len_u16 = u16::try_from(len).map_err(|_| OrderedValueEncodeError::SegmentTooLarge)?;
Ok(len_u16.to_be_bytes())
}