use alloc::vec::Vec;
use super::{Binding, ServerError};
use crate::runtime::memory_management::ErrorGraph;
#[derive(Debug)]
#[must_use]
pub struct WriteScope {
written: Vec<Binding>,
provisional: Option<ErrorGraph>,
armed: bool,
}
impl WriteScope {
pub fn new(written: Vec<Binding>) -> Self {
let mut scope = Self::deferred(written);
scope.enter();
scope
}
pub fn deferred(written: Vec<Binding>) -> Self {
Self { written, provisional: None, armed: true }
}
pub fn enter(&mut self) {
if !self.armed || self.provisional.is_some() { return; }
for binding in &self.written {
if binding.range().is_ok_and(|range| !range.is_empty() || !binding.memory.is_allocated()) {
let root = self.provisional.get_or_insert_with(|| ErrorGraph::new(ServerError::TornDown));
binding.claim(root.clone());
}
}
}
pub fn bindings(&self) -> &[Binding] { &self.written }
pub fn complete(mut self) {
self.enter();
self.armed = false;
if let Some(root) = self.provisional.take() {
for binding in &self.written { binding.release(root.id()); }
}
}
pub fn fail(mut self, error: ServerError) -> ServerError {
self.enter();
self.armed = false;
if let Some(root) = self.provisional.take() { root.replace(error.clone()); }
error
}
pub fn finish(self, result: Result<(), ServerError>) -> Result<(), ServerError> {
match result {
Ok(()) => { self.complete(); Ok(()) }
Err(error) => Err(self.fail(error)),
}
}
}
impl Drop for WriteScope {
fn drop(&mut self) {
if self.armed { self.enter(); }
}
}