use std::{ collections::BTreeMap, rc::Rc, }; #[derive (Clone, Debug, Hash, PartialEq)] pub struct BogusClosure { pub idx: usize, pub upvalues: Vec , } #[derive (Clone, Debug, PartialEq)] pub enum Value { Nil, Boolean (bool), Float (f64), Integer (i64), String (Rc ), // These are all bogus, I haven't figured out how to implement // tables and function pointers yet BogusArg (Rc >), BogusClosure (Rc ), BogusEnv (Rc >), BogusPrint, } impl Default for Value { fn default () -> Self { Self::Nil } } impl From for Value { fn from (x: String) -> Self { Self::String (x.into ()) } } impl From <&str> for Value { fn from (x: &str) -> Self { Self::from (String::from (x)) } } impl From for Value { fn from (x: i32) -> Self { Self::Integer (i64::try_from (x).unwrap ()) } } impl From for Value { fn from (x: f64) -> Self { Self::Float (x) } } impl std::hash::Hash for Value { fn hash (&self, state: &mut H) { // Per https://doc.rust-lang.org/std/hash/trait.Hash.html#prefix-collisions [0xff].hash (state); match self { // TODO: Weaken to a Lua error Self::Nil => panic! ("can't hash a nil value"), Self::Boolean (x) => x.hash (state), Self::Float (x) => x.to_ne_bytes ().hash (state), Self::Integer (x) => x.hash (state), Self::String (x) => x.as_ptr ().hash (state), Self::BogusArg (_) => panic! ("can't hash Bogus values"), Self::BogusClosure (_) => panic! ("can't hash Bogus values"), Self::BogusEnv (_) => panic! ("can't hash Bogus values"), Self::BogusPrint => panic! ("can't hash Bogus values"), } } } impl Value { pub fn as_float (&self) -> Option { match self { Self::Float (x) => Some (*x), // FloatToInt isn't stable yet, so only ints in i32 space can practically be used for now Self::Integer (x) => f64::try_from (i32::try_from (*x).ok ()?).ok (), _ => None, } } pub fn is_truthy (&self) -> bool { // And this is something Lua does better than JS and Python. match self { Value::Nil => false, Value::Boolean (false) => false, _ => true, } } pub fn take (&mut self) -> Self { let mut x = Value::Nil; std::mem::swap (self, &mut x); x } }