use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use pi_result::Error;
use crate::TransferProgress;
#[non_exhaustive]
pub enum OverwriteTargetEvidence {
Unchanged,
ExactInputPrefix {
bytes: usize,
},
MutationStarted,
Unknown,
}
impl fmt::Debug for OverwriteTargetEvidence {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unchanged => formatter.write_str("Unchanged"),
Self::ExactInputPrefix { bytes } => formatter
.debug_struct("ExactInputPrefix")
.field("bytes", bytes)
.finish(),
Self::MutationStarted => formatter.write_str("MutationStarted"),
Self::Unknown => formatter.write_str("Unknown"),
}
}
}
impl fmt::Display for OverwriteTargetEvidence {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unchanged => formatter.write_str("target unchanged"),
Self::ExactInputPrefix { bytes } => {
write!(formatter, "target is exact input prefix of {bytes} bytes")
}
Self::MutationStarted => formatter.write_str("target mutation started"),
Self::Unknown => formatter.write_str("target state unknown"),
}
}
}
impl PartialEq for OverwriteTargetEvidence {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Unchanged, Self::Unchanged)
| (Self::MutationStarted, Self::MutationStarted)
| (Self::Unknown, Self::Unknown) => true,
(
Self::ExactInputPrefix { bytes: left },
Self::ExactInputPrefix { bytes: right },
) => left == right,
_ => false,
}
}
}
impl Eq for OverwriteTargetEvidence {}
impl PartialOrd for OverwriteTargetEvidence {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for OverwriteTargetEvidence {
fn cmp(&self, other: &Self) -> Ordering {
fn rank(evidence: &OverwriteTargetEvidence) -> u8 {
match evidence {
OverwriteTargetEvidence::Unchanged => 0,
OverwriteTargetEvidence::ExactInputPrefix { .. } => 1,
OverwriteTargetEvidence::MutationStarted => 2,
OverwriteTargetEvidence::Unknown => 3,
}
}
rank(self).cmp(&rank(other)).then_with(|| match (self, other) {
(
Self::ExactInputPrefix { bytes: left },
Self::ExactInputPrefix { bytes: right },
) => left.cmp(right),
_ => Ordering::Equal,
})
}
}
impl Hash for OverwriteTargetEvidence {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
match self {
Self::Unchanged => 0_u8.hash(state),
Self::ExactInputPrefix { bytes } => {
1_u8.hash(state);
bytes.hash(state);
}
Self::MutationStarted => 2_u8.hash(state),
Self::Unknown => 3_u8.hash(state),
}
}
}
pub struct OverwriteFailure<B> {
pub(crate) error: Error,
pub(crate) buffer: B,
pub(crate) progress: TransferProgress,
pub(crate) target_evidence: OverwriteTargetEvidence,
}
impl<B> OverwriteFailure<B> {
#[must_use]
pub fn new(
error: Error,
buffer: B,
progress: TransferProgress,
target_evidence: OverwriteTargetEvidence,
) -> Self {
Self {
error,
buffer,
progress,
target_evidence,
}
}
#[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 target_evidence(&self) -> &OverwriteTargetEvidence {
&self.target_evidence
}
#[must_use]
pub fn into_parts(
self,
) -> (
Error,
B,
TransferProgress,
OverwriteTargetEvidence,
) {
(
self.error,
self.buffer,
self.progress,
self.target_evidence,
)
}
}
impl<B> fmt::Debug for OverwriteFailure<B> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("OverwriteFailure")
.field("error", &self.error)
.field("buffer_type", &core::any::type_name::<B>())
.field("buffer", &"<redacted>")
.field("progress", &self.progress)
.field("target_evidence", &self.target_evidence)
.finish()
}
}
impl<B> fmt::Display for OverwriteFailure<B> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{}; progress: {}; target: {}",
self.error, self.progress, self.target_evidence
)
}
}