use crate::js::function::{Function, NativeFunction, NativeFunctionData};
use crate::js::object::{ObjectData, Property, INSTANCE_PROTOTYPE, PROTOTYPE};
use gc::{Gc, GcCell};
use serde_json::map::Map;
use serde_json::Number as JSONNumber;
use serde_json::Value as JSONValue;
use std::collections::HashMap;
use std::f64::NAN;
use std::fmt;
use std::fmt::Display;
use std::iter::FromIterator;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub};
use std::str::FromStr;
#[must_use]
pub type ResultValue = Result<Value, Value>;
pub type Value = Gc<ValueData>;
#[derive(Trace, Finalize, Debug, Clone)]
pub enum ValueData {
Null,
Undefined,
Boolean(bool),
String(String),
Number(f64),
Integer(i32),
Object(GcCell<ObjectData>, GcCell<ObjectData>),
Function(GcCell<Function>),
}
impl ValueData {
pub fn new_obj(global: Option<&Value>) -> Value {
let mut obj: ObjectData = HashMap::new();
let private_obj: ObjectData = HashMap::new();
if global.is_some() {
let obj_proto = global
.unwrap()
.get_field_slice("Object")
.get_field_slice(PROTOTYPE);
obj.insert(INSTANCE_PROTOTYPE.to_string(), Property::new(obj_proto));
}
Gc::new(ValueData::Object(
GcCell::new(obj),
GcCell::new(private_obj),
))
}
pub fn new_obj_from_prototype(proto: Value) -> Value {
let mut obj: ObjectData = HashMap::new();
let private_obj: ObjectData = HashMap::new();
obj.insert(INSTANCE_PROTOTYPE.to_string(), Property::new(proto));
Gc::new(ValueData::Object(
GcCell::new(obj),
GcCell::new(private_obj),
))
}
pub fn is_extensible(&self) -> bool {
true
}
pub fn is_object(&self) -> bool {
match *self {
ValueData::Object(_, _) => true,
_ => false,
}
}
pub fn is_function(&self) -> bool {
match *self {
ValueData::Function(_) => true,
_ => false,
}
}
pub fn is_undefined(&self) -> bool {
match *self {
ValueData::Undefined => true,
_ => false,
}
}
pub fn is_null(&self) -> bool {
match *self {
ValueData::Null => true,
_ => false,
}
}
pub fn is_null_or_undefined(&self) -> bool {
match *self {
ValueData::Null | ValueData::Undefined => true,
_ => false,
}
}
pub fn is_double(&self) -> bool {
match *self {
ValueData::Number(_) => true,
_ => false,
}
}
pub fn is_string(&self) -> bool {
match *self {
ValueData::String(_) => true,
_ => false,
}
}
pub fn is_true(&self) -> bool {
match *self {
ValueData::Object(_, _) => true,
ValueData::String(ref s) if !s.is_empty() => true,
ValueData::Number(n) if n >= 1.0 && n % 1.0 == 0.0 => true,
ValueData::Integer(n) if n > 1 => true,
ValueData::Boolean(v) => v,
_ => false,
}
}
pub fn to_num(&self) -> f64 {
match *self {
ValueData::Object(_, _) | ValueData::Undefined | ValueData::Function(_) => NAN,
ValueData::String(ref str) => match FromStr::from_str(str) {
Ok(num) => num,
Err(_) => NAN,
},
ValueData::Number(num) => num,
ValueData::Boolean(true) => 1.0,
ValueData::Boolean(false) | ValueData::Null => 0.0,
ValueData::Integer(num) => num as f64,
}
}
pub fn to_int(&self) -> i32 {
match *self {
ValueData::Object(_, _)
| ValueData::Undefined
| ValueData::Null
| ValueData::Boolean(false)
| ValueData::Function(_) => 0,
ValueData::String(ref str) => match FromStr::from_str(str) {
Ok(num) => num,
Err(_) => 0,
},
ValueData::Number(num) => num as i32,
ValueData::Boolean(true) => 1,
ValueData::Integer(num) => num,
}
}
pub fn remove_prop(&self, field: &String) {
match *self {
ValueData::Object(ref obj, _) => obj.borrow_mut().deref_mut().remove(field),
ValueData::Function(ref func) => match func.borrow_mut().deref_mut() {
Function::NativeFunc(ref mut func) => func.object.remove(field),
Function::RegularFunc(ref mut func) => func.object.remove(field),
},
_ => None,
};
}
pub fn get_prop(&self, field: String) -> Option<Property> {
if self.is_string() && field == "length" {
if let ValueData::String(ref s) = *self {
return Some(Property::new(to_value(s.len() as i32)));
}
}
let obj: ObjectData = match *self {
ValueData::Object(ref obj, _) => {
let hash = obj.clone();
hash.into_inner()
}
ValueData::Function(ref func) => match func.clone().into_inner() {
Function::NativeFunc(ref func) => func.object.clone(),
Function::RegularFunc(ref func) => func.object.clone(),
},
_ => return None,
};
match obj.get(&field) {
Some(val) => Some(val.clone()),
None => match obj.get(&INSTANCE_PROTOTYPE.to_string()) {
Some(prop) => prop.value.get_prop(field),
None => None,
},
}
}
pub fn update_prop(
&self,
field: String,
value: Option<Value>,
enumerable: Option<bool>,
writable: Option<bool>,
configurable: Option<bool>,
) {
let obj: Option<ObjectData> = match self {
ValueData::Object(ref obj, _) => Some(obj.borrow_mut().deref_mut().clone()),
ValueData::Function(ref func) => match func.borrow_mut().deref_mut() {
Function::NativeFunc(ref mut func) => Some(func.object.clone()),
Function::RegularFunc(ref mut func) => Some(func.object.clone()),
},
_ => None,
};
if obj.is_none() {
return ();
}
let mut hashmap = obj.unwrap();
match hashmap.get_mut(&field) {
Some(ref mut prop) => {
prop.value = value.unwrap_or(prop.value.clone());
prop.enumerable = enumerable.unwrap_or(prop.enumerable);
prop.writable = writable.unwrap_or(prop.writable);
prop.configurable = configurable.unwrap_or(prop.configurable);
}
None => (),
}
}
pub fn get_private_prop(&self, field: String) -> Option<Property> {
let obj: ObjectData = match *self {
ValueData::Object(_, ref obj) => {
let hash = obj.clone();
hash.into_inner()
}
_ => return None,
};
match obj.get(&field) {
Some(val) => Some(val.clone()),
None => match obj.get(&INSTANCE_PROTOTYPE.to_string()) {
Some(prop) => prop.value.get_prop(field),
None => None,
},
}
}
pub fn get_private_field(&self, field: String) -> Value {
match self.get_private_prop(field) {
Some(prop) => prop.value.clone(),
None => Gc::new(ValueData::Undefined),
}
}
pub fn get_field(&self, field: String) -> Value {
match self.get_prop(field) {
Some(prop) => {
let prop_getter = match *prop.get {
ValueData::Function(ref v) => match *v.borrow() {
Function::NativeFunc(ref ntv) => {
let func = ntv.data;
Some(
func(
Gc::new(self.clone()),
Gc::new(self.clone()),
vec![Gc::new(self.clone())],
)
.unwrap(),
)
}
_ => None,
},
_ => None,
};
match prop_getter {
Some(val) => val,
None => prop.value.clone(),
}
}
None => Gc::new(ValueData::Undefined),
}
}
pub fn has_field(&self, field: String) -> bool {
match self.get_prop(field) {
Some(_) => true,
None => false,
}
}
pub fn get_field_slice<'a>(&self, field: &'a str) -> Value {
self.get_field(field.to_string())
}
pub fn set_field(&self, field: String, val: Value) -> Value {
match *self {
ValueData::Object(ref obj, _) => {
obj.borrow_mut()
.insert(field.clone(), Property::new(val.clone()));
}
ValueData::Function(ref func) => {
match *func.borrow_mut().deref_mut() {
Function::NativeFunc(ref mut f) => {
f.object.insert(field.clone(), Property::new(val.clone()))
}
Function::RegularFunc(ref mut f) => {
f.object.insert(field.clone(), Property::new(val.clone()))
}
};
}
_ => (),
}
val
}
pub fn set_field_slice<'a>(&self, field: &'a str, val: Value) -> Value {
self.set_field(field.to_string(), val)
}
pub fn set_private_field(&self, field: String, val: Value) -> Value {
match *self {
ValueData::Object(_, ref obj) => {
obj.borrow_mut()
.insert(field.clone(), Property::new(val.clone()));
}
_ => (),
}
val
}
pub fn set_private_field_slice<'a>(&self, field: &'a str, val: Value) -> Value {
self.set_private_field(field.to_string(), val)
}
pub fn set_prop(&self, field: String, prop: Property) -> Property {
match *self {
ValueData::Object(ref obj, _) => {
obj.borrow_mut().insert(field.clone(), prop.clone());
}
ValueData::Function(ref func) => {
match *func.borrow_mut().deref_mut() {
Function::NativeFunc(ref mut f) => f.object.insert(field.clone(), prop.clone()),
Function::RegularFunc(ref mut f) => {
f.object.insert(field.clone(), prop.clone())
}
};
}
_ => (),
}
prop
}
pub fn set_prop_slice<'t>(&self, field: &'t str, prop: Property) -> Property {
self.set_prop(field.to_string(), prop)
}
pub fn from_json(json: JSONValue) -> ValueData {
match json {
JSONValue::Number(v) => ValueData::Number(v.as_f64().unwrap()),
JSONValue::String(v) => ValueData::String(v),
JSONValue::Bool(v) => ValueData::Boolean(v),
JSONValue::Array(vs) => {
let mut i = 0;
let private_data: ObjectData = HashMap::new();
let mut data: ObjectData = FromIterator::from_iter(vs.iter().map(|json| {
i += 1;
(
(i - 1).to_string().to_string(),
Property::new(to_value(json.clone())),
)
}));
data.insert(
"length".to_string(),
Property::new(to_value(vs.len() as i32)),
);
ValueData::Object(GcCell::new(data), GcCell::new(private_data))
}
JSONValue::Object(obj) => {
let private_data: ObjectData = HashMap::new();
let data: ObjectData = FromIterator::from_iter(
obj.iter()
.map(|(key, json)| (key.clone(), Property::new(to_value(json.clone())))),
);
ValueData::Object(GcCell::new(data), GcCell::new(private_data))
}
JSONValue::Null => ValueData::Null,
}
}
pub fn to_json(&self) -> JSONValue {
match *self {
ValueData::Null | ValueData::Undefined => JSONValue::Null,
ValueData::Boolean(b) => JSONValue::Bool(b),
ValueData::Object(ref obj, _) => {
let mut nobj = Map::new();
for (k, v) in obj.borrow().iter() {
if k != INSTANCE_PROTOTYPE {
nobj.insert(k.clone(), v.value.to_json());
}
}
JSONValue::Object(nobj)
}
ValueData::String(ref str) => JSONValue::String(str.clone()),
ValueData::Number(num) => JSONValue::Number(JSONNumber::from_f64(num).unwrap()),
ValueData::Integer(val) => JSONValue::Number(JSONNumber::from(val)),
ValueData::Function(_) => JSONValue::Null,
}
}
pub fn get_type(&self) -> &'static str {
match *self {
ValueData::Number(_) | ValueData::Integer(_) => "number",
ValueData::String(_) => "string",
ValueData::Boolean(_) => "boolean",
ValueData::Null => "null",
ValueData::Undefined => "undefined",
_ => "object",
}
}
}
impl Display for ValueData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ValueData::Null => write!(f, "null"),
ValueData::Undefined => write!(f, "undefined"),
ValueData::Boolean(v) => write!(f, "{}", v),
ValueData::String(ref v) => write!(f, "{}", v),
ValueData::Number(v) => write!(
f,
"{}",
match v {
_ if v.is_nan() => "NaN".to_string(),
_ if v.is_infinite() && v.is_sign_negative() => "-Infinity".to_string(),
_ if v.is_infinite() => "Infinity".to_string(),
_ => v.to_string(),
}
),
ValueData::Object(ref v, ref p) => {
write!(f, "{}", "{")?;
match v.borrow().iter().last() {
Some((last_key, _)) => {
for (key, val) in v.borrow().iter() {
r#try!(write!(f, "{}: {}", key, val.value.clone()));
if key != last_key {
r#try!(write!(f, "{}", ", "));
}
}
}
None => (),
};
match p.borrow().iter().last() {
Some((last_key, _)) => {
for (key, val) in p.borrow().iter() {
r#try!(write!(f, "(Private) {}: {}", key, val.value.clone()));
if key != last_key {
r#try!(write!(f, "{}", ", "));
}
}
}
None => (),
};
write!(f, "{}", "}")
}
ValueData::Integer(v) => write!(f, "{}", v),
ValueData::Function(ref v) => match *v.borrow() {
Function::NativeFunc(_) => write!(f, "{}", "function() { [native code] }"),
Function::RegularFunc(ref rf) => {
write!(f, "function({}){}", rf.args.join(", "), rf.expr)
}
},
}
}
}
impl PartialEq for ValueData {
fn eq(&self, other: &ValueData) -> bool {
match (self.clone(), other.clone()) {
_ if self.is_null_or_undefined() && other.is_null_or_undefined() => true,
(ValueData::String(_), _) | (_, ValueData::String(_)) => {
self.to_string() == other.to_string()
}
(ValueData::Boolean(a), ValueData::Boolean(b)) if a == b => true,
(ValueData::Number(a), ValueData::Number(b))
if a == b && !a.is_nan() && !b.is_nan() =>
{
true
}
(ValueData::Number(a), _) if a == other.to_num() => true,
(_, ValueData::Number(a)) if a == self.to_num() => true,
(ValueData::Integer(a), ValueData::Integer(b)) if a == b => true,
_ => false,
}
}
}
impl Add for ValueData {
type Output = ValueData;
fn add(self, other: ValueData) -> ValueData {
return match (self.clone(), other.clone()) {
(ValueData::String(ref s), ref other) | (ref other, ValueData::String(ref s)) => {
ValueData::String(s.clone() + &other.to_string())
}
(_, _) => ValueData::Number(self.to_num() + other.to_num()),
};
}
}
impl Sub for ValueData {
type Output = ValueData;
fn sub(self, other: ValueData) -> ValueData {
ValueData::Number(self.to_num() - other.to_num())
}
}
impl Mul for ValueData {
type Output = ValueData;
fn mul(self, other: ValueData) -> ValueData {
ValueData::Number(self.to_num() * other.to_num())
}
}
impl Div for ValueData {
type Output = ValueData;
fn div(self, other: ValueData) -> ValueData {
ValueData::Number(self.to_num() / other.to_num())
}
}
impl Rem for ValueData {
type Output = ValueData;
fn rem(self, other: ValueData) -> ValueData {
ValueData::Number(self.to_num() % other.to_num())
}
}
impl BitAnd for ValueData {
type Output = ValueData;
fn bitand(self, other: ValueData) -> ValueData {
ValueData::Integer(self.to_int() & other.to_int())
}
}
impl BitOr for ValueData {
type Output = ValueData;
fn bitor(self, other: ValueData) -> ValueData {
ValueData::Integer(self.to_int() | other.to_int())
}
}
impl BitXor for ValueData {
type Output = ValueData;
fn bitxor(self, other: ValueData) -> ValueData {
ValueData::Integer(self.to_int() ^ other.to_int())
}
}
impl Shl for ValueData {
type Output = ValueData;
fn shl(self, other: ValueData) -> ValueData {
ValueData::Integer(self.to_int() << other.to_int())
}
}
impl Shr for ValueData {
type Output = ValueData;
fn shr(self, other: ValueData) -> ValueData {
ValueData::Integer(self.to_int() >> other.to_int())
}
}
impl Not for ValueData {
type Output = ValueData;
fn not(self) -> ValueData {
ValueData::Boolean(!self.is_true())
}
}
pub trait ToValue {
fn to_value(&self) -> Value;
}
pub trait FromValue {
fn from_value(value: Value) -> Result<Self, &'static str>
where
Self: Sized;
}
impl ToValue for String {
fn to_value(&self) -> Value {
Gc::new(ValueData::String(self.clone()))
}
}
impl FromValue for String {
fn from_value(v: Value) -> Result<String, &'static str> {
Ok(v.to_string())
}
}
impl<'s> ToValue for &'s str {
fn to_value(&self) -> Value {
Gc::new(ValueData::String(String::from_str(*self).unwrap()))
}
}
impl ToValue for char {
fn to_value(&self) -> Value {
Gc::new(ValueData::String(self.to_string()))
}
}
impl FromValue for char {
fn from_value(v: Value) -> Result<char, &'static str> {
Ok(v.to_string().chars().next().unwrap())
}
}
impl ToValue for f64 {
fn to_value(&self) -> Value {
Gc::new(ValueData::Number(*self))
}
}
impl FromValue for f64 {
fn from_value(v: Value) -> Result<f64, &'static str> {
Ok(v.to_num())
}
}
impl ToValue for i32 {
fn to_value(&self) -> Value {
Gc::new(ValueData::Integer(*self))
}
}
impl FromValue for i32 {
fn from_value(v: Value) -> Result<i32, &'static str> {
Ok(v.to_int())
}
}
impl ToValue for usize {
fn to_value(&self) -> Value {
Gc::new(ValueData::Integer(*self as i32))
}
}
impl FromValue for usize {
fn from_value(v: Value) -> Result<usize, &'static str> {
Ok(v.to_int() as usize)
}
}
impl ToValue for bool {
fn to_value(&self) -> Value {
Gc::new(ValueData::Boolean(*self))
}
}
impl FromValue for bool {
fn from_value(v: Value) -> Result<bool, &'static str> {
Ok(v.is_true())
}
}
impl<'s, T: ToValue> ToValue for &'s [T] {
fn to_value(&self) -> Value {
let mut arr = HashMap::new();
let mut i = 0;
for item in self.iter() {
arr.insert(i.to_string(), Property::new(item.to_value()));
i += 1;
}
to_value(arr)
}
}
impl<T: ToValue> ToValue for Vec<T> {
fn to_value(&self) -> Value {
let mut arr = HashMap::new();
let mut i = 0;
for item in self.iter() {
arr.insert(i.to_string(), Property::new(item.to_value()));
i += 1;
}
to_value(arr)
}
}
impl<T: FromValue> FromValue for Vec<T> {
fn from_value(v: Value) -> Result<Vec<T>, &'static str> {
let len = v.get_field_slice("length").to_int();
let mut vec = Vec::with_capacity(len as usize);
for i in 0..len {
vec.push(r#try!(from_value(v.get_field(i.to_string()))))
}
Ok(vec)
}
}
impl ToValue for ObjectData {
fn to_value(&self) -> Value {
let private_obj: ObjectData = HashMap::new();
Gc::new(ValueData::Object(
GcCell::new(self.clone()),
GcCell::new(private_obj),
))
}
}
impl FromValue for ObjectData {
fn from_value(v: Value) -> Result<ObjectData, &'static str> {
match *v {
ValueData::Object(ref obj, _) => Ok(obj.clone().into_inner()),
ValueData::Function(ref func) => Ok(match *func.borrow().deref() {
Function::NativeFunc(ref data) => data.object.clone(),
Function::RegularFunc(ref data) => data.object.clone(),
}),
_ => Err("Value is not a valid object"),
}
}
}
impl ToValue for JSONValue {
fn to_value(&self) -> Value {
Gc::new(ValueData::from_json(self.clone()))
}
}
impl FromValue for JSONValue {
fn from_value(v: Value) -> Result<JSONValue, &'static str> {
Ok(v.to_json())
}
}
impl ToValue for () {
fn to_value(&self) -> Value {
Gc::new(ValueData::Null)
}
}
impl FromValue for () {
fn from_value(_: Value) -> Result<(), &'static str> {
Ok(())
}
}
impl<T: ToValue> ToValue for Option<T> {
fn to_value(&self) -> Value {
match *self {
Some(ref v) => v.to_value(),
None => Gc::new(ValueData::Null),
}
}
}
impl<T: FromValue> FromValue for Option<T> {
fn from_value(value: Value) -> Result<Option<T>, &'static str> {
Ok(if value.is_null_or_undefined() {
None
} else {
Some(r#try!(FromValue::from_value(value)))
})
}
}
impl ToValue for NativeFunctionData {
fn to_value(&self) -> Value {
Gc::new(ValueData::Function(GcCell::new(Function::NativeFunc(
NativeFunction::new(*self),
))))
}
}
impl FromValue for NativeFunctionData {
fn from_value(v: Value) -> Result<NativeFunctionData, &'static str> {
match *v {
ValueData::Function(ref func) => match *func.borrow() {
Function::NativeFunc(ref data) => Ok(data.data),
_ => Err("Value is not a native function"),
},
_ => Err("Value is not a function"),
}
}
}
pub fn from_value<A: FromValue>(v: Value) -> Result<A, &'static str> {
FromValue::from_value(v)
}
pub fn to_value<A: ToValue>(v: A) -> Value {
v.to_value()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_is_object() {
let val = ValueData::new_obj(None);
assert_eq!(val.is_object(), true);
}
#[test]
fn check_string_to_value() {
let s = String::from("Hello");
let v = s.to_value();
assert_eq!(v.is_string(), true);
assert_eq!(v.is_null(), false);
}
#[test]
fn check_undefined() {
let u = ValueData::Undefined;
assert_eq!(u.get_type(), "undefined");
assert_eq!(u.to_string(), "undefined");
}
#[test]
fn check_get_set_field() {
let obj = ValueData::new_obj(None);
let s = String::from("bar").to_value();
obj.set_field_slice("foo", s);
assert_eq!(obj.get_field_slice("foo").to_string(), "bar");
}
}