use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use std::pin::Pin;
use crate::error::FsError;
use crate::error::FsErrorKind;
use crate::error::FsOperation;
use crate::error::FsResult;
use crate::error::RecoveryCleanupState;
use crate::facade::internal::RecoveryCleanupGuard;
use crate::path::Path;
use crate::spi::AsyncFileWriteSession;
use crate::spi::SpiFuture;
use crate::write::WriteAbortOutcome;
#[must_use = "explicitly clean or retain the isolated recovery session"]
pub struct RejectedAsyncWriter {
session: Pin<Box<dyn AsyncFileWriteSession>>,
state: RecoveryCleanupState,
provider: Box<str>,
path: Option<Path>,
}
impl RejectedAsyncWriter {
pub(crate) fn new(session: Box<dyn AsyncFileWriteSession>, provider: &str, path: Option<Path>) -> Self {
Self {
session: Box::into_pin(session),
state: RecoveryCleanupState::Pending,
provider: provider.into(),
path,
}
}
pub const fn cleanup_state(&self) -> RecoveryCleanupState {
self.state
}
pub fn abort_async(&mut self) -> SpiFuture<'_, FsResult<WriteAbortOutcome>> {
Box::pin(async move {
if self.state == RecoveryCleanupState::Completed {
return Err(self.contextual_error(FsError::new(
FsErrorKind::InvalidState,
FsOperation::AbortWriter,
"isolated session cleanup already completed",
)));
}
let mut guard = RecoveryCleanupGuard::start(&mut self.state);
let result = self.session.as_mut().abort_async().await;
guard.finish(matches!(
&result,
Ok(WriteAbortOutcome::NotPublished | WriteAbortOutcome::Published)
));
drop(guard);
result.map_err(|error| self.contextual_error(error))
})
}
fn contextual_error(&self, error: FsError) -> FsError {
error.with_trusted_cleanup_context(FsOperation::AbortWriter, self.path.as_ref(), &self.provider)
}
}
impl Debug for RejectedAsyncWriter {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("RejectedAsyncWriter")
.field("cleanup_state", &self.state)
.finish_non_exhaustive()
}
}