use super::Type;
use crate::Value;
use std::{
any::{Any, TypeId},
fmt::Debug,
};
#[derive(Debug)]
pub enum RuntimeValue<'a> {
Value(Value),
Extern(Extern<'a>),
}
impl<'a> RuntimeValue<'a> {
pub fn type_of(&self) -> Type {
match self {
Self::Value(v) => v.type_of(),
Self::Extern(e) => e.type_of(),
}
}
pub fn clone_or_take(&mut self) -> Self {
match self {
Self::Value(value) => Self::Value(value.clone()),
#[cfg(feature = "extern_value_type")]
Self::Extern(Extern::Value(v)) => Self::Extern(Extern::Value(std::rc::Rc::clone(&*v))),
Self::Extern(Extern::Ref(v)) => Self::Extern(Extern::Ref(*v)),
v => std::mem::take(v),
}
}
#[cfg(feature = "bool_type")]
pub(crate) fn as_bool(&self) -> Result<bool, super::RuntimeError> {
use super::Type;
match self {
Self::Value(Value::Bool(b)) => Ok(*b),
_ => Err(super::RuntimeError::TypeMismatch {
expected: Type::Bool,
actual: self.type_of(),
}),
}
}
pub(crate) fn receiver_type_id_extern_type(&self) -> (TypeId, Option<Type>) {
match self {
Self::Value(_) => (TypeId::of::<Value>(), None),
Self::Extern(e) => match e {
#[cfg(feature = "extern_value_type")]
Extern::Value(v) => ((**v).type_id(), Some(Type::ExternValue)),
Extern::Ref(r) => ((**r).type_id(), Some(Type::ExternRef)),
Extern::Mut(m) => ((**m).type_id(), Some(Type::ExternMut)),
},
}
}
}
impl<'a> Default for RuntimeValue<'a> {
fn default() -> Self {
Self::Value(Default::default())
}
}
#[non_exhaustive]
pub enum Extern<'a> {
#[cfg(feature = "extern_value_type")]
Value(std::rc::Rc<dyn Any>),
Ref(&'a dyn Any),
Mut(&'a mut dyn Any),
}
impl<'a> Extern<'a> {
pub fn type_of(&self) -> Type {
match self {
#[cfg(feature = "extern_value_type")]
Self::Value(_) => Type::ExternValue,
Self::Ref(_) => Type::ExternRef,
Self::Mut(_) => Type::ExternMut,
}
}
}
impl<'a> Debug for Extern<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
#[cfg(feature = "extern_value_type")]
Self::Value(p) => write!(
f,
"ExternValue@{:x}",
std::rc::Rc::as_ptr(p) as *const () as usize
),
Self::Ref(p) => write!(f, "ExternRef@{:x}", *p as *const _ as *const () as usize),
Self::Mut(p) => write!(f, "ExternMut@{:x}", *p as *const _ as *const () as usize),
}
}
}
impl<'a, 'b> PartialEq<RuntimeValue<'b>> for RuntimeValue<'a> {
fn eq(&self, other: &RuntimeValue<'b>) -> bool {
match (self, other) {
(Self::Value(v), RuntimeValue::Value(v2)) => v == v2,
(Self::Extern(e), RuntimeValue::Extern(e2)) => e == e2,
_ => false,
}
}
}
impl<'a, 'b> PartialEq<Extern<'b>> for Extern<'a> {
fn eq(&self, other: &Extern<'b>) -> bool {
match (self, other) {
#[cfg(feature = "extern_value_type")]
(Self::Value(v), Extern::Value(v2)) => std::rc::Rc::ptr_eq(v, v2),
(Self::Ref(v), Extern::Ref(v2)) => std::ptr::eq(&**v, &**v2),
(Self::Mut(v), Extern::Mut(v2)) => std::ptr::eq(&**v, &**v2),
_ => false,
}
}
}