nix_compat/nar/reader/async/
read.rs

1use tokio::io::{
2    self, AsyncReadExt,
3    ErrorKind::{InvalidData, UnexpectedEof},
4};
5
6use crate::nar::wire::Tag;
7
8use super::Reader;
9
10/// Consume a known token from the reader.
11pub async fn token<const N: usize>(reader: &mut Reader<'_>, token: &[u8; N]) -> io::Result<()> {
12    let mut buf = [0u8; N];
13
14    // This implements something similar to [AsyncReadExt::read_exact], but verifies that
15    // the input data matches the token while we read it. These two slices respectively
16    // represent the remaining token to be verified, and the remaining input buffer.
17    let mut token = &token[..];
18    let mut buf = &mut buf[..];
19
20    while !token.is_empty() {
21        match reader.read(buf).await? {
22            0 => {
23                return Err(UnexpectedEof.into());
24            }
25            n => {
26                let (t, b);
27                (t, token) = token.split_at(n);
28                (b, buf) = buf.split_at_mut(n);
29
30                if t != b {
31                    return Err(InvalidData.into());
32                }
33            }
34        }
35    }
36
37    Ok(())
38}
39
40/// Consume a [Tag] from the reader.
41pub async fn tag<T: Tag>(reader: &mut Reader<'_>) -> io::Result<T> {
42    let mut buf = T::make_buf();
43    let buf = buf.as_mut();
44
45    // first read the known minimum length…
46    reader.read_exact(&mut buf[..T::MIN]).await?;
47
48    // then decide which tag we're expecting
49    let tag = T::from_u8(buf[T::OFF]).ok_or(InvalidData)?;
50    let (head, tail) = tag.as_bytes().split_at(T::MIN);
51
52    // make sure what we've read so far is valid
53    if buf[..T::MIN] != *head {
54        return Err(InvalidData.into());
55    }
56
57    // …then read the rest, if any
58    if !tail.is_empty() {
59        let rest = tail.len();
60        reader.read_exact(&mut buf[..rest]).await?;
61
62        // and make sure it's what we expect
63        if buf[..rest] != *tail {
64            return Err(InvalidData.into());
65        }
66    }
67
68    Ok(tag)
69}