use std::{
ptr,
slice,
};
use libc::size_t;
use crate::ffi;
use crate::ffi::error::Error;
use crate::protobuf::ToProtobuf;
#[repr(C)]
pub struct TokenBalance {
id_shard: u64,
id_realm: u64,
id_num: u64,
amount: u64,
decimals: u32,
}
#[repr(C)]
pub struct AccountBalance {
id: ffi::AccountId,
hbars: i64,
token_balances: *const TokenBalance,
token_balances_len: size_t,
}
impl AccountBalance {
fn borrow_ref<'a>(&'a self) -> RefAccountBalance<'a> {
let token_balances =
unsafe { slice::from_raw_parts(self.token_balances, self.token_balances_len) };
RefAccountBalance { id: self.id.borrow_ref(), hbars: self.hbars, token_balances }
}
}
impl From<crate::AccountBalance> for AccountBalance {
#[allow(deprecated)]
fn from(it: crate::AccountBalance) -> Self {
let token_balances: Vec<_> = it
.tokens
.iter()
.map(|(&id, &balance)| (id, balance, it.token_decimals[&id]))
.map(|(id, amount, decimals)| TokenBalance {
id_shard: id.shard,
id_realm: id.realm,
id_num: id.num,
amount,
decimals,
})
.collect();
let token_balances_len = token_balances.len();
let token_balances = Box::leak(token_balances.into_boxed_slice()).as_ptr();
Self {
id: it.account_id.into(),
hbars: it.hbars.to_tinybars(),
token_balances,
token_balances_len,
}
}
}
struct RefAccountBalance<'a> {
id: ffi::RefAccountId<'a>,
hbars: i64,
token_balances: &'a [TokenBalance],
}
impl<'a> ToProtobuf for RefAccountBalance<'a> {
type Protobuf = hedera_proto::services::CryptoGetAccountBalanceResponse;
fn to_protobuf(&self) -> Self::Protobuf {
use hedera_proto::services;
#[allow(deprecated)]
services::CryptoGetAccountBalanceResponse {
header: None,
account_id: Some(self.id.to_protobuf()),
balance: self.hbars as u64,
token_balances: self
.token_balances
.iter()
.map(|it| services::TokenBalance {
token_id: Some(
crate::TokenId::new(it.id_shard, it.id_realm, it.id_num).to_protobuf(),
),
balance: it.amount,
decimals: it.decimals,
})
.collect(),
}
}
}
impl<'a> RefAccountBalance<'a> {
fn into_bytes(self) -> Vec<u8> {
use prost::Message;
self.to_protobuf().encode_to_vec()
}
}
#[no_mangle]
pub unsafe extern "C" fn hedera_account_balance_from_bytes(
bytes: *const u8,
bytes_size: size_t,
id: *mut AccountBalance,
) -> Error {
assert!(!bytes.is_null());
assert!(!id.is_null());
let bytes = unsafe { std::slice::from_raw_parts(bytes, bytes_size) };
let parsed = ffi_try!(crate::AccountBalance::from_bytes(&bytes)).into();
unsafe {
ptr::write(id, parsed);
}
Error::Ok
}
#[no_mangle]
pub unsafe extern "C" fn hedera_account_balance_to_bytes(
id: AccountBalance,
buf: *mut *mut u8,
) -> size_t {
let bytes = id.borrow_ref().into_bytes().into_boxed_slice();
let bytes = Box::leak(bytes);
let len = bytes.len();
let bytes = bytes.as_mut_ptr();
unsafe {
ptr::write(buf, bytes);
}
len
}
#[no_mangle]
pub unsafe extern "C" fn hedera_account_balance_token_balances_free(
token_balances: *mut TokenBalance,
size: size_t,
) {
assert!(!token_balances.is_null());
let buf = unsafe {
let token_balances = slice::from_raw_parts_mut(token_balances, size);
Box::from_raw(token_balances)
};
drop(buf);
}