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:
parent
c011a6130c
commit
805219a2fa
10 changed files with 114 additions and 50 deletions
|
|
@ -8,6 +8,8 @@
|
|||
use std::iter::FromIterator;
|
||||
|
||||
use imbl::{ordmap, OrdMap};
|
||||
use serde::de::{Deserializer, Error, Visitor};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::vm::VM;
|
||||
|
|
@ -20,7 +22,7 @@ use super::Value;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
enum AttrsRep {
|
||||
Empty,
|
||||
|
||||
|
|
@ -138,6 +140,39 @@ impl TotalDisplay for NixAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for NixAttrs {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct MapVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for MapVisitor {
|
||||
type Value = NixAttrs;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a valid Nix attribute set")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut stack_array = Vec::with_capacity(map.size_hint().unwrap_or(0) * 2);
|
||||
|
||||
while let Some((key, value)) = map.next_entry()? {
|
||||
stack_array.push(key);
|
||||
stack_array.push(value);
|
||||
}
|
||||
|
||||
NixAttrs::construct(stack_array.len() / 2, stack_array).map_err(A::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_map(MapVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary")]
|
||||
mod arbitrary {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ use std::ops::Index;
|
|||
|
||||
use imbl::{vector, Vector};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::vm::VM;
|
||||
|
||||
|
|
@ -11,7 +13,7 @@ use super::TotalDisplay;
|
|||
use super::Value;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct NixList(Vector<Value>);
|
||||
|
||||
impl TotalDisplay for NixList {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ use std::ops::Deref;
|
|||
use std::path::Path;
|
||||
use std::{borrow::Cow, fmt::Display, str::Chars};
|
||||
|
||||
use serde::de::{Deserializer, Visitor};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum StringRepr {
|
||||
Smol(SmolStr),
|
||||
|
|
@ -68,6 +71,39 @@ impl Hash for NixString {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for NixString {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct StringVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for StringVisitor {
|
||||
type Value = NixString;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a valid Nix string")
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(v.into())
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_string(StringVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary")]
|
||||
mod arbitrary {
|
||||
use super::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue