Skip to content

Commit

Permalink
feat: encode doc into binary (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
thorseraq authored May 25, 2023
1 parent bc63b9a commit 4faa5df
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 1 deletion.
20 changes: 20 additions & 0 deletions libs/jwst-codec/src/doc/codec/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ mod tests {
use super::*;
use serde::Deserialize;
use std::{num::ParseIntError, path::PathBuf};
use yrs::{Map, Transact};

fn struct_item(id: (Client, Clock), len: usize) -> StructInfo {
StructInfo::Item {
Expand Down Expand Up @@ -581,4 +582,23 @@ mod tests {
&OrderRange::from(vec![(10..12), (13..15)])
);
}

#[test]
fn double_run_test_with_yrs_basic() {
let yrs_doc = yrs::Doc::new();

let map = yrs_doc.get_or_insert_map("abc");
let mut trx = yrs_doc.transact_mut();
map.insert(&mut trx, "a", 1).unwrap();

let binary_from_yrs = trx.encode_update_v1().unwrap();

let mut decoder = RawDecoder::new(binary_from_yrs.clone());
let update = Update::read(&mut decoder).unwrap();
let mut doc = Doc::default();
doc.apply_update(update).unwrap();
let binary = doc.encode_update_v1().unwrap();

assert_eq!(binary_from_yrs, binary);
}
}
8 changes: 8 additions & 0 deletions libs/jwst-codec/src/doc/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,4 +416,12 @@ impl Doc {
Ok(())
})
}

pub fn encode_update_v1(self) -> JwstCodecResult<Vec<u8>> {
let store = self.store;
let mut encoder = RawEncoder::default();
store.encode_with_state_vector(&StateVector::default(), &mut encoder)?;

Ok(encoder.into_inner())
}
}
91 changes: 90 additions & 1 deletion libs/jwst-codec/src/doc/store.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use crate::doc::StateVector;
use std::collections::VecDeque;
use std::{
cell::{Ref, RefCell, RefMut},
collections::{hash_map::Entry, HashMap},
Expand All @@ -10,6 +11,21 @@ use std::{
#[derive(Clone, PartialEq, Debug)]
pub struct StructRef(Arc<RefCell<StructInfo>>);

impl StructRef {
pub fn read<R: CrdtReader>(decoder: &mut R, id: Id) -> JwstCodecResult<Self> {
match StructInfo::read(decoder, id) {
Ok(info) => Ok(info.into()),
Err(err) => Err(err),
}
}
}

impl<W: CrdtWriter> CrdtWrite<W> for StructRef {
fn write(&self, writer: &mut W) -> JwstCodecResult {
self.0.borrow().write(writer)
}
}

impl From<StructInfo> for StructRef {
fn from(info: StructInfo) -> Self {
Self(Arc::new(RefCell::new(info)))
Expand Down Expand Up @@ -91,8 +107,10 @@ impl StructRef {
#[derive(Default)]
pub struct DocStore {
pub items: Arc<RwLock<HashMap<Client, Vec<StructRef>>>>,
pub types: Arc<RwLock<HashMap<String, TypeStoreRef>>>,
pub delete_set: Arc<RwLock<DeleteSet>>,

// following fields are only used in memory
pub types: Arc<RwLock<HashMap<String, TypeStoreRef>>>,
pub pending: Option<Update>,
}

Expand Down Expand Up @@ -361,6 +379,77 @@ impl DocStore {
delete_set.add(id.client, id.clock, len)
}
}

fn diff_state_vectors(
local_state_vector: &StateVector,
remote_state_vector: &StateVector,
) -> Vec<(Client, Clock)> {
let mut diff = Vec::new();

for (client, &remote_clock) in remote_state_vector.iter() {
let local_clock = local_state_vector.get(client);
if local_clock > remote_clock {
diff.push((*client, remote_clock));
}
}

for (client, _) in local_state_vector.iter() {
if remote_state_vector.get(client) == 0 {
diff.push((*client, 0));
}
}

diff
}

pub fn encode_with_state_vector<W: CrdtWriter>(
&self,
sv: &StateVector,
encoder: &mut W,
) -> JwstCodecResult {
let local_state_vector = self.get_state_vector();
let diff = Self::diff_state_vectors(&local_state_vector, sv);
let mut update_structs: HashMap<u64, VecDeque<StructInfo>> = HashMap::new();

for (client, clock) in diff {
// We have made sure that the client is in the local state vector in diff_state_vectors()
if let Some(items) = self.items.read().unwrap().get(&client) {
if items.is_empty() {
continue;
}

update_structs.insert(client, VecDeque::new());
let vec_struct_info = update_structs.get_mut(&client).unwrap();

// the smallest clock in items may exceed the clock
let clock = items.first().unwrap().id().clock.max(clock);
if let Some(index) = Self::get_item_index(items, clock) {
let first_block = items.get(index).unwrap();
let offset = first_block.clock() - clock;
if offset != 0 {
// needs to implement Content split first
unimplemented!()
} else {
vec_struct_info.push_back(first_block.borrow().clone());
}

for item in items.iter().skip(index + 1) {
vec_struct_info.push_back(item.borrow().clone());
}
}
}
}

let update = Update {
structs: update_structs,
delete_set: self.delete_set.read().unwrap().clone(),
..Update::default()
};

update.write(encoder)?;

Ok(())
}
}

#[cfg(test)]
Expand Down

1 comment on commit 4faa5df

@vercel
Copy link

@vercel vercel bot commented on 4faa5df May 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.