use std::borrow::Cow;
use std::collections::TryReserveError;
use std::sync::Arc;
use bytes::{Bytes, BytesMut};
use pi_result::error_stack::Report;
use pi_result::{ErrorKind, RawResult};
use crate::transfer::{BufferFailure, TransferProgress};
use crate::write_buffer::DetachableWriteBuffer;
#[derive(Debug, pi_result::thiserror::Error)]
enum WriteBufferDetachError {
#[error("failed to reserve {requested_bytes} bytes for a detached write buffer")]
Allocation {
requested_bytes: usize,
#[source]
source: TryReserveError,
},
}
fn try_copy_bytes(bytes: &[u8]) -> RawResult<Vec<u8>, TryReserveError> {
let mut detached = Vec::new();
detached.try_reserve_exact(bytes.len())?;
detached.extend_from_slice(bytes);
Ok(detached)
}
fn allocation_failure<B>(
buffer: B,
requested_bytes: usize,
source: TryReserveError,
) -> BufferFailure<B> {
let error = Report::new(WriteBufferDetachError::Allocation {
requested_bytes,
source,
})
.change_context(ErrorKind::ResourceExhausted);
BufferFailure {
error,
buffer,
progress: TransferProgress::Exact { bytes: 0 },
}
}
fn detach_copied<'a, T>(
original: &'a T,
bytes: &[u8],
) -> RawResult<(Vec<u8>, &'a T), BufferFailure<&'a T>>
where
T: ?Sized,
{
match try_copy_bytes(bytes) {
Ok(detached) => Ok((detached, original)),
Err(source) => Err(allocation_failure(original, bytes.len(), source)),
}
}
impl DetachableWriteBuffer for Vec<u8> {
type Detached = Vec<u8>;
type Recovery = ();
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
Ok((self, ()))
}
fn recover_from_detached(
detached: Self::Detached,
_recovery: Self::Recovery,
) -> Self {
detached
}
}
impl DetachableWriteBuffer for Box<[u8]> {
type Detached = Box<[u8]>;
type Recovery = ();
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
Ok((self, ()))
}
fn recover_from_detached(
detached: Self::Detached,
_recovery: Self::Recovery,
) -> Self {
detached
}
}
impl DetachableWriteBuffer for Arc<[u8]> {
type Detached = Arc<[u8]>;
type Recovery = ();
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
Ok((self, ()))
}
fn recover_from_detached(
detached: Self::Detached,
_recovery: Self::Recovery,
) -> Self {
detached
}
}
impl<'a> DetachableWriteBuffer for Cow<'a, [u8]> {
type Detached = Vec<u8>;
type Recovery = Option<&'a [u8]>;
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
match self {
Cow::Owned(buffer) => Ok((buffer, None)),
Cow::Borrowed(buffer) => match try_copy_bytes(buffer) {
Ok(detached) => Ok((detached, Some(buffer))),
Err(source) => Err(allocation_failure(
Cow::Borrowed(buffer),
buffer.len(),
source,
)),
},
}
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
match recovery {
Some(original) => {
drop(detached);
Cow::Borrowed(original)
}
None => Cow::Owned(detached),
}
}
}
impl DetachableWriteBuffer for Bytes {
type Detached = Bytes;
type Recovery = ();
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
Ok((self, ()))
}
fn recover_from_detached(
detached: Self::Detached,
_recovery: Self::Recovery,
) -> Self {
detached
}
}
impl DetachableWriteBuffer for BytesMut {
type Detached = BytesMut;
type Recovery = ();
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
Ok((self, ()))
}
fn recover_from_detached(
detached: Self::Detached,
_recovery: Self::Recovery,
) -> Self {
detached
}
}
impl<'a> DetachableWriteBuffer for &'a [u8] {
type Detached = Vec<u8>;
type Recovery = &'a [u8];
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
detach_copied(self, self)
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
drop(detached);
recovery
}
}
impl<'a> DetachableWriteBuffer for &'a Vec<u8> {
type Detached = Vec<u8>;
type Recovery = &'a Vec<u8>;
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
detach_copied(self, self.as_slice())
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
drop(detached);
recovery
}
}
#[allow(clippy::borrowed_box)]
impl<'a> DetachableWriteBuffer for &'a Box<[u8]> {
type Detached = Vec<u8>;
type Recovery = &'a Box<[u8]>;
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
detach_copied(self, self.as_ref())
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
drop(detached);
recovery
}
}
impl<'a> DetachableWriteBuffer for &'a Arc<[u8]> {
type Detached = Arc<[u8]>;
type Recovery = &'a Arc<[u8]>;
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
Ok((Arc::clone(self), self))
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
drop(detached);
recovery
}
}
impl<'a, 'b> DetachableWriteBuffer for &'a Cow<'b, [u8]> {
type Detached = Vec<u8>;
type Recovery = &'a Cow<'b, [u8]>;
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
detach_copied(self, self.as_ref())
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
drop(detached);
recovery
}
}
impl<'a> DetachableWriteBuffer for &'a Bytes {
type Detached = Bytes;
type Recovery = &'a Bytes;
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
Ok((Bytes::clone(self), self))
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
drop(detached);
recovery
}
}
impl<'a> DetachableWriteBuffer for &'a BytesMut {
type Detached = Vec<u8>;
type Recovery = &'a BytesMut;
fn try_detach(self) -> RawResult<(Self::Detached, Self::Recovery), BufferFailure<Self>> {
detach_copied(self, self.as_ref())
}
fn recover_from_detached(
detached: Self::Detached,
recovery: Self::Recovery,
) -> Self {
drop(detached);
recovery
}
}