use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use crate::copy::CopyFailureState;
use crate::copy::CopyStats;
use crate::copy::internal::CopyFailureParts;
use crate::error::FsError;
use crate::write::WriterRecovery;
pub struct CopyFailure {
parts: Box<CopyFailureParts>,
}
impl CopyFailure {
#[must_use]
pub(crate) fn new(
error: FsError,
state: CopyFailureState,
partial_stats: CopyStats,
writer: Option<WriterRecovery>,
) -> Self {
Self {
parts: Box::new(CopyFailureParts {
error,
state,
partial_stats,
writer,
}),
}
}
#[inline]
#[must_use]
pub const fn error(&self) -> &FsError {
&self.parts.error
}
#[inline]
#[must_use]
pub const fn state(&self) -> CopyFailureState {
self.parts.state
}
#[inline]
#[must_use]
pub const fn partial_stats(&self) -> &CopyStats {
&self.parts.partial_stats
}
#[inline]
#[must_use]
pub const fn has_recovery(&self) -> bool {
self.parts.writer.is_some()
}
#[inline]
#[must_use]
pub fn recovery(&self) -> Option<&WriterRecovery> {
self.parts.writer.as_ref()
}
#[inline]
#[must_use]
pub fn recovery_mut(&mut self) -> Option<&mut WriterRecovery> {
self.parts.writer.as_mut()
}
#[inline]
#[must_use]
pub fn take_recovery(&mut self) -> Option<WriterRecovery> {
self.parts.writer.take()
}
#[inline]
#[must_use]
pub fn into_parts(self) -> (FsError, CopyFailureState, CopyStats, Option<WriterRecovery>) {
let mut parts = self.parts;
(parts.error, parts.state, parts.partial_stats, parts.writer.take())
}
}
impl Debug for CopyFailure {
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
formatter
.debug_struct("CopyFailure")
.field("error", &self.parts.error)
.field("state", &self.parts.state)
.field("partial_stats", &self.parts.partial_stats)
.field("has_recovery", &self.parts.writer.is_some())
.finish()
}
}
impl Display for CopyFailure {
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
Display::fmt(self.error(), formatter)
}
}
impl Error for CopyFailure {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(self.error())
}
}
#[cfg(test)]
mod tests {
use std::hint::black_box;
use super::CopyFailure;
use crate::copy::CopyFailureState;
use crate::copy::CopyStats;
use crate::error::FsError;
use crate::error::FsErrorKind;
use crate::error::FsOperation;
use crate::write::WriterRecovery;
#[test]
fn recovery_accessors_are_executed_at_runtime() {
let has_recovery: fn(&CopyFailure) -> bool = black_box(CopyFailure::has_recovery);
let recovery: fn(&CopyFailure) -> Option<&WriterRecovery> = black_box(CopyFailure::recovery);
let recovery_mut: for<'a> fn(&'a mut CopyFailure) -> Option<&'a mut WriterRecovery> =
black_box(CopyFailure::recovery_mut);
let take_recovery: fn(&mut CopyFailure) -> Option<WriterRecovery> = black_box(CopyFailure::take_recovery);
let mut failure = CopyFailure::new(
FsError::new(FsErrorKind::NotFound, FsOperation::Copy, "missing source"),
CopyFailureState::Unchanged,
CopyStats::default(),
None,
);
assert!(!has_recovery(&failure));
assert!(recovery(&failure).is_none());
assert!(recovery_mut(&mut failure).is_none());
assert!(take_recovery(&mut failure).is_none());
}
}