magnus/
r_object.rs

1use std::fmt;
2
3use rb_sys::ruby_value_type;
4
5use crate::{
6    error::Error,
7    into_value::IntoValue,
8    object::Object,
9    try_convert::TryConvert,
10    value::{
11        private::{self, ReprValue as _},
12        NonZeroValue, ReprValue, Value,
13    },
14    Ruby,
15};
16
17/// A Value pointer to a RObject struct, Ruby's internal representation of
18/// generic objects, not covered by the other R* types.
19///
20/// See the [`ReprValue`] and [`Object`] traits for additional methods
21/// available on this type.
22#[derive(Clone, Copy)]
23#[repr(transparent)]
24pub struct RObject(NonZeroValue);
25
26impl RObject {
27    /// Return `Some(RObject)` if `val` is a `RObject`, `None` otherwise.
28    ///
29    /// # Examples
30    ///
31    /// ```
32    /// use magnus::{eval, RObject};
33    /// # let _cleanup = unsafe { magnus::embed::init() };
34    ///
35    /// assert!(RObject::from_value(eval("Object.new").unwrap()).is_some());
36    ///
37    /// // many built-in types have specialised implementations and are not
38    /// // RObjects
39    /// assert!(RObject::from_value(eval(r#""example""#).unwrap()).is_none());
40    /// assert!(RObject::from_value(eval("1").unwrap()).is_none());
41    /// assert!(RObject::from_value(eval("[]").unwrap()).is_none());
42    /// ```
43    #[inline]
44    pub fn from_value(val: Value) -> Option<Self> {
45        unsafe {
46            (val.rb_type() == ruby_value_type::RUBY_T_OBJECT)
47                .then(|| Self(NonZeroValue::new_unchecked(val)))
48        }
49    }
50}
51
52impl fmt::Display for RObject {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        write!(f, "{}", unsafe { self.to_s_infallible() })
55    }
56}
57
58impl fmt::Debug for RObject {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        write!(f, "{}", self.inspect())
61    }
62}
63
64impl IntoValue for RObject {
65    #[inline]
66    fn into_value_with(self, _: &Ruby) -> Value {
67        self.0.get()
68    }
69}
70
71impl Object for RObject {}
72
73unsafe impl private::ReprValue for RObject {}
74
75impl ReprValue for RObject {}
76
77impl TryConvert for RObject {
78    fn try_convert(val: Value) -> Result<Self, Error> {
79        Self::from_value(val).ok_or_else(|| {
80            Error::new(
81                Ruby::get_with(val).exception_type_error(),
82                format!("no implicit conversion of {} into Object", unsafe {
83                    val.classname()
84                },),
85            )
86        })
87    }
88}