hexagon 0.1.2

The Hexagon VM
Documentation
use std::cmp::Ordering;
use std::borrow::Cow;
use errors;
use object::Object;
use object_pool::ObjectPool;
use object_info::ObjectHandle;
use opcode::{OpCode, RtOpCode};

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Value {
    Object(usize),
    Null,
    Bool(bool),
    Int(i64),
    Float(f64)
}

impl Value {
    pub fn is_object(&self) -> bool {
        if let Value::Object(_) = *self {
            true
        } else {
            false
        }
    }

    pub fn as_object_id(&self) -> usize {
        if let Value::Object(obj) = *self {
            obj
        } else {
            panic!(errors::VMError::from(errors::RuntimeError::new(
                format!("Not an object: {:?}", self)
            )));
        }
    }

    pub fn to_opcode(&self) -> OpCode {
        match *self {
            Value::Object(id) => OpCode::Rt(RtOpCode::LoadObject(id)),
            Value::Null => OpCode::LoadNull,
            Value::Bool(v) => OpCode::LoadBool(v),
            Value::Int(v) => OpCode::LoadInt(v),
            Value::Float(v) => OpCode::LoadFloat(v)
        }
    }
}

pub struct ValueContext<'a, 'b> {
    pub value: &'a Value,
    pub pool: &'b ObjectPool
}

impl<'a, 'b> ValueContext<'a, 'b> {
    pub fn new(v: &'a Value, pool: &'b ObjectPool) -> ValueContext<'a, 'b> {
        ValueContext {
            value: v,
            pool: pool
        }
    }

    pub fn is_object(&self) -> bool {
        self.value.is_object()
    }

    pub fn as_object_id(&self) -> usize {
        self.value.as_object_id()
    }

    pub fn as_object<'z>(&self) -> ObjectHandle<'z> {
        self.pool.get(self.as_object_id())
    }

    pub fn as_object_direct(&self) -> &'b Object {
        self.pool.get_direct(self.as_object_id())
    }

    pub fn to_i64(&self) -> i64 {
        match *self.value {
            Value::Object(id) => self.pool.get_direct(id).to_i64(),
            Value::Null => 0,
            Value::Bool(v) => if v {
                1
            } else {
                0
            },
            Value::Int(v) => v,
            Value::Float(v) => v as i64
        }
    }

    pub fn to_f64(&self) -> f64 {
        match *self.value {
            Value::Object(id) => self.pool.get_direct(id).to_f64(),
            Value::Null => 0.0,
            Value::Bool(v) => if v {
                1.0
            } else {
                0.0
            },
            Value::Int(v) => v as f64,
            Value::Float(v) => v
        }
    }

    pub fn to_bool(&self) -> bool {
        match *self.value {
            Value::Object(id) => self.pool.get_direct(id).to_bool(),
            Value::Null => false,
            Value::Bool(v) => v,
            Value::Int(v) => if v != 0 {
                true
            } else {
                false
            },
            Value::Float(v) => if v != 0.0 {
                true
            } else {
                false
            }
        }
    }

    pub fn compare(&self, other: &ValueContext) -> Option<Ordering> {
        if let Value::Object(_) = *self.value {
            return self.as_object_direct().compare(other);
        }
        if let Value::Object(_) = *other.value {
            return other.as_object_direct().compare(self);
        }

        match (*self.value, *other.value) {
            (Value::Null, Value::Null) => Some(Ordering::Equal),
            (Value::Bool(a), Value::Bool(b)) => a.partial_cmp(&b),
            (Value::Int(a), Value::Int(b)) => a.partial_cmp(&b),
            (Value::Float(a), Value::Float(b)) => a.partial_cmp(&b),
            (Value::Int(a), Value::Float(b)) => (a as f64).partial_cmp(&b),
            (Value::Float(a), Value::Int(b)) => a.partial_cmp(&(b as f64)),
            _ => None
        }
    }

    pub fn to_str<'z>(&'z self) -> Cow<'z, str> {
        match *self.value {
            Value::Object(_) => Cow::from(self.as_object_direct().to_str()),
            Value::Null => Cow::from("(null)"),
            Value::Bool(v) => Cow::from(if v {
                "true"
            } else {
                "false"
            }),
            Value::Int(v) => Cow::from(format!("{}", v)),
            Value::Float(v) => Cow::from(format!("{}", v))
        }
    }
}