1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
//! Types that implement `Value` can be represented in the Artichoke VM.

use alloc::vec::Vec;

use crate::convert::{TryConvert, TryConvertMut};
use crate::types::Ruby;

/// A boxed Ruby value owned by the interpreter.
///
/// `Value` is equivalent to an `RValue` in MRI or `mrb_value` in mruby.
pub trait Value {
    /// Concrete type for Artichoke interpreter.
    type Artichoke;

    /// Concrete type for arguments passed to [`funcall`](Value::funcall).
    type Arg;

    /// Concrete type for results from [`funcall`](Value::funcall).
    type Value: Value;

    /// Concrete type for blocks passed to [`funcall`](Value::funcall).
    type Block;

    /// Concrete error type for funcall errors.
    type Error;

    /// Call a method on this [`Value`] with arguments and an optional block.
    ///
    /// # Errors
    ///
    /// If an exception is raised on the interpreter, then an error is returned.
    ///
    /// If a [`TryConvert`] conversion fails, then an error is returned.
    fn funcall(
        &self,
        interp: &mut Self::Artichoke,
        func: &str,
        args: &[Self::Arg],
        block: Option<Self::Block>,
    ) -> Result<Self::Value, Self::Error>;

    /// Consume `self` and try to convert `self` to type `T` using a
    /// [`TryConvert`] conversion.
    ///
    /// # Errors
    ///
    /// If a [`TryConvert`] conversion fails, then an error is returned.
    fn try_into<T>(self, interp: &Self::Artichoke) -> Result<T, Self::Error>
    where
        Self: Sized,
        Self::Artichoke: TryConvert<Self, T, Error = Self::Error>,
    {
        interp.try_convert(self)
    }

    /// Consume `self` and try to convert `self` to type `T` using a
    /// [`TryConvertMut`] conversion.
    ///
    /// # Errors
    ///
    /// If a [`TryConvertMut`] conversion fails, then an error is returned.
    fn try_into_mut<T>(self, interp: &mut Self::Artichoke) -> Result<T, Self::Error>
    where
        Self: Sized,
        Self::Artichoke: TryConvertMut<Self, T, Error = Self::Error>,
    {
        interp.try_convert_mut(self)
    }

    /// Call `#freeze` on this [`Value`].
    ///
    /// # Errors
    ///
    /// If an exception is raised on the interpreter, then an error is returned.
    fn freeze(&mut self, interp: &mut Self::Artichoke) -> Result<(), Self::Error>;

    /// Call `#frozen?` on this [`Value`].
    fn is_frozen(&self, interp: &mut Self::Artichoke) -> bool;

    /// Whether `self` is `nil`
    fn is_nil(&self) -> bool;

    /// Whether `self` responds to a method.
    ///
    /// Equivalent to invoking `#respond_to?` on this [`Value`].
    ///
    /// # Errors
    ///
    /// If an exception is raised on the interpreter, then an error is returned.
    fn respond_to(&self, interp: &mut Self::Artichoke, method: &str) -> Result<bool, Self::Error>;

    /// Call `#inspect` on this [`Value`].
    ///
    /// This function can never fail.
    fn inspect(&self, interp: &mut Self::Artichoke) -> Vec<u8>;

    /// Call `#to_s` on this [`Value`].
    ///
    /// This function can never fail.
    fn to_s(&self, interp: &mut Self::Artichoke) -> Vec<u8>;

    /// Return this values [Rust-mapped type tag](Ruby).
    fn ruby_type(&self) -> Ruby;
}