use crate::lowlevel::{FFISlice, GcHandle};
use std::str;
#[derive(Debug)]
pub struct Error {
message: Box<str>,
code: ErrorKind,
}
impl Error {
pub(crate) unsafe fn from_ffi(error: ErrorFFI) -> Self {
let message = str::from_boxed_utf8_unchecked(error.message.into_boxed_byte_slice());
if error.code == i32::MIN {
panic!("{}", message);
}
Self {
code: std::mem::transmute(error.code),
message,
}
}
pub fn kind(&self) -> ErrorKind {
self.code
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for Error {}
#[cfg_attr(not(doc), repr(i32))]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ErrorKind {
NotFound = -1,
PermissionDenied = -3,
InvalidFilename = -4,
OtherIO = -5,
InvalidDatabase = 103,
IndexDuplicateKey = 110,
InvalidIndexKey = 111,
IndexNotFound = 112,
LockTimeout = 120,
InvalidTransactionState = 126,
InvalidCollectionName = 130,
InvalidUpdateField = 136,
UnexpectedToken = 203,
InvalidDataType = 204,
InvalidInitialSize = 211,
InvalidNullCharString = 212,
InvalidFreeSpacePage = 213,
Unsupported = 300,
Uncategorized = 400,
}
#[repr(C)]
pub(crate) struct ErrorFFI {
message: FFISlice<u8>,
code: i32,
}
impl ErrorFFI {
pub unsafe fn into_result(self) -> super::Result<()> {
if self.code == 0 && self.message.is_null() {
return Ok(());
}
Err(Error::from_ffi(self))
}
}
#[repr(C)]
pub(crate) struct HandleErrorResult {
pub result: Option<GcHandle>,
pub error: ErrorFFI,
}
impl HandleErrorResult {
pub unsafe fn into_result(self) -> super::Result<GcHandle> {
if let Some(result) = self.result {
Ok(result)
} else {
Err(Error::from_ffi(self.error))
}
}
}
impl From<Error> for std::io::Error {
fn from(value: Error) -> Self {
use std::io::ErrorKind as IoErrorKind;
let kind = match value.kind() {
ErrorKind::NotFound => IoErrorKind::NotFound,
ErrorKind::PermissionDenied => IoErrorKind::PermissionDenied,
ErrorKind::InvalidFilename => IoErrorKind::InvalidInput,
ErrorKind::OtherIO => IoErrorKind::Other, ErrorKind::InvalidDatabase => IoErrorKind::InvalidData,
ErrorKind::IndexDuplicateKey => IoErrorKind::InvalidData,
ErrorKind::InvalidIndexKey => IoErrorKind::Unsupported,
ErrorKind::IndexNotFound => IoErrorKind::InvalidInput,
ErrorKind::LockTimeout => IoErrorKind::TimedOut,
ErrorKind::InvalidTransactionState => IoErrorKind::InvalidInput,
ErrorKind::InvalidCollectionName => IoErrorKind::InvalidInput,
ErrorKind::InvalidUpdateField => IoErrorKind::InvalidInput,
ErrorKind::UnexpectedToken => IoErrorKind::InvalidData,
ErrorKind::InvalidDataType => IoErrorKind::InvalidData,
ErrorKind::InvalidInitialSize => IoErrorKind::InvalidInput,
ErrorKind::InvalidNullCharString => IoErrorKind::InvalidInput,
ErrorKind::InvalidFreeSpacePage => IoErrorKind::InvalidData,
ErrorKind::Unsupported => IoErrorKind::Unsupported,
ErrorKind::Uncategorized => IoErrorKind::Other,
};
Self::new(kind, value)
}
}