feat(tvix/eval): implement serde::Deserialize for Value

Co-Authored-By: Vincent Ambo <tazjin@tvl.su>

Change-Id: Ib6f7d1f4f4faac36b44f5f75cccc57bf912cf606
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7626
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
This commit is contained in:
Ryan Lahfa 2022-12-24 18:18:26 +01:00 committed by tazjin
parent c011a6130c
commit 805219a2fa
10 changed files with 114 additions and 50 deletions

View file

@ -6,6 +6,8 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::{cell::Ref, fmt::Display};
use serde::Deserialize;
#[cfg(feature = "arbitrary")]
mod arbitrary;
mod attrs;
@ -31,30 +33,41 @@ pub use thunk::Thunk;
use self::thunk::ThunkSet;
#[warn(variant_size_differences)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum Value {
Null,
Bool(bool),
Integer(i64),
Float(f64),
String(NixString),
#[serde(skip)]
Path(PathBuf),
Attrs(Box<NixAttrs>),
List(NixList),
#[serde(skip)]
Closure(Rc<Closure>), // must use Rc<Closure> here in order to get proper pointer equality
#[serde(skip)]
Builtin(Builtin),
// Internal values that, while they technically exist at runtime,
// are never returned to or created directly by users.
#[serde(skip)]
Thunk(Thunk),
// See [`compiler::compile_select_or()`] for explanation
#[serde(skip)]
AttrNotFound,
// this can only occur in Chunk::Constants and nowhere else
#[serde(skip)]
Blueprint(Rc<Lambda>),
#[serde(skip)]
DeferredUpvalue(StackIdx),
#[serde(skip)]
UnresolvedPath(PathBuf),
}
@ -542,47 +555,9 @@ impl From<PathBuf> for Value {
}
}
impl TryFrom<serde_json::Value> for Value {
type Error = ErrorKind;
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
// TODO(grfn): Replace with a real serde::Deserialize impl (for perf)
match value {
serde_json::Value::Null => Ok(Self::Null),
serde_json::Value::Bool(b) => Ok(Self::Bool(b)),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(Self::Integer(i))
} else if let Some(f) = n.as_f64() {
Ok(Self::Float(f))
} else {
Err(ErrorKind::FromJsonError(format!(
"JSON number not representable as Nix value: {n}"
)))
}
}
serde_json::Value::String(s) => Ok(s.into()),
serde_json::Value::Array(a) => Ok(Value::List(
a.into_iter()
.map(Value::try_from)
.collect::<Result<imbl::Vector<_>, _>>()?
.into(),
)),
serde_json::Value::Object(obj) => {
match (obj.len(), obj.get("name"), obj.get("value")) {
(2, Some(name), Some(value)) => Ok(Self::attrs(NixAttrs::from_kv(
name.clone().try_into()?,
value.clone().try_into()?,
))),
_ => Ok(Self::attrs(NixAttrs::from_iter(
obj.into_iter()
.map(|(k, v)| Ok((k.into(), v.try_into()?)))
.collect::<Result<Vec<(NixString, Value)>, ErrorKind>>()?
.into_iter(),
))),
}
}
}
impl From<Vec<Value>> for Value {
fn from(val: Vec<Value>) -> Self {
Self::List(NixList::from_vec(val))
}
}