use js_sys::{Array, Map, Set, Uint8Array};
use wasm_bindgen::JsValue;
use crate::{SData, SDataRef, SDoc, SFunc, SNodeRef, SNum, SVal};
impl From<SVal> for JsValue {
fn from(value: SVal) -> Self {
match value {
SVal::Null => Self::null(),
SVal::Blob(blob) => {
let array = Uint8Array::from(blob.as_ref());
Self::from(array)
},
SVal::Bool(val) => Self::from_bool(val),
SVal::String(val) => Self::from_str(&val),
SVal::Number(num) => {
match num {
SNum::I64(val) => Self::from(val as i32),
SNum::F64(val) => Self::from(val),
SNum::Units(val, _) => Self::from(val),
}
},
SVal::FnPtr(dref) => Self::from_str(&dref.id), SVal::Data(dref) => Self::from_str(&dref.id), SVal::Object(nref) => Self::from_str(&nref.id), SVal::Array(vals) => {
let array = Array::new();
for val in vals {
array.push(&JsValue::from(val));
}
Self::from(array)
},
SVal::Tuple(vals) => {
let array = Array::new();
for val in vals {
array.push(&JsValue::from(val));
}
Self::from(array)
},
SVal::Void => Self::undefined(),
SVal::Set(set) => {
let jsset = Set::new(&JsValue::NULL);
for val in set {
jsset.add(&Self::from(val));
}
Self::from(jsset)
},
SVal::Map(map) => {
let jsmap = Map::new();
for (k, v) in map {
jsmap.set(&Self::from(k), &Self::from(v));
}
Self::from(jsmap)
},
SVal::Boxed(val) => Self::from(val.lock().unwrap().clone()),
}
}
}
impl From<(JsValue, &mut SDoc)> for SVal {
fn from((value, doc): (JsValue, &mut SDoc)) -> Self {
if value.is_null() || value.is_undefined() { return Self::Null; }
if let Some(val) = value.as_bool() {
return Self::Bool(val);
}
if let Some(val) = value.as_f64() {
return Self::Number(SNum::F64(val));
}
if let Some(val) = value.as_string() {
let nref = SNodeRef::from(&val);
if nref.exists(&doc.graph) {
return Self::Object(nref);
}
let dref = SDataRef::from(&val);
if dref.exists(&doc.graph) {
if let Some(_func) = SData::get::<SFunc>(&doc.graph, &dref) {
return Self::FnPtr(dref);
}
return Self::Data(dref);
}
return Self::String(val);
}
if value.is_array() {
let mut res = Vec::new();
let array = Array::from(&value);
for val in array {
res.push(Self::from((val, &mut *doc)));
}
return Self::Array(res);
}
let intarray = Uint8Array::from(value);
Self::Blob(intarray.to_vec())
}
}
impl From<(JsValue, &SDoc)> for SVal {
fn from((value, doc): (JsValue, &SDoc)) -> Self {
if value.is_null() || value.is_undefined() { return Self::Null; }
if let Some(val) = value.as_bool() {
return Self::Bool(val);
}
if let Some(val) = value.as_f64() {
return Self::Number(SNum::F64(val));
}
if let Some(val) = value.as_string() {
let nref = SNodeRef::from(&val);
if nref.exists(&doc.graph) {
return Self::Object(nref);
}
let dref = SDataRef::from(&val);
if dref.exists(&doc.graph) {
return Self::FnPtr(dref);
}
return Self::String(val);
}
if value.is_array() {
let mut res = Vec::new();
let array = Array::from(&value);
for val in array {
res.push(Self::from((val, doc)));
}
return Self::Array(res);
}
let intarray = Uint8Array::from(value);
Self::Blob(intarray.to_vec())
}
}