use std::fmt;
use crate::sys;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Rust {
Bool,
Bytes,
Float,
Map,
Object,
SignedInt,
String,
UnsignedInt,
Vec,
}
impl fmt::Display for Rust {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "rust ")?;
match self {
Rust::Bool => write!(f, "bool"),
Rust::Bytes => write!(f, "&[u8]"),
Rust::Float => write!(f, "f64"),
Rust::Map => write!(f, "HashMap"),
Rust::Object => write!(f, "struct"),
Rust::SignedInt => write!(f, "i64"),
Rust::String => write!(f, "String"),
Rust::Vec => write!(f, "Vec"),
Rust::UnsignedInt => write!(f, "usize"),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Ruby {
Array,
Bool,
Class,
CPointer,
Data,
Exception,
Fiber,
Fixnum,
Float,
Hash,
InlineStruct,
Module,
Nil,
Object,
Proc,
Range,
SingletonClass,
String,
Symbol,
Unreachable,
}
impl Ruby {
pub fn class_name(&self) -> String {
match self {
Ruby::Array => "Array",
Ruby::Bool => "Boolean",
Ruby::Class => "Class",
Ruby::CPointer => "C Pointer",
Ruby::Data => "Rust-backed Ruby instance",
Ruby::Exception => "Exception",
Ruby::Fiber => "Fiber",
Ruby::Fixnum => "Fixnum",
Ruby::Float => "Float",
Ruby::Hash => "Hash",
Ruby::InlineStruct => "Inline Struct",
Ruby::Module => "Module",
Ruby::Nil => "NilClass",
Ruby::Object => "Object",
Ruby::Proc => "Proc",
Ruby::Range => "Range",
Ruby::SingletonClass => "Singleton (anonymous) class",
Ruby::String => "String",
Ruby::Symbol => "Symbol",
Ruby::Unreachable => "mruby internal and unreachable",
}
.to_owned()
}
}
impl fmt::Display for Ruby {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ruby {}", self.class_name())
}
}
impl From<sys::mrb_value> for Ruby {
#[allow(non_upper_case_globals)]
fn from(value: sys::mrb_value) -> Self {
if unsafe { sys::mrb_sys_value_is_nil(value) } {
return Ruby::Nil;
}
#[allow(clippy::match_same_arms)]
match value.tt {
sys::mrb_vtype::MRB_TT_FALSE => Ruby::Bool,
sys::mrb_vtype::MRB_TT_FREE => Ruby::Unreachable,
sys::mrb_vtype::MRB_TT_TRUE => Ruby::Bool,
sys::mrb_vtype::MRB_TT_FIXNUM => Ruby::Fixnum,
sys::mrb_vtype::MRB_TT_SYMBOL => Ruby::Symbol,
sys::mrb_vtype::MRB_TT_UNDEF => Ruby::Unreachable,
sys::mrb_vtype::MRB_TT_FLOAT => Ruby::Float,
sys::mrb_vtype::MRB_TT_CPTR => Ruby::CPointer,
sys::mrb_vtype::MRB_TT_OBJECT => Ruby::Object,
sys::mrb_vtype::MRB_TT_CLASS => Ruby::Class,
sys::mrb_vtype::MRB_TT_MODULE => Ruby::Module,
sys::mrb_vtype::MRB_TT_ICLASS => Ruby::Unreachable,
sys::mrb_vtype::MRB_TT_SCLASS => Ruby::SingletonClass,
sys::mrb_vtype::MRB_TT_PROC => Ruby::Proc,
sys::mrb_vtype::MRB_TT_ARRAY => Ruby::Array,
sys::mrb_vtype::MRB_TT_HASH => Ruby::Hash,
sys::mrb_vtype::MRB_TT_STRING => Ruby::String,
sys::mrb_vtype::MRB_TT_RANGE => Ruby::Range,
sys::mrb_vtype::MRB_TT_EXCEPTION => Ruby::Exception,
sys::mrb_vtype::MRB_TT_FILE => unimplemented!("mruby type file"),
sys::mrb_vtype::MRB_TT_ENV => unimplemented!("mruby type env"),
sys::mrb_vtype::MRB_TT_DATA => Ruby::Data,
sys::mrb_vtype::MRB_TT_FIBER => Ruby::Fiber,
sys::mrb_vtype::MRB_TT_ISTRUCT => Ruby::InlineStruct,
sys::mrb_vtype::MRB_TT_BREAK => Ruby::Unreachable,
sys::mrb_vtype::MRB_TT_MAXDEFINE => Ruby::Unreachable,
}
}
}
#[cfg(test)]
mod tests {
use std::ffi::CString;
use crate::sys;
use crate::value::types::*;
#[test]
fn nil_type() {
unsafe {
let value = sys::mrb_sys_nil_value();
assert_eq!(Ruby::from(value), Ruby::Nil);
}
}
#[test]
fn bool_type() {
unsafe {
let value = sys::mrb_sys_false_value();
assert_eq!(Ruby::from(value), Ruby::Bool);
let value = sys::mrb_sys_true_value();
assert_eq!(Ruby::from(value), Ruby::Bool);
}
}
#[test]
fn fixnum_type() {
unsafe {
let value = sys::mrb_sys_fixnum_value(17);
assert_eq!(Ruby::from(value), Ruby::Fixnum);
}
}
#[test]
fn string_type() {
unsafe {
let mrb = sys::mrb_open();
let literal = "dinner plate";
let cstr = CString::new(literal).unwrap();
let value = sys::mrb_str_new_cstr(mrb, cstr.as_ptr());
assert_eq!(Ruby::from(value), Ruby::String);
sys::mrb_close(mrb);
}
}
}