use std::fmt;
use std::sync::Mutex;
use kcode_k1_objects::{K1Objects, TxId};
use kcode_k1_web_package::SourcePackage;
const SOURCE_PACKAGE_FILE_TYPE: &str = "k1-web-source-package-v1";
pub struct SourceObjectCapture<'a> {
objects: &'a K1Objects,
captured: Mutex<Option<TxId>>,
}
impl<'a> SourceObjectCapture<'a> {
pub fn new(objects: &'a K1Objects) -> Self {
Self {
objects,
captured: Mutex::new(None),
}
}
pub fn preserve(&self, package: &SourcePackage) -> Result<(), String> {
let bytes = kcode_k1_web_transaction::encode(package).map_err(|error| error.to_string())?;
let mut captured = self
.captured
.lock()
.map_err(|_| CaptureStateError::Poisoned.to_string())?;
let id = self
.objects
.save("", SOURCE_PACKAGE_FILE_TYPE, "", &bytes)?;
*captured = Some(id);
Ok(())
}
pub fn captured(&self) -> Option<TxId> {
self.captured.lock().ok().and_then(|captured| *captured)
}
pub fn finish(self) -> Result<TxId, CaptureStateError> {
self.captured
.into_inner()
.map_err(|_| CaptureStateError::Poisoned)?
.ok_or(CaptureStateError::Missing)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CaptureStateError {
Poisoned,
Missing,
}
impl fmt::Display for CaptureStateError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::Poisoned => "source object capture mutex poisoned",
Self::Missing => "publication completed without a captured source object",
})
}
}
impl std::error::Error for CaptureStateError {}
#[cfg(test)]
mod tests {
use super::CaptureStateError;
#[test]
fn capture_state_errors_have_stable_messages() {
assert_eq!(
CaptureStateError::Poisoned.to_string(),
"source object capture mutex poisoned"
);
assert_eq!(
CaptureStateError::Missing.to_string(),
"publication completed without a captured source object"
);
}
}