evalit 0.2.0-beta.0

a toy interpreter
Documentation
use std::fmt;

#[cfg(not(feature = "async"))]
use std::{
    cell::{Ref, RefCell, RefMut},
    rc::Rc,
};

#[cfg(feature = "async")]
use std::sync::Arc;

#[cfg(feature = "async")]
use parking_lot::{
    MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
};

use super::{Immd, Null, Object};
use crate::bytecode::{Constant, Primitive};

#[derive(Debug)]
pub struct Value(Box<dyn Object>);

impl Value {
    pub fn new<T: Object>(object: T) -> Self {
        Value(Box::new(object))
    }

    pub fn null() -> Self {
        Value(Box::new(Null))
    }

    pub fn downcast_ref<T: Object + 'static>(&self) -> Option<&T> {
        let any = &*self.0 as &dyn std::any::Any;
        any.downcast_ref::<T>()
    }

    pub fn downcast_mut<T: Object + 'static>(&mut self) -> Option<&mut T> {
        let any = &mut *self.0 as &mut dyn std::any::Any;
        any.downcast_mut::<T>()
    }

    pub fn as_object(&self) -> &dyn Object {
        &*self.0
    }

    pub fn as_object_mut(&mut self) -> &mut dyn Object {
        &mut *self.0
    }

    pub fn into_inner<T: Object + 'static>(self) -> Result<T, Box<dyn std::any::Any + 'static>> {
        (self.0 as Box<dyn std::any::Any>)
            .downcast::<T>()
            .map(|v| *v)
    }
}

#[cfg(feature = "async")]
#[derive(Debug, Clone)]
pub struct ValueRef(Arc<RwLock<Value>>);

#[cfg(feature = "async")]
impl ValueRef {
    pub fn new<T: Object + 'static>(object: T) -> Self {
        ValueRef(Arc::new(RwLock::new(Value::new(object))))
    }

    pub fn from_value(value: Value) -> Self {
        ValueRef(Arc::new(RwLock::new(value)))
    }

    pub fn value(&self) -> RwLockReadGuard<Value> {
        self.0.read()
    }

    pub fn value_mut(&self) -> RwLockWriteGuard<Value> {
        self.0.write()
    }

    pub fn as_object(&self) -> MappedRwLockReadGuard<'_, dyn Object> {
        let guard = self.0.read();
        RwLockReadGuard::map(guard, |value: &Value| value.as_object())
    }

    pub fn as_object_mut(&self) -> MappedRwLockWriteGuard<'_, dyn Object> {
        let guard = self.0.write();
        RwLockWriteGuard::map(guard, |value: &mut Value| value.as_object_mut())
    }

    pub fn null() -> Self {
        ValueRef(Arc::new(RwLock::new(Value::null())))
    }

    pub fn immd(immd: isize) -> Self {
        Self::new(Immd(immd))
    }

    pub fn take(&self) -> Value {
        let mut lock = self.0.write();
        std::mem::replace(&mut *lock, Value::null())
    }

    pub fn from_constant(constant: &Constant) -> Self {
        match constant {
            Constant::String(s) => Self::new(s.to_string()),
        }
    }

    pub fn from_primitive(primitive: Primitive) -> Self {
        match primitive {
            Primitive::Null => Self::null(),
            Primitive::Byte(b) => Self::new(b),
            Primitive::Boolean(b) => Self::new(b),
            Primitive::Integer(i) => Self::new(i),
            Primitive::Float(f) => Self::new(f),
            Primitive::Char(c) => Self::new(c),
        }
    }
}

#[cfg(not(feature = "async"))]
#[derive(Debug, Clone)]
pub struct ValueRef(Rc<RefCell<Value>>);

#[cfg(not(feature = "async"))]
impl ValueRef {
    pub fn new<T: Object + 'static>(object: T) -> Self {
        ValueRef(Rc::new(RefCell::new(Value::new(object))))
    }

    pub fn from_value(value: Value) -> Self {
        ValueRef(Rc::new(RefCell::new(value)))
    }

    pub fn value(&self) -> Ref<Value> {
        self.0.borrow()
    }

    pub fn value_mut(&self) -> RefMut<Value> {
        self.0.borrow_mut()
    }

    pub fn as_object(&self) -> Ref<dyn Object> {
        let guard = self.0.borrow();
        Ref::map(guard, |value| value.as_object())
    }

    pub fn as_object_mut(&self) -> RefMut<dyn Object> {
        let guard = self.0.borrow_mut();
        RefMut::map(guard, |value| value.as_object_mut())
    }

    pub fn null() -> Self {
        Self::new(Null {})
    }

    pub fn immd(immd: isize) -> Self {
        Self::new(Immd(immd))
    }

    pub fn take(&self) -> Value {
        self.0.replace(Value::null())
    }

    pub fn from_constant(constant: &Constant) -> Self {
        match constant {
            Constant::String(s) => Self::new(s.to_string()),
        }
    }

    pub fn from_primitive(primitive: Primitive) -> Self {
        match primitive {
            Primitive::Null => Self::null(),
            Primitive::Byte(b) => Self::new(b),
            Primitive::Boolean(b) => Self::new(b),
            Primitive::Integer(i) => Self::new(i),
            Primitive::Float(f) => Self::new(f),
            Primitive::Char(c) => Self::new(c),
        }
    }
}

impl From<Value> for ValueRef {
    fn from(value: Value) -> Self {
        Self::from_value(value)
    }
}

impl fmt::Display for ValueRef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.value().as_object().debug(f)
    }
}