tvl-depot/tvix/serde/src/de.rs
Ryan Lahfa 863c4207cc feat(tvix/eval): contextful JSON operations
`toJSON` transform a Nix structure into a JSON string.

For each context in that Nix structure, the JSON string must possess it.

Thus, it is necessary to take the union of all contexts and attach it to
the final structure.

Unfortunately, the return type of `into_json` is a serde's JSON object,
not a string. Therefore, it is not possible to reuse `NixString`
machinery.

Context tests are reinforced as Nix does not test those behaviors.

Fixes b/393.

Change-Id: I5afdbc4e18dd70469192c1aa657d1049ba330149
Signed-off-by: Ryan Lahfa <tvl@lahfa.xyz>
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11266
Reviewed-by: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
2024-04-13 10:11:18 +00:00

475 lines
13 KiB
Rust

//! Deserialisation from Nix to Rust values.
use bstr::ByteSlice;
use serde::de::value::{MapDeserializer, SeqDeserializer};
use serde::de::{self, EnumAccess, VariantAccess};
pub use tvix_eval::Evaluation;
use tvix_eval::{EvalIO, Value};
use crate::error::Error;
struct NixDeserializer {
value: tvix_eval::Value,
}
impl NixDeserializer {
fn new(value: Value) -> Self {
if let Value::Thunk(thunk) = value {
Self::new(thunk.value().clone())
} else {
Self { value }
}
}
}
impl de::IntoDeserializer<'_, Error> for NixDeserializer {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
/// Evaluate the Nix code in `src` and attempt to deserialise the
/// value it returns to `T`.
pub fn from_str<'code, T>(src: &'code str) -> Result<T, Error>
where
T: serde::Deserialize<'code>,
{
from_str_with_config(src, |_| /* no extra config */ ())
}
/// Evaluate the Nix code in `src`, with extra configuration for the
/// `tvix_eval::Evaluation` provided by the given closure.
pub fn from_str_with_config<'code, T, F>(src: &'code str, config: F) -> Result<T, Error>
where
T: serde::Deserialize<'code>,
F: FnOnce(&mut Evaluation<Box<dyn EvalIO>>),
{
// First step is to evaluate the Nix code ...
let mut eval = Evaluation::new_pure();
config(&mut eval);
eval.strict = true;
let result = eval.evaluate(src, None);
if !result.errors.is_empty() {
return Err(Error::NixErrors {
errors: result.errors,
});
}
let de = NixDeserializer::new(result.value.expect("value should be present on success"));
T::deserialize(de)
}
fn unexpected(expected: &'static str, got: &Value) -> Error {
Error::UnexpectedType {
expected,
got: got.type_of(),
}
}
fn visit_integer<I: TryFrom<i64>>(v: &Value) -> Result<I, Error> {
match v {
Value::Integer(i) => I::try_from(*i).map_err(|_| Error::IntegerConversion {
got: *i,
need: std::any::type_name::<I>(),
}),
_ => Err(unexpected("integer", v)),
}
}
impl<'de> de::Deserializer<'de> for NixDeserializer {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
match self.value {
Value::Null => visitor.visit_unit(),
Value::Bool(b) => visitor.visit_bool(b),
Value::Integer(i) => visitor.visit_i64(i),
Value::Float(f) => visitor.visit_f64(f),
Value::String(s) => visitor.visit_string(s.to_string()),
Value::Path(p) => visitor.visit_string(p.to_string_lossy().into()), // TODO: hmm
Value::Attrs(_) => self.deserialize_map(visitor),
Value::List(_) => self.deserialize_seq(visitor),
// tvix-eval types that can not be deserialized through serde.
Value::Closure(_)
| Value::Builtin(_)
| Value::Thunk(_)
| Value::AttrNotFound
| Value::Blueprint(_)
| Value::DeferredUpvalue(_)
| Value::UnresolvedPath(_)
| Value::Json(..)
| Value::Catchable(_)
| Value::FinaliseRequest(_) => Err(Error::Unserializable {
value_type: self.value.type_of(),
}),
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
match self.value {
Value::Bool(b) => visitor.visit_bool(b),
_ => Err(unexpected("bool", &self.value)),
}
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_i8(visit_integer(&self.value)?)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_i16(visit_integer(&self.value)?)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_i32(visit_integer(&self.value)?)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_i64(visit_integer(&self.value)?)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_u8(visit_integer(&self.value)?)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_u16(visit_integer(&self.value)?)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_u32(visit_integer(&self.value)?)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_u64(visit_integer(&self.value)?)
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::Float(f) = self.value {
return visitor.visit_f32(f as f32);
}
Err(unexpected("float", &self.value))
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::Float(f) = self.value {
return visitor.visit_f64(f);
}
Err(unexpected("float", &self.value))
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::String(s) = &self.value {
let chars = s.chars().collect::<Vec<_>>();
if chars.len() == 1 {
return visitor.visit_char(chars[0]);
}
}
Err(unexpected("char", &self.value))
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::String(s) = &self.value {
if let Ok(s) = s.to_str() {
return visitor.visit_str(s);
}
}
Err(unexpected("string", &self.value))
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::String(s) = &self.value {
if let Ok(s) = s.to_str() {
return visitor.visit_str(s);
}
}
Err(unexpected("string", &self.value))
}
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
unimplemented!()
}
fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
unimplemented!()
}
// Note that this can not distinguish between a serialisation of
// `Some(())` and `None`.
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::Null = self.value {
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::Null = self.value {
return visitor.visit_unit();
}
Err(unexpected("null", &self.value))
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::List(list) = self.value {
let mut seq = SeqDeserializer::new(list.into_iter().map(NixDeserializer::new));
let result = visitor.visit_seq(&mut seq)?;
seq.end()?;
return Ok(result);
}
Err(unexpected("list", &self.value))
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
// just represent tuples as lists ...
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
// same as above
self.deserialize_seq(visitor)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if let Value::Attrs(attrs) = self.value {
let mut map = MapDeserializer::new(attrs.into_iter().map(|(k, v)| {
(
NixDeserializer::new(Value::from(k)),
NixDeserializer::new(v),
)
}));
let result = visitor.visit_map(&mut map)?;
map.end()?;
return Ok(result);
}
Err(unexpected("map", &self.value))
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
self.deserialize_map(visitor)
}
// This method is responsible for deserializing the externally
// tagged enum variant serialisation.
fn deserialize_enum<V>(
self,
name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
match self.value {
// a string represents a unit variant
Value::String(ref s) => {
if let Ok(s) = s.to_str() {
visitor.visit_enum(de::value::StrDeserializer::new(s))
} else {
Err(unexpected(name, &self.value))
}
}
// an attribute set however represents an externally
// tagged enum with content
Value::Attrs(attrs) => visitor.visit_enum(Enum(*attrs)),
_ => Err(unexpected(name, &self.value)),
}
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_unit()
}
}
struct Enum(tvix_eval::NixAttrs);
impl<'de> EnumAccess<'de> for Enum {
type Error = Error;
type Variant = NixDeserializer;
// TODO: pass the known variants down here and check against them
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: de::DeserializeSeed<'de>,
{
if self.0.len() != 1 {
return Err(Error::AmbiguousEnum);
}
let (key, value) = self.0.into_iter().next().expect("length asserted above");
if let Ok(k) = key.to_str() {
let val = seed.deserialize(de::value::StrDeserializer::<Error>::new(k))?;
Ok((val, NixDeserializer::new(value)))
} else {
Err(unexpected("string", &key.clone().into()))
}
}
}
impl<'de> VariantAccess<'de> for NixDeserializer {
type Error = Error;
fn unit_variant(self) -> Result<(), Self::Error> {
// If this case is hit, a user specified the name of a unit
// enum variant but gave it content. Unit enum deserialisation
// is handled in `deserialize_enum` above.
Err(Error::UnitEnumContent)
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: de::DeserializeSeed<'de>,
{
seed.deserialize(self)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
de::Deserializer::deserialize_seq(self, visitor)
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
de::Deserializer::deserialize_map(self, visitor)
}
}