use std::{
io::{self, Stderr, Stdout, Write},
sync::{RwLock, RwLockWriteGuard},
};
use crate::{
backend::{Backend as _, BackendImpl},
error, Action, Retrieved, Value,
};
pub fn stdout() -> Terminal<Stdout> {
Terminal::custom(io::stdout())
}
pub fn stderr() -> Terminal<Stderr> {
Terminal::custom(io::stderr())
}
pub struct Terminal<W: Write> {
lock: RwLock<BackendImpl<W>>,
}
impl<W: Write> Terminal<W> {
pub fn custom(buffer: W) -> Terminal<W> {
Terminal {
lock: RwLock::new(BackendImpl::create(buffer)),
}
}
pub fn lock_mut(&self) -> error::Result<TerminalLock<'_, W>> {
if let Ok(lock) = self.lock.try_write() {
Ok(TerminalLock::new(lock))
} else {
Err(error::ErrorKind::AttemptToAcquireLock(
"`Terminal` can only be mutably borrowed once.".to_string(),
))
}
}
pub fn act(&self, action: Action) -> error::Result<()> {
let mut lock = self.lock_mut()?;
lock.act(action)
}
pub fn batch(&self, action: Action) -> error::Result<()> {
let mut lock = self.lock_mut()?;
lock.batch(action)
}
pub fn flush_batch(&self) -> error::Result<()> {
let mut lock = self.lock_mut()?;
lock.flush_batch()
}
pub fn get(&self, value: Value) -> error::Result<Retrieved> {
let lock = self.lock_mut()?;
lock.get(value)
}
}
impl<'a, W: Write> Write for Terminal<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut lock = self.lock_mut().unwrap();
lock.backend.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
let mut lock = self.lock_mut().unwrap();
lock.backend.flush()
}
}
pub struct TerminalLock<'a, W: Write> {
backend: RwLockWriteGuard<'a, BackendImpl<W>>,
}
impl<'a, W: Write> TerminalLock<'a, W> {
pub fn new(locked_backend: RwLockWriteGuard<'a, BackendImpl<W>>) -> TerminalLock<'a, W> {
TerminalLock {
backend: locked_backend,
}
}
pub fn act(&mut self, action: Action) -> error::Result<()> {
self.backend.act(action)
}
pub fn batch(&mut self, action: Action) -> error::Result<()> {
self.backend.batch(action)
}
pub fn flush_batch(&mut self) -> error::Result<()> {
self.backend.flush_batch()
}
pub fn get(&self, value: Value) -> error::Result<Retrieved> {
self.backend.get(value)
}
}
impl<'a, W: Write> Write for TerminalLock<'a, W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.backend.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.backend.flush()
}
}