use std::ops::Deref;
use std::sync::Arc;
use tokio::sync::Mutex;
use crate::error::Error;
use crate::json::{Patch, Value};
use crate::result::Result;
use crate::sync::Sender;
#[derive(Clone)]
struct Checkpoint<T>(Arc<Mutex<Option<T>>>);
impl<T> Default for Checkpoint<T> {
fn default() -> Self {
Self(Arc::new(Mutex::new(None)))
}
}
impl<T> Deref for Checkpoint<T> {
type Target = Mutex<Option<T>>;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
#[derive(Clone)]
pub struct Channel {
sender: Option<Sender<Patch>>,
checkpoint: Checkpoint<Value>,
}
impl std::fmt::Debug for Channel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut dbg = f.debug_struct("Channel");
dbg.field(
"sender",
if self.sender.is_some() {
&"attached"
} else {
&"detached"
},
);
match self.checkpoint.try_lock() {
Ok(guard) => dbg.field("checkpoint", &*guard),
Err(_) => dbg.field("checkpoint", &"locked"),
};
dbg.finish()
}
}
impl Channel {
pub fn is_detached(&self) -> bool {
self.sender.is_none()
}
pub fn detached() -> Self {
Self {
sender: None,
checkpoint: Checkpoint::default(),
}
}
pub async fn send(&self, changes: Patch) -> Result<()> {
if let Some(sender) = self.sender.as_ref() {
sender.send(changes).await.map_err(Error::internal)?;
}
Ok(())
}
pub async fn send_and_commit(&self, changes: Patch, new_checkpoint: Value) -> Result<()> {
if let Some(sender) = self.sender.as_ref() {
sender.send(changes).await.map_err(Error::internal)?;
*self.checkpoint.lock().await = Some(new_checkpoint);
}
Ok(())
}
pub async fn checkpoint(&self) -> Option<Value> {
self.checkpoint.lock().await.clone()
}
}
impl From<Sender<Patch>> for Channel {
fn from(sender: Sender<Patch>) -> Self {
Self {
sender: Some(sender),
checkpoint: Checkpoint::default(),
}
}
}