use std::io;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, PoisonError};
use super::arbiter::{Ephemeral, LineLease, LineWriter, Sink, Terminal};
use super::caps::LineCaps;
pub(crate) struct EphemeralRow {
lease: LineLease,
pub(super) paint_gate: Mutex<()>,
finished: AtomicBool,
}
impl EphemeralRow {
pub(crate) fn acquire(caps: LineCaps, sink: Sink) -> Option<Arc<Self>> {
let lease = Terminal::lease_with_caps(caps, sink)?;
let row = Arc::new(Self {
lease,
paint_gate: Mutex::new(()),
finished: AtomicBool::new(false),
});
let as_ephemeral: Arc<dyn Ephemeral> = row.clone();
Terminal::register(
Arc::as_ptr(&row) as *const () as usize as u64,
&as_ephemeral,
);
Some(row)
}
pub(crate) fn paint(&self, f: impl FnOnce(&mut LineWriter<'_>) -> io::Result<()>) {
let _gate = self
.paint_gate
.lock()
.unwrap_or_else(PoisonError::into_inner);
if self.finished.load(Ordering::SeqCst) {
return;
}
self.lease.paint(f);
}
pub(crate) fn emit_line(&self, f: impl FnOnce(&mut LineWriter<'_>) -> io::Result<()>) {
self.lease.emit_line(f);
}
pub(crate) fn finish(&self, before_erase: impl FnOnce(&Self)) {
let _gate = self
.paint_gate
.lock()
.unwrap_or_else(PoisonError::into_inner);
if self.finished.swap(true, Ordering::SeqCst) {
return;
}
before_erase(self);
self.lease.erase();
}
#[cfg(test)]
pub(super) fn is_finished(&self) -> bool {
self.finished.load(Ordering::SeqCst)
}
}
impl Ephemeral for EphemeralRow {
fn erase(&self) {
let _gate = self
.paint_gate
.lock()
.unwrap_or_else(PoisonError::into_inner);
self.lease.erase();
}
fn restore(&self) {
}
}