1use serde::{de::SeqAccess, ser::SerializeTuple, Deserialize, Serialize};
9use serde_bytes::ByteBuf;
10
11use crate::{
12 serialize::{NixDeserializer, Tee},
13 NixString,
14};
15
16#[derive(Clone, Debug, Default)]
17pub struct NarFile {
18 pub contents: NixString,
19 pub executable: bool,
20}
21
22#[derive(Clone, Debug)]
23pub enum Nar {
24 Contents(NarFile),
25 Target(NixString),
26 Directory(Vec<NarDirectoryEntry>),
27}
28
29impl Default for Nar {
30 fn default() -> Nar {
31 Nar::Contents(NarFile::default())
32 }
33}
34
35#[derive(Clone, Debug)]
38pub struct NarDirectoryEntry {
39 pub name: NixString,
40 pub node: Nar,
41}
42
43pub trait EntrySink<'a>: 'a {
44 type DirectorySink: DirectorySink<'a>;
45 type FileSink: FileSink;
46
47 fn become_directory(self) -> Self::DirectorySink;
48 fn become_file(self) -> Self::FileSink;
49 fn become_symlink(self, target: NixString);
50}
51
52pub trait DirectorySinkSuper {
55 type EntrySink<'b>: EntrySink<'b>;
56}
57
58pub trait DirectorySink<'a>: DirectorySinkSuper {
59 fn create_entry<'b>(&'b mut self, name: NixString) -> Self::EntrySink<'b>
60 where
61 'a: 'b;
62}
63
64pub trait FileSink: std::io::Write {
65 fn set_executable(&mut self, executable: bool);
66 fn add_contents(&mut self, contents: &[u8]);
67}
68
69impl<'a> EntrySink<'a> for &'a mut Nar {
70 type DirectorySink = &'a mut Vec<NarDirectoryEntry>;
71 type FileSink = &'a mut NarFile;
72
73 fn become_directory(self) -> Self::DirectorySink {
74 *self = Nar::Directory(Vec::new());
75 let Nar::Directory(dir) = self else {
76 unreachable!()
77 };
78 dir
79 }
80
81 fn become_file(self) -> Self::FileSink {
82 *self = Nar::Contents(NarFile {
83 executable: false,
84 contents: NixString::default(),
85 });
86 let Nar::Contents(contents) = self else {
88 unreachable!()
89 };
90 contents
91 }
92
93 fn become_symlink(self, target: NixString) {
94 *self = Nar::Target(target);
95 }
96}
97
98impl<'a> DirectorySinkSuper for &'a mut Vec<NarDirectoryEntry> {
99 type EntrySink<'b> = &'b mut Nar;
100}
101
102impl<'a> DirectorySink<'a> for &'a mut Vec<NarDirectoryEntry> {
103 fn create_entry<'b>(&'b mut self, name: NixString) -> Self::EntrySink<'b>
104 where
105 'a: 'b,
106 {
107 self.push(NarDirectoryEntry {
108 name,
109 node: Nar::Contents(NarFile {
110 contents: NixString::default(),
111 executable: false,
112 }),
113 });
114 &mut self.last_mut().unwrap().node
115 }
116}
117
118impl<'a> std::io::Write for &'a mut NarFile {
119 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
120 self.add_contents(buf);
121 Ok(buf.len())
122 }
123
124 fn flush(&mut self) -> std::io::Result<()> {
125 Ok(())
126 }
127}
128
129impl<'a> FileSink for &'a mut NarFile {
130 fn set_executable(&mut self, executable: bool) {
131 self.executable = executable;
132 }
133
134 fn add_contents(&mut self, contents: &[u8]) {
135 self.contents.0.extend_from_slice(contents);
136 }
137}
138
139#[derive(Default)]
140struct Null;
141
142impl<'a> std::io::Write for &'a mut Null {
143 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
144 Ok(buf.len())
145 }
146
147 fn flush(&mut self) -> std::io::Result<()> {
148 Ok(())
149 }
150}
151
152impl<'a> FileSink for &'a mut Null {
153 fn set_executable(&mut self, _executable: bool) {}
154
155 fn add_contents(&mut self, _contents: &[u8]) {}
156}
157
158impl<'a> EntrySink<'a> for &'a mut Null {
159 type DirectorySink = &'a mut Null;
160 type FileSink = &'a mut Null;
161
162 fn become_directory(self) -> Self::DirectorySink {
163 self
164 }
165
166 fn become_file(self) -> Self::FileSink {
167 self
168 }
169
170 fn become_symlink(self, _target: NixString) {}
171}
172
173impl<'a> DirectorySinkSuper for &'a mut Null {
174 type EntrySink<'b> = &'b mut Null;
175}
176
177impl<'a> DirectorySink<'a> for &'a mut Null {
178 fn create_entry<'b>(&'b mut self, _name: NixString) -> Self::EntrySink<'b>
179 where
180 'a: 'b,
181 {
182 self
183 }
184}
185
186trait SerializeTupleExt: SerializeTuple {
187 fn serialize_buf(&mut self, s: impl AsRef<[u8]>) -> Result<(), Self::Error> {
188 self.serialize_element(&ByteBuf::from(s.as_ref()))
189 }
190}
191
192impl<S: SerializeTuple> SerializeTupleExt for S {}
193
194trait StringReader<'a> {
196 type Error: serde::de::Error;
197
198 fn expect_string(&mut self) -> Result<NixString, Self::Error>;
199
200 fn expect_tag(&mut self, s: &str) -> Result<(), Self::Error> {
201 let tag = self.expect_string()?;
202 if tag.0 != s.as_bytes() {
203 Err(serde::de::Error::custom(format!(
204 "got {tag:?} instead of `{s}`"
205 )))
206 } else {
207 Ok(())
208 }
209 }
210
211 fn write_string(&mut self, mut write: impl std::io::Write) -> Result<(), Self::Error> {
216 write
217 .write_all(&self.expect_string()?.0)
218 .map_err(|e| serde::de::Error::custom(format!("io error: {e}")))
219 }
220}
221
222impl<'v, A: SeqAccess<'v>> StringReader<'v> for A {
223 type Error = A::Error;
224
225 fn expect_string(&mut self) -> Result<NixString, Self::Error> {
226 self.next_element()
227 .transpose()
228 .unwrap_or_else(|| Err(serde::de::Error::custom("unexpected end")))
229 }
230}
231
232fn read_entry<'v, 's, A: StringReader<'v>, S: EntrySink<'s> + 's>(
233 seq: &mut A,
234 sink: S,
235) -> Result<(), A::Error> {
236 seq.expect_tag("(")?;
237 seq.expect_tag("type")?;
238 let ty = seq.expect_string()?;
239 match ty.0.as_slice() {
240 b"regular" => {
241 let mut file = sink.become_file();
242 let mut tag = seq.expect_string()?;
244 while tag.0 == b"executable" {
245 seq.expect_tag("")?;
247 file.set_executable(true);
248 tag = seq.expect_string()?
249 }
250
251 if tag.0 == "contents" {
252 seq.write_string(file)?;
253 seq.expect_tag(")")?;
254 Ok(())
255 } else if tag.0 == ")" {
256 Ok(())
257 } else {
258 Err(serde::de::Error::custom(format!(
259 "expected contents, got {tag:?}"
260 )))
261 }
262 }
263 b"symlink" => {
264 seq.expect_tag("target")?;
265 let target = seq.expect_string()?;
266 seq.expect_tag(")")?;
267 sink.become_symlink(target);
268 Ok(())
269 }
270 b"directory" => {
271 let mut dir = sink.become_directory();
272 loop {
273 let tag = seq.expect_string()?;
274 if tag.0 == ")" {
275 break Ok(());
276 } else if tag.0 == "entry" {
277 seq.expect_tag("(")?;
278 seq.expect_tag("name")?;
279 let name = seq.expect_string()?;
280 let entry = dir.create_entry(name);
281 seq.expect_tag("node")?;
282 read_entry(seq, entry)?;
283 seq.expect_tag(")")?;
284 } else {
285 break Err(serde::de::Error::custom(format!(
286 "expected entry, got {tag:?}"
287 )));
288 }
289 }
290 }
291 v => Err(serde::de::Error::custom(format!(
292 "unknown file type `{v:?}`"
293 ))),
294 }
295}
296
297impl<'v> StringReader<'v> for NixDeserializer<'v> {
298 type Error = crate::serialize::Error;
299
300 fn expect_string(&mut self) -> Result<NixString, Self::Error> {
301 NixString::deserialize(self)
302 }
303
304 fn write_string(
305 &mut self,
306 mut write: impl std::io::Write,
307 ) -> Result<(), crate::serialize::Error> {
308 let len = self.read_u64()? as usize;
309 let mut buf = [0; 4096];
310 let mut remaining = len;
311 while remaining > 0 {
312 let max_len = buf.len().min(remaining);
313 let written = self.read.read(&mut buf[0..max_len])?;
314 write.write_all(&buf[0..written])?;
315
316 remaining -= written;
317 }
318
319 if len % 8 > 0 {
320 let padding = 8 - len % 8;
321 self.read.read_exact(&mut buf[..padding])?;
322 }
323 Ok(())
324 }
325}
326
327pub fn stream<R: std::io::Read, W: std::io::Write>(
336 read: R,
337 write: W,
338) -> Result<(), crate::serialize::Error> {
339 let mut tee = Tee::new(read, write);
340 let mut de = NixDeserializer { read: &mut tee };
341 de.expect_tag("nix-archive-1")?;
342 read_entry(&mut de, &mut Null)?;
343 Ok(())
344}
345
346impl<'de> Deserialize<'de> for Nar {
347 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
348 where
349 D: serde::Deserializer<'de>,
350 {
351 struct Visitor;
352
353 impl<'v> serde::de::Visitor<'v> for Visitor {
354 type Value = Nar;
355
356 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
357 formatter.write_str("Nar")
358 }
359
360 fn visit_seq<A: SeqAccess<'v>>(self, mut seq: A) -> Result<Nar, A::Error> {
361 seq.expect_tag("nix-archive-1")?;
362 let mut entry = Nar::default();
363 read_entry(&mut seq, &mut entry)?;
364 Ok(entry)
365 }
366 }
367
368 deserializer.deserialize_tuple(usize::MAX, Visitor)
369 }
370}
371
372impl Serialize for Nar {
373 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
374 where
375 S: serde::Serializer,
376 {
377 let mut tup = serializer.serialize_tuple(usize::MAX)?;
378 tup.serialize_buf(b"nix-archive-1")?;
379 tup.serialize_element(&Untagged(self))?;
380 tup.end()
381 }
382}
383
384struct Untagged<T>(T);
385
386impl<'a> Serialize for Untagged<&'a Nar> {
387 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
388 where
389 S: serde::Serializer,
390 {
391 let mut tup = serializer.serialize_tuple(usize::MAX)?;
392 tup.serialize_buf(b"(")?;
393 tup.serialize_buf(b"type")?;
394 match self.0 {
395 Nar::Contents(NarFile {
396 contents,
397 executable,
398 }) => {
399 tup.serialize_buf(b"regular")?;
400 if *executable {
401 tup.serialize_buf(b"executable")?;
402 tup.serialize_buf(b"")?;
403 }
404 tup.serialize_buf(b"contents")?;
405 tup.serialize_element(&contents)?;
406 }
407 Nar::Target(s) => {
408 tup.serialize_buf(b"symlink")?;
409 tup.serialize_buf(b"target")?;
410 tup.serialize_element(s)?;
411 }
412 Nar::Directory(entries) => {
413 tup.serialize_buf(b"directory")?;
414 for entry in entries {
415 tup.serialize_buf(b"entry")?;
416 tup.serialize_buf(b"(")?;
417 tup.serialize_buf(b"name")?;
418 tup.serialize_element(&entry.name)?;
419 tup.serialize_buf(b"node")?;
420 tup.serialize_element(&Untagged(&entry.node))?;
421 tup.serialize_buf(b")")?;
422 }
423 }
424 }
425 tup.serialize_buf(b")")?;
426 tup.end()
427 }
428}