nix_remote/
framed_data.rs

1//! Framed data, for streaming large blobs.
2
3use serde::{Deserialize, Serialize};
4use serde_bytes::ByteBuf;
5use std::io::{Read, Write};
6
7use crate::Result;
8
9/// Nix "framed data" stored in memory.
10///
11/// Nix has `FramedSource` and `FramedSink` for streaming large amounts of miscellaneous
12/// data. They represent lists of byte buffers, and the wire format is:
13/// - each byte buffer is represented as a length followed by a buffer of that length.
14///   The buffer is *NOT* padded, unlike everything else in this protocol.
15/// - the list is terminated by an empty buffer (which is represented on the wire as
16///   a length of zero, followed by nothing).
17///
18/// The whole point of this is that it is big enough that you don't want to hold it in
19/// memory all at once. Therefore, this struct might not be ideal for "production" use;
20/// see the [`stream`] function instead.
21#[derive(Clone, Default)]
22pub struct FramedData {
23    pub data: Vec<ByteBuf>,
24}
25
26impl std::fmt::Debug for FramedData {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        f.debug_struct("FramedData").finish_non_exhaustive()
29    }
30}
31
32impl FramedData {
33    pub fn read(mut r: impl Read) -> Result<FramedData> {
34        let mut de = crate::serialize::NixDeserializer { read: &mut r };
35
36        let mut ret = FramedData::default();
37        loop {
38            let len = u64::deserialize(&mut de)?;
39            if len == 0 {
40                break;
41            }
42            let mut buf = vec![0; len as usize];
43            de.read.read_exact(&mut buf)?;
44            // NOTE: the buffers in framed data are *not* padded.
45            ret.data.push(ByteBuf::from(buf));
46        }
47        Ok(ret)
48    }
49
50    pub fn write(&self, mut w: impl Write) -> Result<()> {
51        let mut ser = crate::serialize::NixSerializer { write: &mut w };
52
53        for data in &self.data {
54            (data.len() as u64).serialize(&mut ser)?;
55            ser.write.write_all(data)?;
56        }
57        0_u64.serialize(&mut ser)?;
58        Ok(())
59    }
60}
61
62/// Stream framed data from a `std::io::Read` to a `std::io::Write`.
63pub fn stream(read: &mut impl Read, write: &mut impl Write) -> anyhow::Result<()> {
64    let mut de = crate::serialize::NixDeserializer { read };
65    let mut ser = crate::serialize::NixSerializer { write };
66    const BUF_SIZE: usize = 4096;
67    let mut buf = vec![0; BUF_SIZE];
68
69    loop {
70        let mut len = u64::deserialize(&mut de)? as usize;
71        (len as u64).serialize(&mut ser)?;
72        if len == 0 {
73            break;
74        }
75        while len > 0 {
76            let chunk_len = len.min(BUF_SIZE);
77            de.read.read_exact(&mut buf[..chunk_len])?;
78            ser.write.write_all(&buf[..chunk_len])?;
79            len -= chunk_len;
80        }
81    }
82    Ok(())
83}