feat(nix-compat/wire/bytes/reader): parametrise on trailer tag
This allows using BytesReader with a custom tag, eg the closing parens for the NAR reader. No public constructor is provided for custom-tagged readers, since this feature isn't public API. Change-Id: I82e73d064edc4b6783ead1d6fe46a5b35f45c844 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11543 Reviewed-by: Brian Olsen <me@griff.name> Reviewed-by: flokli <flokli@flokli.de> Tested-by: BuildkiteCI
This commit is contained in:
parent
ba00f0c695
commit
343e176bec
3 changed files with 31 additions and 10 deletions
|
@ -4,7 +4,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
mod reader;
|
pub(crate) mod reader;
|
||||||
pub use reader::BytesReader;
|
pub use reader::BytesReader;
|
||||||
mod writer;
|
mod writer;
|
||||||
pub use writer::BytesWriter;
|
pub use writer::BytesWriter;
|
||||||
|
|
|
@ -8,6 +8,10 @@ use std::{
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf};
|
use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf};
|
||||||
|
|
||||||
use trailer::{read_trailer, ReadTrailer, Trailer};
|
use trailer::{read_trailer, ReadTrailer, Trailer};
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use self::trailer::Pad;
|
||||||
|
pub(crate) use self::trailer::Tag;
|
||||||
mod trailer;
|
mod trailer;
|
||||||
|
|
||||||
/// Reads a "bytes wire packet" from the underlying reader.
|
/// Reads a "bytes wire packet" from the underlying reader.
|
||||||
|
@ -24,12 +28,13 @@ mod trailer;
|
||||||
/// If the data is not read all the way to the end, or an error is encountered,
|
/// If the data is not read all the way to the end, or an error is encountered,
|
||||||
/// the underlying reader is no longer usable and might return garbage.
|
/// the underlying reader is no longer usable and might return garbage.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BytesReader<R> {
|
#[allow(private_bounds)]
|
||||||
state: State<R>,
|
pub struct BytesReader<R, T: Tag = Pad> {
|
||||||
|
state: State<R, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum State<R> {
|
enum State<R, T: Tag> {
|
||||||
/// Full 8-byte blocks are being read and released to the caller.
|
/// Full 8-byte blocks are being read and released to the caller.
|
||||||
Body {
|
Body {
|
||||||
reader: Option<R>,
|
reader: Option<R>,
|
||||||
|
@ -38,7 +43,7 @@ enum State<R> {
|
||||||
user_len: u64,
|
user_len: u64,
|
||||||
},
|
},
|
||||||
/// The trailer is in the process of being read.
|
/// The trailer is in the process of being read.
|
||||||
ReadTrailer(ReadTrailer<R>),
|
ReadTrailer(ReadTrailer<R, T>),
|
||||||
/// The trailer has been fully read and validated,
|
/// The trailer has been fully read and validated,
|
||||||
/// and data can now be released to the caller.
|
/// and data can now be released to the caller.
|
||||||
ReleaseTrailer { consumed: u8, data: Trailer },
|
ReleaseTrailer { consumed: u8, data: Trailer },
|
||||||
|
@ -49,7 +54,21 @@ where
|
||||||
R: AsyncRead + Unpin,
|
R: AsyncRead + Unpin,
|
||||||
{
|
{
|
||||||
/// Constructs a new BytesReader, using the underlying passed reader.
|
/// Constructs a new BytesReader, using the underlying passed reader.
|
||||||
pub async fn new<S: RangeBounds<u64>>(mut reader: R, allowed_size: S) -> io::Result<Self> {
|
pub async fn new<S: RangeBounds<u64>>(reader: R, allowed_size: S) -> io::Result<Self> {
|
||||||
|
BytesReader::new_internal(reader, allowed_size).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(private_bounds)]
|
||||||
|
impl<R, T: Tag> BytesReader<R, T>
|
||||||
|
where
|
||||||
|
R: AsyncRead + Unpin,
|
||||||
|
{
|
||||||
|
/// Constructs a new BytesReader, using the underlying passed reader.
|
||||||
|
pub(crate) async fn new_internal<S: RangeBounds<u64>>(
|
||||||
|
mut reader: R,
|
||||||
|
allowed_size: S,
|
||||||
|
) -> io::Result<Self> {
|
||||||
let size = reader.read_u64_le().await?;
|
let size = reader.read_u64_le().await?;
|
||||||
|
|
||||||
if !allowed_size.contains(&size) {
|
if !allowed_size.contains(&size) {
|
||||||
|
@ -84,7 +103,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: AsyncRead + Unpin> AsyncRead for BytesReader<R> {
|
#[allow(private_bounds)]
|
||||||
|
impl<R: AsyncRead + Unpin, T: Tag> AsyncRead for BytesReader<R, T> {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
mut self: Pin<&mut Self>,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut task::Context,
|
cx: &mut task::Context,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
future::Future,
|
future::Future,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
|
@ -33,14 +34,14 @@ pub(crate) trait Tag {
|
||||||
/// Suitably sized buffer for reading [Self::PATTERN]
|
/// Suitably sized buffer for reading [Self::PATTERN]
|
||||||
///
|
///
|
||||||
/// HACK: This is a workaround for const generics limitations.
|
/// HACK: This is a workaround for const generics limitations.
|
||||||
type Buf: AsRef<[u8]> + AsMut<[u8]> + Unpin;
|
type Buf: AsRef<[u8]> + AsMut<[u8]> + Debug + Unpin;
|
||||||
|
|
||||||
/// Make an instance of [Self::Buf]
|
/// Make an instance of [Self::Buf]
|
||||||
fn make_buf() -> Self::Buf;
|
fn make_buf() -> Self::Buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Pad {}
|
pub enum Pad {}
|
||||||
|
|
||||||
impl Tag for Pad {
|
impl Tag for Pad {
|
||||||
const PATTERN: &'static [u8] = &[0; 8];
|
const PATTERN: &'static [u8] = &[0; 8];
|
||||||
|
@ -53,7 +54,7 @@ impl Tag for Pad {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ReadTrailer<R, T: Tag = Pad> {
|
pub(crate) struct ReadTrailer<R, T: Tag> {
|
||||||
reader: R,
|
reader: R,
|
||||||
data_len: u8,
|
data_len: u8,
|
||||||
filled: u8,
|
filled: u8,
|
||||||
|
|
Loading…
Reference in a new issue