mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-22 15:24:48 +01:00
feat: internally mutable
Co-authored-by: zaaarf <me@zaaarf.foo>
This commit is contained in:
parent
4de09cb164
commit
cd8f7cd5c5
2 changed files with 38 additions and 33 deletions
|
@ -9,10 +9,11 @@ use tokio::sync::{mpsc, watch};
|
||||||
use tonic::async_trait;
|
use tonic::async_trait;
|
||||||
|
|
||||||
use crate::api::Controller;
|
use crate::api::Controller;
|
||||||
use crate::errors::IgnorableError;
|
|
||||||
|
|
||||||
use crate::api::TextChange;
|
use crate::api::TextChange;
|
||||||
|
|
||||||
|
use super::tools::InternallyMutable;
|
||||||
|
|
||||||
/// the buffer controller implementation
|
/// the buffer controller implementation
|
||||||
///
|
///
|
||||||
/// for each controller a worker exists, managing outgoing and inbound
|
/// for each controller a worker exists, managing outgoing and inbound
|
||||||
|
@ -29,7 +30,7 @@ pub struct BufferController(Arc<BufferControllerInner>);
|
||||||
struct BufferControllerInner {
|
struct BufferControllerInner {
|
||||||
name: String,
|
name: String,
|
||||||
content: watch::Receiver<String>,
|
content: watch::Receiver<String>,
|
||||||
seen: StatusCheck<String>, // internal buffer previous state
|
seen: InternallyMutable<String>, // internal buffer previous state
|
||||||
operations: mpsc::UnboundedSender<TextChange>,
|
operations: mpsc::UnboundedSender<TextChange>,
|
||||||
poller: mpsc::UnboundedSender<oneshot::Sender<()>>,
|
poller: mpsc::UnboundedSender<oneshot::Sender<()>>,
|
||||||
_stop: Arc<StopOnDrop>, // just exist
|
_stop: Arc<StopOnDrop>, // just exist
|
||||||
|
@ -73,6 +74,7 @@ impl Drop for StopOnDrop {
|
||||||
self.0
|
self.0
|
||||||
.send(())
|
.send(())
|
||||||
.unwrap_or_warn("could not send stop message to worker");
|
.unwrap_or_warn("could not send stop message to worker");
|
||||||
|
seen: InternallyMutable::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ impl Controller<TextChange> for BufferController {
|
||||||
/// block until a text change is available
|
/// block until a text change is available
|
||||||
/// this returns immediately if one is already available
|
/// this returns immediately if one is already available
|
||||||
async fn poll(&self) -> crate::Result<()> {
|
async fn poll(&self) -> crate::Result<()> {
|
||||||
if self.0.seen.check() != *self.0.content.borrow() {
|
if self.0.seen.get() != *self.0.content.borrow() {
|
||||||
return Ok(()); // short circuit: already available!
|
return Ok(()); // short circuit: already available!
|
||||||
}
|
}
|
||||||
let (tx, rx) = oneshot::channel::<()>();
|
let (tx, rx) = oneshot::channel::<()>();
|
||||||
|
@ -93,57 +95,33 @@ impl Controller<TextChange> for BufferController {
|
||||||
|
|
||||||
/// if a text change is available, return it immediately
|
/// if a text change is available, return it immediately
|
||||||
fn try_recv(&self) -> crate::Result<Option<TextChange>> {
|
fn try_recv(&self) -> crate::Result<Option<TextChange>> {
|
||||||
let seen = self.0.seen.check();
|
let seen = self.0.seen.get();
|
||||||
let actual = self.0.content.borrow().clone();
|
let actual = self.0.content.borrow().clone();
|
||||||
if seen == actual {
|
if seen == actual {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let change = TextChange::from_diff(&seen, &actual);
|
let change = TextChange::from_diff(&seen, &actual);
|
||||||
self.0.seen.update(actual);
|
self.0.seen.set(actual);
|
||||||
Ok(Some(change))
|
Ok(Some(change))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// block until a new text change is available, and return it
|
/// block until a new text change is available, and return it
|
||||||
async fn recv(&self) -> crate::Result<TextChange> {
|
async fn recv(&self) -> crate::Result<TextChange> {
|
||||||
self.poll().await?;
|
self.poll().await?;
|
||||||
let seen = self.0.seen.check();
|
let seen = self.0.seen.get();
|
||||||
let actual = self.0.content.borrow().clone();
|
let actual = self.0.content.borrow().clone();
|
||||||
let change = TextChange::from_diff(&seen, &actual);
|
let change = TextChange::from_diff(&seen, &actual);
|
||||||
self.0.seen.update(actual);
|
self.0.seen.set(actual);
|
||||||
Ok(change)
|
Ok(change)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// enqueue a text change for processing
|
/// enqueue a text change for processing
|
||||||
/// this also updates internal buffer previous state
|
/// this also updates internal buffer previous state
|
||||||
fn send(&self, op: TextChange) -> crate::Result<()> {
|
fn send(&self, op: TextChange) -> crate::Result<()> {
|
||||||
let before = self.0.seen.check();
|
let before = self.0.seen.get();
|
||||||
self.0.seen.update(op.apply(&before));
|
self.0.seen.set(op.apply(&before));
|
||||||
Ok(self.0.operations.send(op)?)
|
Ok(self.0.operations.send(op)?)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct StatusCheck<T: Clone> {
|
|
||||||
state: watch::Receiver<T>,
|
|
||||||
updater: Arc<watch::Sender<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone + Default> Default for StatusCheck<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
let (tx, rx) = watch::channel(T::default());
|
|
||||||
StatusCheck {
|
|
||||||
state: rx,
|
|
||||||
updater: Arc::new(tx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> StatusCheck<T> {
|
|
||||||
fn update(&self, state: T) -> T {
|
|
||||||
self.updater.send_replace(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check(&self) -> T {
|
|
||||||
self.state.borrow().clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,3 +48,30 @@ pub async fn select_buffer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// wraps sender and receiver to allow mutable field with immutable ref
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InternallyMutable<T: Clone> {
|
||||||
|
getter: tokio::sync::watch::Receiver<T>,
|
||||||
|
setter: tokio::sync::watch::Sender<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Default> Default for InternallyMutable<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
let (tx, rx) = tokio::sync::watch::channel(T::default());
|
||||||
|
InternallyMutable {
|
||||||
|
getter: rx,
|
||||||
|
setter: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> InternallyMutable<T> {
|
||||||
|
pub fn set(&self, state: T) -> T {
|
||||||
|
self.setter.send_replace(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> T {
|
||||||
|
self.getter.borrow().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue