artichoke_backend/
debug.rs

1use std::ffi::CStr;
2
3use artichoke_core::debug::Debug;
4use artichoke_core::value::Value as _;
5
6use crate::Artichoke;
7use crate::sys;
8use crate::types::Ruby;
9use crate::value::Value;
10
11impl Debug for Artichoke {
12    type Value = Value;
13
14    fn inspect_type_name_for_value(&mut self, value: Self::Value) -> &str {
15        match value.try_convert_into(self) {
16            Ok(Some(true)) => "true",
17            Ok(Some(false)) => "false",
18            Ok(None) => "nil",
19            Err(_) if matches!(value.ruby_type(), Ruby::Data | Ruby::Object) => self.class_name_for_value(value),
20            Err(_) => value.ruby_type().class_name(),
21        }
22    }
23
24    fn class_name_for_value(&mut self, value: Self::Value) -> &str {
25        // SAFETY: `mrb_obj_classname` requires an initialized mruby interpreter
26        // which is guaranteed by the `Artichoke` type.
27        let class = unsafe { self.with_ffi_boundary(|mrb| sys::mrb_obj_classname(mrb, value.inner())) };
28        let Ok(class) = class else {
29            return "";
30        };
31        let class = unsafe { CStr::from_ptr(class) };
32        class.to_str().unwrap_or_default()
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use crate::test::prelude::*;
39
40    #[test]
41    fn debug_true_value_as_classlike() {
42        let mut interp = interpreter();
43        let value = interp.convert(true);
44        assert_eq!(interp.inspect_type_name_for_value(value), "true");
45    }
46
47    #[test]
48    fn debug_false_value_as_classlike() {
49        let mut interp = interpreter();
50        let value = interp.convert(false);
51        assert_eq!(interp.inspect_type_name_for_value(value), "false");
52    }
53
54    #[test]
55    fn debug_nil_value_as_classlike() {
56        let mut interp = interpreter();
57        let value = interp.convert(None::<Value>);
58        assert_eq!(interp.inspect_type_name_for_value(value), "nil");
59    }
60
61    #[test]
62    fn debug_fixnum_value_as_classlike() {
63        let mut interp = interpreter();
64        let value = interp.convert(1_i64);
65        assert_eq!(interp.inspect_type_name_for_value(value), "Integer");
66    }
67
68    #[test]
69    fn debug_hash_value_as_classlike() {
70        let mut interp = interpreter();
71        let value = interp.try_convert_mut(vec![(b"foo".to_vec(), vec![1, 2, 3])]).unwrap();
72        assert_eq!(interp.inspect_type_name_for_value(value), "Hash");
73    }
74
75    #[test]
76    fn debug_array_value_as_classlike() {
77        let mut interp = interpreter();
78        let value = interp.try_convert_mut(vec![1_i64]).unwrap();
79        assert_eq!(interp.inspect_type_name_for_value(value), "Array");
80    }
81}