use core::fmt;
use core::hash::{Hash, Hasher};
use pi_result::Error;
#[non_exhaustive]
pub enum TransferProgress {
Exact {
bytes: usize,
},
AtLeast {
bytes: usize,
},
Unknown,
}
impl TransferProgress {
#[must_use]
pub fn minimum_bytes(&self) -> usize {
match self {
Self::Exact { bytes } | Self::AtLeast { bytes } => *bytes,
Self::Unknown => 0,
}
}
#[must_use]
pub fn exact_bytes(&self) -> Option<usize> {
match self {
Self::Exact { bytes } => Some(*bytes),
Self::AtLeast { .. } | Self::Unknown => None,
}
}
#[must_use]
pub fn is_exact(&self) -> bool {
matches!(self, Self::Exact { .. })
}
#[must_use]
pub fn is_uncertain(&self) -> bool {
!self.is_exact()
}
}
impl Clone for TransferProgress {
fn clone(&self) -> Self {
match self {
Self::Exact { bytes } => Self::Exact { bytes: *bytes },
Self::AtLeast { bytes } => Self::AtLeast { bytes: *bytes },
Self::Unknown => Self::Unknown,
}
}
}
impl fmt::Debug for TransferProgress {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Exact { bytes } => formatter
.debug_struct("Exact")
.field("bytes", bytes)
.finish(),
Self::AtLeast { bytes } => formatter
.debug_struct("AtLeast")
.field("bytes", bytes)
.finish(),
Self::Unknown => formatter.write_str("Unknown"),
}
}
}
impl fmt::Display for TransferProgress {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Exact { bytes } => write!(formatter, "exactly {bytes} bytes"),
Self::AtLeast { bytes } => write!(formatter, "at least {bytes} bytes"),
Self::Unknown => formatter.write_str("unknown progress"),
}
}
}
impl PartialEq for TransferProgress {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Exact { bytes: left }, Self::Exact { bytes: right })
| (Self::AtLeast { bytes: left }, Self::AtLeast { bytes: right }) => {
left == right
}
(Self::Unknown, Self::Unknown) => true,
_ => false,
}
}
}
impl Eq for TransferProgress {}
impl Hash for TransferProgress {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
match self {
Self::Exact { bytes } => {
0_u8.hash(state);
bytes.hash(state);
}
Self::AtLeast { bytes } => {
1_u8.hash(state);
bytes.hash(state);
}
Self::Unknown => 2_u8.hash(state),
}
}
}
pub struct BufferFailure<B> {
pub(crate) error: Error,
pub(crate) buffer: B,
pub(crate) progress: TransferProgress,
}
impl<B> BufferFailure<B> {
#[must_use]
pub fn new(error: Error, buffer: B, progress: TransferProgress) -> Self {
Self {
error,
buffer,
progress,
}
}
#[must_use]
pub fn error(&self) -> &Error {
&self.error
}
#[must_use]
pub fn buffer(&self) -> &B {
&self.buffer
}
#[must_use]
pub fn progress(&self) -> &TransferProgress {
&self.progress
}
#[must_use]
pub fn into_parts(self) -> (Error, B, TransferProgress) {
(self.error, self.buffer, self.progress)
}
}
impl<B> fmt::Debug for BufferFailure<B> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("BufferFailure")
.field("error", &self.error)
.field("buffer_type", &core::any::type_name::<B>())
.field("buffer", &"<redacted>")
.field("progress", &self.progress)
.finish()
}
}
impl<B> fmt::Display for BufferFailure<B> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{}; progress: {}",
self.error, self.progress
)
}
}