feat(tvix/serde): handle nested data structures
Change-Id: I543fc05d31bbb9ad2edb887bce4510e9a1cdb102 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7714 Tested-by: BuildkiteCI Autosubmit: tazjin <tazjin@tvl.su> Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
parent
7b88e4fa9b
commit
4350be34d1
1 changed files with 55 additions and 12 deletions
|
@ -1,14 +1,33 @@
|
||||||
//! Deserialisation from Nix to Rust values.
|
//! Deserialisation from Nix to Rust values.
|
||||||
|
|
||||||
use serde::de;
|
use serde::de;
|
||||||
|
use serde::de::value::{MapDeserializer, SeqDeserializer};
|
||||||
use tvix_eval::Value;
|
use tvix_eval::Value;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
struct Deserializer {
|
struct NixDeserializer {
|
||||||
value: tvix_eval::Value,
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_str<'code, T>(src: &'code str) -> Result<T, Error>
|
pub fn from_str<'code, T>(src: &'code str) -> Result<T, Error>
|
||||||
where
|
where
|
||||||
T: serde::Deserialize<'code>,
|
T: serde::Deserialize<'code>,
|
||||||
|
@ -25,9 +44,7 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let de = Deserializer {
|
let de = NixDeserializer::new(result.value.expect("value should be present on success"));
|
||||||
value: result.value.expect("value should be present on success"),
|
|
||||||
};
|
|
||||||
|
|
||||||
T::deserialize(de)
|
T::deserialize(de)
|
||||||
}
|
}
|
||||||
|
@ -50,7 +67,7 @@ fn visit_integer<I: TryFrom<i64>>(v: &Value) -> Result<I, Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> de::Deserializer<'de> for Deserializer {
|
impl<'de> de::Deserializer<'de> for NixDeserializer {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
@ -218,11 +235,17 @@ impl<'de> de::Deserializer<'de> for Deserializer {
|
||||||
todo!("how to represent this?");
|
todo!("how to represent this?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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>
|
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
todo!("how to represent this?");
|
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>
|
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
@ -262,7 +285,15 @@ impl<'de> de::Deserializer<'de> for Deserializer {
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
todo!()
|
if let Value::List(list) = self.value {
|
||||||
|
let mut seq =
|
||||||
|
SeqDeserializer::new(list.into_iter().map(|value| NixDeserializer::new(value)));
|
||||||
|
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>
|
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
@ -288,19 +319,31 @@ impl<'de> de::Deserializer<'de> for Deserializer {
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
todo!()
|
if let Value::Attrs(attrs) = self.value {
|
||||||
|
let mut map = MapDeserializer::new(attrs.into_iter().map(|(k, v)| {
|
||||||
|
(
|
||||||
|
NixDeserializer::new(Value::String(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>(
|
fn deserialize_struct<V>(
|
||||||
self,
|
self,
|
||||||
name: &'static str,
|
_name: &'static str,
|
||||||
fields: &'static [&'static str],
|
_fields: &'static [&'static str],
|
||||||
visitor: V,
|
visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
todo!()
|
self.deserialize_map(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum<V>(
|
fn deserialize_enum<V>(
|
||||||
|
@ -319,7 +362,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
todo!()
|
self.deserialize_str(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
|
Loading…
Reference in a new issue