difftreelog
feat (de)serialize nix imports
in: trunk
5 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2208,6 +2208,7 @@
name = "nixlike"
version = "0.1.0"
dependencies = [
+ "itertools 0.14.0",
"linked-hash-map",
"peg",
"ron",
crates/nixlike/Cargo.tomldiffbeforeafterboth--- a/crates/nixlike/Cargo.toml
+++ b/crates/nixlike/Cargo.toml
@@ -10,6 +10,7 @@
linked-hash-map = "0.5.6"
peg = "0.8.5"
ron = "0.11.0"
-serde = "1.0.219"
+serde = { version = "1.0.219", features = ["derive"] }
serde-transcode = "1.1.1"
serde_json = "1.0.140"
+itertools = "0.14.0"
crates/nixlike/src/de_impl.rsdiffbeforeafterboth--- a/crates/nixlike/src/de_impl.rs
+++ b/crates/nixlike/src/de_impl.rs
@@ -2,7 +2,7 @@
use linked_hash_map::LinkedHashMap;
use serde::{
- Deserializer,
+ Deserializer, Serialize,
de::{self, MapAccess, SeqAccess},
};
@@ -138,6 +138,10 @@
Value::Object(o) => visitor.visit_map(ObjectAccess::new(o)),
Value::Array(a) => visitor.visit_seq(ArrayAccess::new(a)),
Value::Null => visitor.visit_none(),
+ Value::Import(d) => {
+ let value = d.serialize(crate::se_impl::MySerialize)?;
+ value.deserialize_any(visitor)
+ }
}
}
@@ -323,7 +327,13 @@
where
V: serde::de::Visitor<'de>,
{
- visitor.visit_map(self.parse_object().map(ObjectAccess::new)?)
+ match self {
+ Value::Import(d) => {
+ let value = d.serialize(crate::se_impl::MySerialize)?;
+ value.deserialize_map(visitor)
+ }
+ v => visitor.visit_map(v.parse_object().map(ObjectAccess::new)?),
+ }
}
fn deserialize_struct<V>(
crates/nixlike/src/lib.rsdiffbeforeafterboth5//! expressions and expect it to work, only basic primitives are supported, and there is no5//! expressions and expect it to work, only basic primitives are supported, and there is no6//! variables/recursive records, interpolation, e.t.c.6//! variables/recursive records, interpolation, e.t.c.78use std::marker::PhantomData;798use linked_hash_map::LinkedHashMap;10use linked_hash_map::LinkedHashMap;9use peg::str::LineCol;11use peg::str::LineCol;39 Boolean(bool),41 Boolean(bool),40 Object(LinkedHashMap<String, Value>),42 Object(LinkedHashMap<String, Value>),41 Array(Vec<Value>),43 Array(Vec<Value>),44 Import(NixImport),42 Null,45 Null,43}46}4748#[derive(Debug, Serialize, Deserialize)]49pub struct NixImport {50 #[serde(rename = "__magic_import")]51 import: String,52 // Magic values should have exactly two values to avoid pretty-printing53 // as nix inline object value54 __magic_marker: PhantomData<()>,55}5657impl NixImport {58 pub fn new(import: impl AsRef<str>) -> Self {59 Self {60 import: import.as_ref().to_string(),61 __magic_marker: PhantomData,62 }63 }64}446545fn count_spaces(l: &str) -> usize {66fn count_spaces(l: &str) -> usize {46 l.chars().take_while(|&c| c == ' ').count()67 l.chars().take_while(|&c| c == ' ').count()150 rule array() -> Vec<Value>171 rule array() -> Vec<Value>151 = "[" _ v:value()**_ _ "]" {v}172 = "[" _ v:value()**_ _ "]" {v}173174 rule import() -> NixImport175 = "import" _ s:string() {NixImport::new(s)}152176153 rule value() -> Value177 rule value() -> Value154 = o:object() { Value::Object(o) }178 = i:import() { Value::Import(i) }179 / o:object() { Value::Object(o) }155 / a:array() { Value::Array(a) }180 / a:array() { Value::Array(a) }156 / s:string() { Value::String(s) }181 / s:string() { Value::String(s) }157 / "null" { Value::Null }182 / "null" { Value::Null }191 out216 out192}217}193218194#[test]195fn test() {196 assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\"\n");197}198pub fn format_nix(value: &String) -> String {219pub fn format_nix(value: &String) -> String {199 // TODO220 // TODO200 value.to_owned()221 value.to_owned()201}222}223224#[cfg(test)]225mod tests {226 use super::*;227228 #[test]229 fn test() {230 assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\"");231 }202232203#[test]233 #[test]204fn parse_multiline() {234 fn parse_multiline() {215 assert_eq!(nixlike::multiline_string("'' ''").expect("parse"), "");245 assert_eq!(nixlike::multiline_string("'' ''").expect("parse"), "");216}246 }247248 #[test]249 fn test_nix_import_roundtrip() {250 let import = NixImport::new("./some/path.nix");251252 let serialized = serialize(&import).expect("serialize");253 assert_eq!(serialized, "import \"./some/path.nix\"");254255 let deserialized: NixImport = parse_str(&serialized).expect("deserialize");256 assert_eq!(deserialized.import, "./some/path.nix");257 }258}217259crates/nixlike/src/to_string.rsdiffbeforeafterboth--- a/crates/nixlike/src/to_string.rs
+++ b/crates/nixlike/src/to_string.rs
@@ -1,3 +1,5 @@
+use itertools::Itertools;
+
use crate::Value;
pub fn write_identifier(k: &str, out: &mut String) {
@@ -76,6 +78,10 @@
}
}
+fn write_nix_import(import: &str, out: &mut String, padding: &mut usize) {
+ out.push_str("import ");
+ write_nix_str(import, out, padding)
+}
fn write_nix_buf(value: &Value, out: &mut String, padding: &mut usize) {
match value {
Value::Null => out.push_str("null"),
@@ -98,9 +104,17 @@
out.push(']');
}
}
+ Value::Import(i) => write_nix_import(&i.import, out, padding),
Value::Object(obj) => {
if obj.is_empty() {
- out.push_str("{ }")
+ out.push_str("{ }");
+ } else if obj.len() == 2
+ && let Some([(importk, Value::String(importv)), (markerk, Value::Null)]) =
+ obj.iter().next_array::<2>()
+ && markerk == "__magic_marker"
+ && importk == "__magic_import"
+ {
+ write_nix_import(importv, out, padding)
} else {
out.push_str("{\n");
*padding += 1;