-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(s2n-quic-core): add buffer reader/writer traits
- Loading branch information
Showing
40 changed files
with
2,785 additions
and
211 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
pub mod duplex; | ||
mod error; | ||
pub mod reader; | ||
pub mod reassembler; | ||
pub mod writer; | ||
|
||
pub use duplex::Duplex; | ||
pub use error::Error; | ||
pub use reader::Reader; | ||
pub use reassembler::Reassembler; | ||
pub use writer::Writer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use super::{Error, Reader, Writer}; | ||
use crate::varint::VarInt; | ||
|
||
mod split; | ||
|
||
pub use split::Split; | ||
|
||
pub trait Duplex: Reader + Writer {} | ||
|
||
impl<T: Reader + Writer> Duplex for T {} | ||
|
||
pub trait Skip: Duplex { | ||
fn skip(&mut self, len: VarInt, final_offset: Option<VarInt>) -> Result<(), Error>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use crate::{ | ||
buffer::{ | ||
duplex, | ||
reader::{self, storage::Infallible as _, Reader, Storage as _}, | ||
writer::{self, Writer}, | ||
Error, | ||
}, | ||
varint::VarInt, | ||
}; | ||
use core::convert::Infallible; | ||
|
||
pub struct Split<'a, C, D> | ||
where | ||
C: writer::Storage + ?Sized, | ||
D: duplex::Skip<Error = Infallible> + ?Sized, | ||
{ | ||
chunk: &'a mut C, | ||
duplex: &'a mut D, | ||
} | ||
|
||
impl<'a, C, D> Split<'a, C, D> | ||
where | ||
C: writer::Storage + ?Sized, | ||
D: duplex::Skip<Error = Infallible> + ?Sized, | ||
{ | ||
#[inline] | ||
pub fn new(chunk: &'a mut C, duplex: &'a mut D) -> Self { | ||
Self { chunk, duplex } | ||
} | ||
} | ||
|
||
/// Delegates to the inner Duplex | ||
impl<'a, C, D> reader::Storage for Split<'a, C, D> | ||
where | ||
C: writer::Storage + ?Sized, | ||
D: duplex::Skip<Error = Infallible> + ?Sized, | ||
{ | ||
type Error = D::Error; | ||
|
||
#[inline] | ||
fn buffered_len(&self) -> usize { | ||
self.duplex.buffered_len() | ||
} | ||
|
||
#[inline] | ||
fn buffer_is_empty(&self) -> bool { | ||
self.duplex.buffer_is_empty() | ||
} | ||
|
||
#[inline] | ||
fn read_chunk(&mut self, watermark: usize) -> Result<reader::storage::Chunk<'_>, Self::Error> { | ||
self.duplex.read_chunk(watermark) | ||
} | ||
|
||
#[inline] | ||
fn partial_copy_into<Dest>( | ||
&mut self, | ||
dest: &mut Dest, | ||
) -> Result<reader::storage::Chunk<'_>, Self::Error> | ||
where | ||
Dest: crate::buffer::writer::Storage + ?Sized, | ||
{ | ||
self.duplex.partial_copy_into(dest) | ||
} | ||
|
||
#[inline] | ||
fn copy_into<Dest>(&mut self, dest: &mut Dest) -> Result<(), Self::Error> | ||
where | ||
Dest: crate::buffer::writer::Storage + ?Sized, | ||
{ | ||
self.duplex.copy_into(dest) | ||
} | ||
} | ||
|
||
/// Delegates to the inner Duplex | ||
impl<'a, C, D> Reader for Split<'a, C, D> | ||
where | ||
C: writer::Storage + ?Sized, | ||
D: duplex::Skip<Error = Infallible> + ?Sized, | ||
{ | ||
#[inline] | ||
fn current_offset(&self) -> VarInt { | ||
self.duplex.current_offset() | ||
} | ||
|
||
#[inline] | ||
fn final_offset(&self) -> Option<VarInt> { | ||
self.duplex.final_offset() | ||
} | ||
|
||
#[inline] | ||
fn has_buffered_fin(&self) -> bool { | ||
self.duplex.has_buffered_fin() | ||
} | ||
|
||
#[inline] | ||
fn is_consumed(&self) -> bool { | ||
self.duplex.is_consumed() | ||
} | ||
} | ||
|
||
impl<'a, C, D> Writer for Split<'a, C, D> | ||
where | ||
C: writer::Storage + ?Sized, | ||
D: duplex::Skip<Error = Infallible> + ?Sized, | ||
{ | ||
#[inline] | ||
fn copy_from<R>(&mut self, reader: &mut R) -> Result<(), Error<R::Error>> | ||
where | ||
R: Reader + ?Sized, | ||
{ | ||
// enable reader checks | ||
let mut reader = reader.with_checks(); | ||
let reader = &mut reader; | ||
|
||
let initial_offset = reader.current_offset(); | ||
let final_offset = reader.final_offset(); | ||
let is_contiguous = initial_offset == self.duplex.current_offset(); | ||
|
||
{ | ||
// if the chunk specializes writing zero-copy Bytes/BytesMut, then just write to the | ||
// receive buffer, since that's what it stores | ||
let mut should_delegate = C::SPECIALIZES_BYTES || C::SPECIALIZES_BYTES_MUT; | ||
|
||
// if this packet is non-contiguous, then delegate to the wrapped writer | ||
should_delegate |= !is_contiguous; | ||
|
||
// if the chunk doesn't have any remaining capacity, then delegate | ||
should_delegate |= !self.chunk.has_remaining_capacity(); | ||
|
||
if should_delegate { | ||
self.duplex.copy_from(reader)?; | ||
|
||
if !self.duplex.buffer_is_empty() && self.chunk.has_remaining_capacity() { | ||
self.duplex.infallible_copy_into(self.chunk); | ||
} | ||
|
||
return Ok(()); | ||
} | ||
} | ||
|
||
debug_assert!( | ||
self.chunk.has_remaining_capacity(), | ||
"this code should only be executed if the chunk is empty" | ||
); | ||
|
||
reader.copy_into(self.chunk)?; | ||
|
||
let write_len = reader.current_offset() - initial_offset; | ||
|
||
self.duplex | ||
.skip(write_len, final_offset) | ||
.map_err(Error::mapped)?; | ||
|
||
if !reader.buffer_is_empty() { | ||
self.duplex.copy_from(reader)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
pub enum Error<Reader = core::convert::Infallible> { | ||
/// An invalid data range was provided | ||
OutOfRange, | ||
/// The provided final size was invalid for the buffer's state | ||
InvalidFin, | ||
/// The provided reader failed | ||
ReaderError(Reader), | ||
} | ||
|
||
impl<Reader> From<Reader> for Error<Reader> { | ||
#[inline] | ||
fn from(reader: Reader) -> Self { | ||
Self::ReaderError(reader) | ||
} | ||
} | ||
|
||
impl Error { | ||
#[inline] | ||
pub fn mapped<Reader>(error: Error) -> Error<Reader> { | ||
match error { | ||
Error::OutOfRange => Error::OutOfRange, | ||
Error::InvalidFin => Error::InvalidFin, | ||
Error::ReaderError(_) => unreachable!(), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
impl<Reader: std::error::Error> std::error::Error for Error<Reader> {} | ||
|
||
impl<Reader: core::fmt::Display> core::fmt::Display for Error<Reader> { | ||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
match self { | ||
Self::OutOfRange => write!(f, "write extends out of the maximum possible offset"), | ||
Self::InvalidFin => write!( | ||
f, | ||
"write modifies the final offset in a non-compliant manner" | ||
), | ||
Self::ReaderError(reader) => write!(f, "the provided reader failed with: {reader}"), | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.