use crate::error::ptr::{MutPtr, OwnedPtr, SharedPtr};
use crate::error::{
ConcreteError, DynError, ErrorExt, OomOrDynErrorMut, OomOrDynErrorRef, OutOfMemory,
};
use core::{any::TypeId, fmt, ptr::NonNull};
use std_alloc::boxed::Box;
#[repr(C)]
pub(crate) struct Vtable {
pub(crate) display: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result,
pub(crate) debug: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result,
pub(crate) source: unsafe fn(SharedPtr<'_, DynError>) -> Option<OomOrDynErrorRef<'_>>,
pub(crate) source_mut: unsafe fn(MutPtr<'_, DynError>) -> Option<OomOrDynErrorMut<'_>>,
pub(crate) is: unsafe fn(SharedPtr<'_, DynError>, TypeId) -> bool,
pub(crate) as_dyn_core_error:
unsafe fn(SharedPtr<'_, DynError>) -> &(dyn core::error::Error + Send + Sync + 'static),
pub(crate) into_boxed_dyn_core_error:
unsafe fn(
OwnedPtr<DynError>,
)
-> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>,
pub(crate) drop_and_deallocate: unsafe fn(OwnedPtr<DynError>),
pub(crate) downcast: unsafe fn(OwnedPtr<DynError>, TypeId, NonNull<u8>),
}
impl Vtable {
pub(crate) fn of<E>() -> &'static Self
where
E: ErrorExt,
{
&Vtable {
display: display::<E>,
debug: debug::<E>,
source: source::<E>,
source_mut: source_mut::<E>,
is: is::<E>,
as_dyn_core_error: as_dyn_core_error::<E>,
into_boxed_dyn_core_error: into_boxed_dyn_core_error::<E>,
drop_and_deallocate: drop_and_deallocate::<E>,
downcast: downcast::<E>,
}
}
}
unsafe fn display<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let error = unsafe { error.as_ref() };
fmt::Display::fmt(error.error.ext_as_dyn_core_error(), f)
}
unsafe fn debug<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let error = unsafe { error.as_ref() };
fmt::Debug::fmt(error.error.ext_as_dyn_core_error(), f)
}
unsafe fn source<E>(error: SharedPtr<'_, DynError>) -> Option<OomOrDynErrorRef<'_>>
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let error = unsafe { error.as_ref() };
error.error.ext_source()
}
unsafe fn source_mut<E>(error: MutPtr<'_, DynError>) -> Option<OomOrDynErrorMut<'_>>
where
E: ErrorExt,
{
let mut error = error.cast::<ConcreteError<E>>();
let error = unsafe { error.as_mut() };
error.error.ext_source_mut()
}
unsafe fn is<E>(error: SharedPtr<'_, DynError>, type_id: TypeId) -> bool
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let error = unsafe { error.as_ref() };
error.error.ext_is(type_id)
}
unsafe fn as_dyn_core_error<E>(
error: SharedPtr<'_, DynError>,
) -> &(dyn core::error::Error + Send + Sync + 'static)
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let error = unsafe { error.as_ref() };
error.error.ext_as_dyn_core_error()
}
unsafe fn into_boxed_dyn_core_error<E>(
error: OwnedPtr<DynError>,
) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let error = unsafe { error.into_box() };
error.error.ext_into_boxed_dyn_core_error()
}
unsafe fn drop_and_deallocate<E>(error: OwnedPtr<DynError>)
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let _ = unsafe { error.into_box() };
}
unsafe fn downcast<E>(error: OwnedPtr<DynError>, type_id: TypeId, ret_ptr: NonNull<u8>)
where
E: ErrorExt,
{
let error = error.cast::<ConcreteError<E>>();
let mut error = unsafe { error.into_box() };
if error.error.ext_is(type_id) {
unsafe {
error.error.ext_move(ret_ptr);
}
} else {
let source = error
.error
.ext_take_source()
.expect("must have a source up the chain if `E` is not our target type");
unsafe {
source.downcast(type_id, ret_ptr);
}
}
}