You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yuurei/src/state/local/karada.rs

102 lines
3.1 KiB

//! Mutating post body
use super::*;
/// A message that can be mutated by deltas.
pub type MessageSpan = Vec<char>;
/// Contains post deltas and an intermediate representation of the still-open post body.
/// Created and modified with `Kokoro` worker instances.
///
/// This should not be created by itself, instead `Kokoro` should create instances of this, so that it can retain the `watch::Sender` and other such things.
#[derive(Debug)]
pub struct Karada
{
/// The post body so far as a vector of `char`s.
pub(super) scape: Arc<RwLock<MessageSpan>>,
/// All applied deltas so far. Last applied one is at the end.
pub(super) deltas: Arc<RwLock<Vec<Delta>>>,
/// the latest render of the whole body string. Updated whenever a delta(s) are applied atomically.
pub(super) current_body: watch::Receiver<String>,
}
impl Karada
{
/// Clone the body string
pub fn body(&self) -> String
{
self.current_body.borrow().to_owned()
}
/// Create the deltas required to atomically transform current body into `new`.
///
/// Return the number of deltas added to `output`.
pub fn create_body_deltas<T: BackInserter<Delta> + ?Sized, U: AsRef<str>>(&self, output: &mut T, new: U) -> usize
{
let body = self.body();
let new = new.as_ref();
delta::infer_deltas(output, &body[..], new)
}
/// Consume this instance into a suspension
///
/// This will only acquire locks if needed, but since they might be needed, it must be awaited in case of `Kokoro` instances potentially owning the data.
pub async fn into_suspended(self) -> Suspension
{
let scape: String = {
let scape = self.scape;
match Arc::try_unwrap(scape) { //try to unwrap if possible, to avoid acquiring useless lock
Ok(scape) => scape.into_inner().into_iter().collect(),
Err(scape) => scape.read().await.iter().collect(),
}
};
let deltas: Vec<Delta> = {
let deltas = self.deltas;
match Arc::try_unwrap(deltas) {
Ok(deltas) => deltas.into_inner(),
Err(deltas) => deltas.read().await.clone(),
}
};
Suspension{scape,deltas}
}
pub(super) fn from_suspended(susp: Suspension, current_body: watch::Receiver<String>) -> Self
{
Self {
scape: Arc::new(RwLock::new(susp.scape.chars().collect())),
deltas: Arc::new(RwLock::new(susp.deltas)),
current_body,
}
}
}
/// Suspension of [`Karada`](Karada).
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Suspension
{
pub(super) scape: String,
pub(super) deltas: Vec<Delta>,
}
use suspend::{
Suspendable,
SuspendStream,
};
#[async_trait]
impl Suspendable for Suspension
{
async fn suspend<S: SuspendStream +Send+Sync + ?Sized>(self, into: &mut S) -> Result<(), suspend::Error>
{
let mut output = suspend::Object::new();
output.insert("post-dynamic", self);
into.set_object(output).await
}
async fn load<S: SuspendStream +Send+Sync+ ?Sized>(from: &mut S) -> Result<Self, suspend::Error>
{
let mut input = from.get_object().await?.ok_or(suspend::Error::BadObject)?;
input.try_get("post-dynamic").ok_or(suspend::Error::BadObject)
}
}