git.delta.rocks / jrsonnet / refs/commits / 9b70922a5a83

difftreelog

feat (de)serialize nix imports

upkxyxktYaroslav Bolyukin2026-01-22parent: #3bdc221.patch.diff
in: trunk

5 files changed

modifiedCargo.lockdiffbeforeafterboth
2208name = "nixlike"2208name = "nixlike"
2209version = "0.1.0"2209version = "0.1.0"
2210dependencies = [2210dependencies = [
2211 "itertools 0.14.0",
2211 "linked-hash-map",2212 "linked-hash-map",
2212 "peg",2213 "peg",
2213 "ron",2214 "ron",
modifiedcrates/nixlike/Cargo.tomldiffbeforeafterboth
10linked-hash-map = "0.5.6"10linked-hash-map = "0.5.6"
11peg = "0.8.5"11peg = "0.8.5"
12ron = "0.11.0"12ron = "0.11.0"
13serde = "1.0.219"13serde = { version = "1.0.219", features = ["derive"] }
14serde-transcode = "1.1.1"14serde-transcode = "1.1.1"
15serde_json = "1.0.140"15serde_json = "1.0.140"
16itertools = "0.14.0"
1617
modifiedcrates/nixlike/src/de_impl.rsdiffbeforeafterboth
22
3use linked_hash_map::LinkedHashMap;3use linked_hash_map::LinkedHashMap;
4use serde::{4use serde::{
5 Deserializer,5 Deserializer, Serialize,
6 de::{self, MapAccess, SeqAccess},6 de::{self, MapAccess, SeqAccess},
7};7};
88
138 Value::Object(o) => visitor.visit_map(ObjectAccess::new(o)),138 Value::Object(o) => visitor.visit_map(ObjectAccess::new(o)),
139 Value::Array(a) => visitor.visit_seq(ArrayAccess::new(a)),139 Value::Array(a) => visitor.visit_seq(ArrayAccess::new(a)),
140 Value::Null => visitor.visit_none(),140 Value::Null => visitor.visit_none(),
141 Value::Import(d) => {
142 let value = d.serialize(crate::se_impl::MySerialize)?;
143 value.deserialize_any(visitor)
144 }
141 }145 }
142 }146 }
143147
323 where327 where
324 V: serde::de::Visitor<'de>,328 V: serde::de::Visitor<'de>,
325 {329 {
330 match self {
331 Value::Import(d) => {
332 let value = d.serialize(crate::se_impl::MySerialize)?;
333 value.deserialize_map(visitor)
334 }
326 visitor.visit_map(self.parse_object().map(ObjectAccess::new)?)335 v => visitor.visit_map(v.parse_object().map(ObjectAccess::new)?),
336 }
327 }337 }
328338
329 fn deserialize_struct<V>(339 fn deserialize_struct<V>(
modifiedcrates/nixlike/src/lib.rsdiffbeforeafterboth
5//! 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 no
6//! variables/recursive records, interpolation, e.t.c.6//! variables/recursive records, interpolation, e.t.c.
7
8use std::marker::PhantomData;
79
8use 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}
47
48#[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-printing
53 // as nix inline object value
54 __magic_marker: PhantomData<()>,
55}
56
57impl 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}
4465
45fn 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}
173
174 rule import() -> NixImport
175 = "import" _ s:string() {NixImport::new(s)}
152176
153 rule value() -> Value177 rule value() -> Value
154 = 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 out
192}217}
193218
194#[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 // TODO
200 value.to_owned()221 value.to_owned()
201}222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test() {
230 assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\"");
231 }
202232
203#[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 }
247
248 #[test]
249 fn test_nix_import_roundtrip() {
250 let import = NixImport::new("./some/path.nix");
251
252 let serialized = serialize(&import).expect("serialize");
253 assert_eq!(serialized, "import \"./some/path.nix\"");
254
255 let deserialized: NixImport = parse_str(&serialized).expect("deserialize");
256 assert_eq!(deserialized.import, "./some/path.nix");
257 }
258}
217259
modifiedcrates/nixlike/src/to_string.rsdiffbeforeafterboth
1use itertools::Itertools;
2
1use crate::Value;3use crate::Value;
24
76 }78 }
77}79}
7880
81fn write_nix_import(import: &str, out: &mut String, padding: &mut usize) {
82 out.push_str("import ");
83 write_nix_str(import, out, padding)
84}
79fn write_nix_buf(value: &Value, out: &mut String, padding: &mut usize) {85fn write_nix_buf(value: &Value, out: &mut String, padding: &mut usize) {
80 match value {86 match value {
81 Value::Null => out.push_str("null"),87 Value::Null => out.push_str("null"),
98 out.push(']');104 out.push(']');
99 }105 }
100 }106 }
107 Value::Import(i) => write_nix_import(&i.import, out, padding),
101 Value::Object(obj) => {108 Value::Object(obj) => {
102 if obj.is_empty() {109 if obj.is_empty() {
103 out.push_str("{ }")110 out.push_str("{ }");
104 } else {111 } else if obj.len() == 2
112 && let Some([(importk, Value::String(importv)), (markerk, Value::Null)]) =
113 obj.iter().next_array::<2>()
114 && markerk == "__magic_marker"
115 && importk == "__magic_import"
116 {
117 write_nix_import(importv, out, padding)
118 } else {
105 out.push_str("{\n");119 out.push_str("{\n");
106 *padding += 1;120 *padding += 1;
107 for (k, v) in obj {121 for (k, v) in obj {