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_convert_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_convert_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;
}