use std::cell::RefCell;
use std::ffi::CString;
use std::os::raw::c_char;
use std::ptr;
thread_local! {
static LAST_ERROR: RefCell<Option<crate::Error>> = RefCell::new(None);
static LAST_ERROR_MESSAGE: RefCell<CString> = RefCell::new(CString::new("").unwrap());
}
macro_rules! ffi_try {
($expr:expr) => {{
match $expr {
Ok(it) => it,
Err(error) => {
return $crate::ffi::error::Error::new(error);
}
}
}};
}
pub(crate) fn set_last_error(error: crate::Error) {
LAST_ERROR.with(|slot| {
slot.borrow_mut().replace(error);
});
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[repr(C)]
pub enum Error {
Ok,
TimedOut,
GrpcStatus,
FromProtobuf,
TransactionPreCheckStatus,
TransactionNoIdPreCheckStatus,
QueryPreCheckStatus,
QueryPaymentPreCheckStatus,
QueryNoPaymentPreCheckStatus,
BasicParse,
KeyParse,
KeyDerive,
NoPayerAccountOrTransactionId,
MaxQueryPaymentExceeded,
NodeAccountUnknown,
ResponseStatusUnrecognized,
ReceiptStatus,
Signature,
RequestParse,
MnemonicParse,
MnemonicEntropy,
SignatureVerify,
BadEntityId,
CannotToStringWithChecksum,
CannotPerformTaskWithoutLedgerId,
NoEvmAddressPresent,
WrongKeyType,
}
impl Error {
pub(crate) fn new(error: crate::Error) -> Self {
let err = match &error {
crate::Error::TimedOut(_) => Self::TimedOut,
crate::Error::GrpcStatus(_) => Self::GrpcStatus,
crate::Error::FromProtobuf(_) => Self::FromProtobuf,
crate::Error::TransactionPreCheckStatus { .. } => Self::TransactionPreCheckStatus,
crate::Error::TransactionNoIdPreCheckStatus { .. } => {
Self::TransactionNoIdPreCheckStatus
}
crate::Error::QueryPreCheckStatus { .. } => Self::QueryPreCheckStatus,
crate::Error::QueryPaymentPreCheckStatus { .. } => Self::QueryPaymentPreCheckStatus,
crate::Error::QueryNoPaymentPreCheckStatus { .. } => Self::QueryNoPaymentPreCheckStatus,
crate::Error::BasicParse(_) => Self::BasicParse,
crate::Error::KeyParse(_) => Self::KeyParse,
crate::Error::KeyDerive(_) => Self::KeyDerive,
crate::Error::NoPayerAccountOrTransactionId => Self::NoPayerAccountOrTransactionId,
crate::Error::MaxQueryPaymentExceeded { .. } => Self::MaxQueryPaymentExceeded,
crate::Error::NodeAccountUnknown(_) => Self::NodeAccountUnknown,
crate::Error::ResponseStatusUnrecognized(_) => Self::ResponseStatusUnrecognized,
crate::Error::ReceiptStatus { .. } => Self::ReceiptStatus,
crate::Error::Signature(_) => Self::Signature,
crate::Error::RequestParse(_) => Self::RequestParse,
crate::Error::MnemonicParse { .. } => Self::MnemonicParse,
crate::Error::MnemonicEntropy(_) => Self::MnemonicEntropy,
crate::Error::SignatureVerify(_) => Self::SignatureVerify,
crate::Error::BadEntityId { .. } => Self::BadEntityId,
crate::Error::CannotToStringWithChecksum => Self::CannotToStringWithChecksum,
crate::Error::CannotPerformTaskWithoutLedgerId { .. } => {
Self::CannotPerformTaskWithoutLedgerId
}
crate::Error::NoEvmAddressPresent { .. } => Self::NoEvmAddressPresent,
crate::Error::WrongKeyType { .. } => Self::WrongKeyType,
};
set_last_error(error);
err
}
}
#[no_mangle]
pub extern "C" fn hedera_error_message() -> *mut c_char {
LAST_ERROR.with(|error| {
if let Some(error) = &*error.borrow() {
return CString::new(error.to_string()).unwrap().into_raw();
}
ptr::null_mut()
})
}
#[no_mangle]
pub extern "C" fn hedera_error_grpc_status() -> i32 {
LAST_ERROR.with(|error| {
if let Some(crate::Error::GrpcStatus(status)) = &*error.borrow() {
return status.code() as i32;
}
-1
})
}
#[no_mangle]
pub extern "C" fn hedera_error_pre_check_status() -> i32 {
LAST_ERROR.with(|error| {
if let Some(error) = &*error.borrow() {
if let crate::Error::TransactionPreCheckStatus { status, .. }
| crate::Error::TransactionNoIdPreCheckStatus { status }
| crate::Error::QueryPreCheckStatus { status, .. }
| crate::Error::QueryPaymentPreCheckStatus { status, .. }
| crate::Error::QueryNoPaymentPreCheckStatus { status } = error
{
return *status as i32;
}
}
-1
})
}
#[no_mangle]
pub extern "C" fn hedera_error_receipt_status_status() -> i32 {
LAST_ERROR.with(|error| {
if let Some(error) = &*error.borrow() {
if let crate::Error::ReceiptStatus { status, .. } = error {
return *status as i32;
}
}
-1
})
}