lunar_wave/src/value.rs

105 lines
2.2 KiB
Rust
Raw Normal View History

use std::{
collections::BTreeMap,
rc::Rc,
};
#[derive (Clone, Debug, Hash, PartialEq)]
pub struct BogusClosure {
pub idx: usize,
pub upvalues: Vec <Value>,
}
#[derive (Clone, Debug, PartialEq)]
pub enum Value {
Nil,
Boolean (bool),
Float (f64),
Integer (i64),
String (Rc <String>),
// These are all bogus, I haven't figured out how to implement
// tables and function pointers yet
BogusArg (Rc <Vec <String>>),
BogusClosure (Rc <BogusClosure>),
BogusEnv (Rc <BTreeMap <String, Value>>),
BogusPrint,
}
impl Default for Value {
fn default () -> Self {
Self::Nil
}
}
impl From <String> 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 <i32> for Value {
fn from (x: i32) -> Self {
Self::Integer (i64::try_from (x).unwrap ())
}
}
impl From <f64> for Value {
fn from (x: f64) -> Self {
Self::Float (x)
}
}
impl std::hash::Hash for Value {
fn hash <H: std::hash::Hasher> (&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 <f64> {
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
}
}