#![allow(
unsafe_code,
reason = "FFI error retrieval requires unsafe calls to xmtp_sys"
)]
use std::ffi::CStr;
pub type Result<T> = std::result::Result<T, XmtpError>;
#[derive(Debug, thiserror::Error)]
pub enum XmtpError {
#[error("xmtp ffi: {0}")]
Ffi(String),
#[error("unexpected null pointer from FFI")]
NullPointer,
#[error("invalid UTF-8 in FFI string")]
InvalidUtf8,
#[error("{0}")]
InvalidArgument(String),
#[error("signing: {0}")]
Signing(String),
#[error("no resolver configured — use ClientBuilder::resolver()")]
NoResolver,
#[error("resolution: {0}")]
Resolution(String),
#[error("io: {0}")]
Io(String),
}
pub(crate) fn last_ffi_error() -> XmtpError {
let len = unsafe { xmtp_sys::xmtp_last_error_length() };
if len <= 0 {
return XmtpError::Ffi("unknown FFI error".into());
}
let mut buf = vec![0u8; len.unsigned_abs() as usize];
let written = unsafe { xmtp_sys::xmtp_last_error_message(buf.as_mut_ptr().cast(), len) };
if written <= 0 {
return XmtpError::Ffi("failed to read FFI error".into());
}
let written_len = written.unsigned_abs() as usize;
CStr::from_bytes_until_nul(&buf).map_or_else(
|_| {
XmtpError::Ffi(
String::from_utf8_lossy(buf.get(..written_len).unwrap_or(&buf)).into_owned(),
)
},
|cstr| XmtpError::Ffi(cstr.to_string_lossy().into_owned()),
)
}
#[inline]
pub(crate) fn check(rc: i32) -> Result<()> {
if rc == 0 {
Ok(())
} else {
Err(last_ffi_error())
}
}