use crate::vm::array::DvmArray; use crate::vm::object::DvmObject; use crate::vm::pointer::DvmPointer; use std::cell::RefCell; use std::fmt::{Display, Formatter}; use std::rc::Rc; #[derive(Debug, PartialEq, Clone)] pub enum DvmValue { // Primitives Byte(u8), Int(i32), Long(i64), Double(f64), USize(usize), Boolean(bool), // Object Object(Rc>), // Array Array(Rc>), // Pointer to constant u8 ConstantPointer(DvmPointer), // Null Empty, } impl Default for DvmValue { fn default() -> Self { DvmValue::Empty } } impl Display for DvmValue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { DvmValue::Byte(b) => write!(f, "Byte({:x})", b), DvmValue::Int(i) => write!(f, "Int({})", i), DvmValue::Long(i) => write!(f, "Long({})", i), DvmValue::Double(i) => write!(f, "Double({})", i), DvmValue::USize(u) => write!(f, "USize({})", u), DvmValue::Boolean(b) => write!(f, "Boolean({})", b), DvmValue::Object(o) => write!(f, "Object({:p})", &o), DvmValue::Array(a) => write!(f, "Array({:p})", &a), DvmValue::ConstantPointer(p) => write!(f, "ConstantPointer({})", p), DvmValue::Empty => write!(f, "Empty"), } } } impl DvmValue { pub fn from_object(object: DvmObject) -> Self { DvmValue::Object(Rc::new(RefCell::new(object))) } pub fn expect_byte(&self) -> u8 { if let DvmValue::Byte(b) = self { *b } else { panic!("Expected DvmValue::Byte, but found DvmValue::{:?}", self); } } pub fn expect_int(&self) -> i32 { if let DvmValue::Int(i) = self { *i } else { panic!("Expected DvmValue::Int, but found DvmValue::{:?}", self); } } pub fn expect_long(&self) -> i64 { if let DvmValue::Long(l) = self { *l } else { panic!("Expected DvmValue::Long, but found DvmValue::{:?}", self); } } pub fn is_long(&self) -> bool { match self { DvmValue::Long(_) => true, _ => false, } } pub fn expect_double(&self) -> f64 { if let DvmValue::Double(d) = self { *d } else { panic!("Expected DvmValue::Double, but found DvmValue::{:?}", self); } } pub fn expect_object(&self) -> Rc> { if let DvmValue::Object(o) = self { o.clone() } else { panic!("Expected DvmValue::Object, but found DvmValue::{:?}", self); } } pub fn map_object( &self, mapper: impl FnOnce(Rc>) -> T, on_non_object: impl FnOnce(&Self) -> T, ) -> T { if let DvmValue::Object(o) = self { mapper(o.clone()) } else { on_non_object(self) } } pub fn is_object(&self) -> bool { match self { DvmValue::Object(_) => true, _ => false, } } pub fn expect_array(&self) -> Rc> { if let DvmValue::Array(a) = self { a.clone() } else { panic!("Expected DvmValue::Array, but found DvmValue::{:?}", self); } } pub fn is_array(&self) -> bool { match self { DvmValue::Array(_) => true, _ => false, } } pub fn map_array( &self, mapper: impl FnOnce(Rc>) -> T, on_non_array: impl FnOnce(&Self) -> T, ) -> T { if let DvmValue::Array(a) = self { mapper(a.clone()) } else { on_non_array(self) } } pub fn expect_usize(&self) -> usize { if let DvmValue::USize(u) = self { *u } else { panic!("Expected DvmValue::USize, but found DvmValue::{:?}", self); } } pub fn is_usize(&self) -> bool { match self { DvmValue::USize(_) => true, _ => false, } } pub fn as_usize(&self) -> Option { match self { DvmValue::Byte(b) => Some(*b as usize), DvmValue::Int(i) => Some(*i as usize), DvmValue::Long(l) => Some(*l as usize), DvmValue::Double(d) => Some(*d as usize), DvmValue::USize(u) => Some(*u), _ => None, } } pub fn expect_boolean(&self) -> bool { if let DvmValue::Boolean(b) = self { *b } else { panic!("Expected DvmValue::Boolean, but found DvmValue::{:?}", self); } } pub fn expect_constant_pointer(&self) -> DvmPointer { if let DvmValue::ConstantPointer(ptr) = self { ptr.clone() } else { panic!( "Expected DvmValue::ConstantPointer, but found DvmValue::{:?}", self ); } } }