litto 0.1.0

Building blocks for DSL scripting language interpreters that interact with native Rust code.
Documentation
//! Example implementations about _value_.

use crate::Interpreter;
use gcmodule::{Cc, Trace, Tracer};
use std::fmt;
use std::ops::Deref;

/// An abstract value type that is tracked by a cyclic garbage collector.
///
/// Call `gcmodule::collect_thread_cycles` to collect cycles and reclaim space.
#[derive(Clone)]
pub struct Value<L: 'static> {
    // Ideally the Box can be removed.
    inner: Cc<Box<dyn AbstractValue<L>>>,
}

impl<L: Interpreter> Value<L> {
    /// Create a new `Value`.
    pub fn new<T: AbstractValue<L> + Sized>(value: T) -> Self {
        let value: Box<dyn AbstractValue<L>> = Box::new(value);
        Self {
            inner: Cc::new(value),
        }
    }

    /// Attempt to downcast.
    pub fn downcast_ref<T: AbstractValue<L> + Sized>(&self) -> Option<&T> {
        let inner: &dyn AbstractValue<L> = <Value<L> as Deref>::deref(self);
        inner.as_any().and_then(|any| any.downcast_ref::<T>())
    }
}

/// An abstract interface for `Value` that supports function calls.
pub trait AbstractValue<L: Interpreter>: Trace + fmt::Display + fmt::Debug {
    /// Call a function.
    ///
    /// This can have side effect on `env`. Errors might be used for special
    /// control flow purposes.
    fn apply(&self, env: &L::Env, args: &[L::Expr]) -> Result<L::Value, L::Error> {
        let _ = (env, args);
        Err(format!("{:?} is not callable", self).into())
    }
}

impl<L> Deref for Value<L> {
    type Target = dyn AbstractValue<L>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.inner.deref().deref()
    }
}

impl<L: 'static> Trace for Value<L> {
    fn trace(&self, tracer: &mut Tracer) {
        self.deref().trace(tracer)
    }
}

impl<L: Interpreter> Trace for Box<dyn AbstractValue<L>> {
    fn trace(&self, tracer: &mut Tracer) {
        self.deref().trace(tracer)
    }
}

impl<L: Interpreter> fmt::Display for Value<L> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.deref(), f)
    }
}

impl<L: Interpreter> fmt::Debug for Value<L> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.deref(), f)
    }
}