1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::{
	error::{Error::*, LocError, Result},
	throw, LazyBinding, LazyVal, ObjMember, ObjValue, Val,
};
use jrsonnet_parser::Visibility;
use rustc_hash::FxHasher;
use serde_json::{Map, Number, Value};
use std::{
	collections::HashMap,
	convert::{TryFrom, TryInto},
	hash::BuildHasherDefault,
	rc::Rc,
};

impl TryFrom<&Val> for Value {
	type Error = LocError;
	fn try_from(v: &Val) -> Result<Self> {
		Ok(match v {
			Val::Bool(b) => Self::Bool(*b),
			Val::Null => Self::Null,
			Val::Str(s) => Self::String((s as &str).into()),
			Val::Num(n) => Self::Number(if n.fract() <= f64::EPSILON {
				(*n as i64).into()
			} else {
				Number::from_f64(*n).expect("to json number")
			}),
			Val::Arr(a) => {
				let mut out = Vec::with_capacity(a.len());
				for item in a.iter() {
					out.push((&item?).try_into()?);
				}
				Self::Array(out)
			}
			Val::Obj(o) => {
				let mut out = Map::new();
				for key in o.fields() {
					out.insert(
						(&key as &str).into(),
						(&o.get(key)?.expect("field exists")).try_into()?,
					);
				}
				Self::Object(out)
			}
			Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),
		})
	}
}

impl From<&Value> for Val {
	fn from(v: &Value) -> Self {
		match v {
			Value::Null => Self::Null,
			Value::Bool(v) => Self::Bool(*v),
			Value::Number(n) => Self::Num(n.as_f64().expect("as f64")),
			Value::String(s) => Self::Str((s as &str).into()),
			Value::Array(a) => {
				let mut out = Vec::with_capacity(a.len());
				for v in a {
					out.push(LazyVal::new_resolved(v.into()));
				}
				Self::Arr(out.into())
			}
			Value::Object(o) => {
				let mut entries = HashMap::with_capacity_and_hasher(
					o.len(),
					BuildHasherDefault::<FxHasher>::default(),
				);
				for (k, v) in o {
					entries.insert(
						(k as &str).into(),
						ObjMember {
							add: false,
							visibility: Visibility::Normal,
							invoke: LazyBinding::Bound(LazyVal::new_resolved(v.into())),
							location: None,
						},
					);
				}
				Self::Obj(ObjValue::new(None, Rc::new(entries)))
			}
		}
	}
}