use std::{
cell::RefCell,
fmt::{Debug, Display, Formatter},
};
use crate::runtime::{Cell, Origin, RuntimeError};
pub(crate) struct Stringifier<'a> {
pub(crate) origin: Origin,
pub(crate) cell: &'a Cell,
pub(crate) error: RefCell<Option<RuntimeError>>,
pub(crate) fallback_to_type: bool,
}
impl<'a> Display for Stringifier<'a> {
#[inline(always)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
let result = self
.cell
.clone()
.into_object()
.display(self.origin, self.origin, formatter);
if let Err(error) = result {
let is_format_error = match &error {
RuntimeError::FormatError { .. } => true,
_ => false,
};
*self.error.borrow_mut() = Some(error);
if is_format_error {
return Err(std::fmt::Error);
}
if self.fallback_to_type {
formatter.write_str(&format!("<{}>", self.cell.ty()))?;
}
}
Ok(())
}
}
impl<'a> Debug for Stringifier<'a> {
#[inline(always)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
let result = self
.cell
.clone()
.into_object()
.debug(self.origin, self.origin, formatter);
if let Err(error) = result {
let is_format_error = match &error {
RuntimeError::FormatError { .. } => true,
_ => false,
};
*self.error.borrow_mut() = Some(error);
if is_format_error {
return Err(std::fmt::Error);
}
if self.fallback_to_type {
formatter.write_str(&format!("<{}>", self.cell.ty()))?;
}
}
Ok(())
}
}
impl Cell {
#[inline(always)]
pub fn stringify(&self, alt: bool) -> String {
let stringifier = Stringifier {
origin: Origin::nil(),
cell: self,
error: RefCell::new(None),
fallback_to_type: true,
};
let result = match (self.ty().prototype().implements_display(), alt) {
(true, true) => format!("{stringifier:#}"),
(true, false) => format!("{stringifier:}"),
(false, true) => format!("{stringifier:#?}"),
(false, false) => format!("{stringifier:?}"),
};
result
}
}
macro_rules! transparent_upcast {
($ty:ty) => {
impl<'a> $crate::runtime::Upcast<'a> for $ty {
type Output = ::std::boxed::Box<$ty>;
#[inline(always)]
fn upcast(
_origin: $crate::runtime::Origin,
this: Self,
) -> $crate::runtime::RuntimeResult<Self::Output> {
::std::result::Result::Ok(::std::boxed::Box::new(this))
}
#[inline(always)]
fn hint() -> $crate::runtime::TypeHint {
$crate::runtime::TypeHint::Type(<$ty as $crate::runtime::ScriptType>::type_meta())
}
}
impl<'a> $crate::runtime::Upcast<'a> for &'a $ty {
type Output = &'a $ty;
#[inline(always)]
fn upcast(
_origin: $crate::runtime::Origin,
this: Self,
) -> $crate::runtime::RuntimeResult<Self::Output> {
::std::result::Result::Ok(this)
}
#[inline(always)]
fn hint() -> $crate::runtime::TypeHint {
$crate::runtime::TypeHint::Type(<$ty as $crate::runtime::ScriptType>::type_meta())
}
}
impl<'a> $crate::runtime::Upcast<'a> for &'a mut $ty {
type Output = &'a mut $ty;
#[inline(always)]
fn upcast(
_origin: $crate::runtime::Origin,
this: Self,
) -> $crate::runtime::RuntimeResult<Self::Output> {
::std::result::Result::Ok(this)
}
#[inline(always)]
fn hint() -> $crate::runtime::TypeHint {
$crate::runtime::TypeHint::Type(<$ty as $crate::runtime::ScriptType>::type_meta())
}
}
};
}
pub(crate) use transparent_upcast;