Merge pull request from automerge/two-level-objtype

Two level objtype
This commit is contained in:
Orion Henry 2020-05-26 07:08:00 -07:00 committed by GitHub
commit dd33e528ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 397 additions and 323 deletions

View file

@ -77,12 +77,12 @@ impl ActorMap {
}
}
pub fn export_actor(&self, actor: &ActorID) -> amp::ActorID {
pub fn export_actor(&self, actor: ActorID) -> amp::ActorID {
self.0[actor.0].clone()
}
pub fn export_opid(&self, opid: &OpID) -> amp::OpID {
amp::OpID(opid.0, self.export_actor(&opid.1))
amp::OpID(opid.0, self.export_actor(opid.1))
}
pub fn export_obj(&self, obj: &ObjectID) -> amp::ObjectID {
@ -151,7 +151,7 @@ impl ActorMap {
}
pub fn opid_to_string(&self, id: &OpID) -> String {
format!("{}@{}", id.0, self.export_actor(&id.1).to_hex_string())
format!("{}@{}", id.0, self.export_actor(id.1).to_hex_string())
}
pub fn elementid_to_string(&self, eid: &ElementID) -> String {

View file

@ -127,10 +127,10 @@ impl Backend {
let internal_key = self.actors.import_key(external_key.clone());
let pred = op_set.get_pred(&internal_object_id, &internal_key, insert);
let action = match rop.action {
amp::OpType::MakeMap => OpType::Make(amp::ObjType::Map),
amp::OpType::MakeTable => OpType::Make(amp::ObjType::Table),
amp::OpType::MakeList => OpType::Make(amp::ObjType::List),
amp::OpType::MakeText => OpType::Make(amp::ObjType::Text),
amp::OpType::MakeMap => OpType::Make(amp::ObjType::map()),
amp::OpType::MakeTable => OpType::Make(amp::ObjType::table()),
amp::OpType::MakeList => OpType::Make(amp::ObjType::list()),
amp::OpType::MakeText => OpType::Make(amp::ObjType::text()),
amp::OpType::Del => OpType::Del,
amp::OpType::Link => OpType::Link(
child

View file

@ -415,7 +415,7 @@ mod tests {
pred: vec![opid3.clone(), opid4.clone()],
},
Operation {
action: OpType::Make(amp::ObjType::List),
action: OpType::Make(amp::ObjType::list()),
key: key2.clone(),
obj: obj2.clone(),
insert,

View file

@ -229,10 +229,10 @@ impl<'a> Iterator for OperationIterator<'a> {
let child = self.chld.next()?;
let action = match action {
Action::Set => OpType::Set(value),
Action::MakeList => OpType::Make(amp::ObjType::List),
Action::MakeText => OpType::Make(amp::ObjType::Text),
Action::MakeMap => OpType::Make(amp::ObjType::Map),
Action::MakeTable => OpType::Make(amp::ObjType::Table),
Action::MakeList => OpType::Make(amp::ObjType::list()),
Action::MakeText => OpType::Make(amp::ObjType::text()),
Action::MakeMap => OpType::Make(amp::ObjType::map()),
Action::MakeTable => OpType::Make(amp::ObjType::table()),
Action::Del => OpType::Del,
Action::Inc => OpType::Inc(value.to_i64()?),
Action::Link => OpType::Link(child),
@ -537,10 +537,10 @@ impl ColumnEncoder {
self.val.append_null();
self.chld.append_null();
match kind {
amp::ObjType::List => Action::MakeList,
amp::ObjType::Map => Action::MakeMap,
amp::ObjType::Table => Action::MakeTable,
amp::ObjType::Text => Action::MakeText,
amp::ObjType::Sequence(amp::SequenceType::List) => Action::MakeList,
amp::ObjType::Map(amp::MapType::Map) => Action::MakeMap,
amp::ObjType::Map(amp::MapType::Table) => Action::MakeTable,
amp::ObjType::Sequence(amp::SequenceType::Text) => Action::MakeText,
}
}
};

View file

@ -39,7 +39,7 @@ impl ObjState {
pub fn is_seq(&self) -> bool {
match self.obj_type {
amp::ObjType::Text | amp::ObjType::List => true,
amp::ObjType::Sequence(_) => true,
_ => false,
}
}

View file

@ -222,10 +222,14 @@ impl<'de> Deserialize<'de> for Operation {
let insert = insert.unwrap_or(false);
let value = amp::Value::from(value, datatype);
let action = match action {
amp::OpType::MakeMap => OpType::Make(amp::ObjType::Map),
amp::OpType::MakeTable => OpType::Make(amp::ObjType::Table),
amp::OpType::MakeList => OpType::Make(amp::ObjType::List),
amp::OpType::MakeText => OpType::Make(amp::ObjType::Text),
amp::OpType::MakeMap => OpType::Make(amp::ObjType::Map(amp::MapType::Map)),
amp::OpType::MakeTable => OpType::Make(amp::ObjType::Map(amp::MapType::Table)),
amp::OpType::MakeList => {
OpType::Make(amp::ObjType::Sequence(amp::SequenceType::List))
}
amp::OpType::MakeText => {
OpType::Make(amp::ObjType::Sequence(amp::SequenceType::Text))
}
amp::OpType::Del => OpType::Del,
amp::OpType::Link => {
OpType::Link(child.ok_or_else(|| Error::missing_field("pred"))?)

View file

@ -46,7 +46,7 @@ pub(crate) struct OpSet {
impl OpSet {
pub fn init() -> OpSet {
let mut objs = im_rc::HashMap::new();
objs.insert(ObjectID::Root, Rc::new(ObjState::new(amp::ObjType::Map)));
objs.insert(ObjectID::Root, Rc::new(ObjState::new(amp::ObjType::map())));
OpSet {
objs,
@ -208,6 +208,7 @@ impl OpSet {
object_id: &ObjectID,
object: &ObjState,
actors: &ActorMap,
map_type: amp::MapType,
) -> Result<amp::Diff, AutomergeError> {
let mut props = HashMap::new();
@ -227,7 +228,7 @@ impl OpSet {
}
Ok(amp::MapDiff {
object_id: actors.export_obj(object_id),
obj_type: object.obj_type,
obj_type: map_type,
props,
}
.into())
@ -238,6 +239,7 @@ impl OpSet {
object_id: &ObjectID,
object: &ObjState,
actors: &ActorMap,
seq_type: amp::SequenceType,
) -> Result<amp::Diff, AutomergeError> {
let mut edits = Vec::new();
let mut props = HashMap::new();
@ -267,7 +269,7 @@ impl OpSet {
}
Ok(amp::SeqDiff {
object_id: actors.export_obj(object_id),
obj_type: object.obj_type,
obj_type: seq_type,
edits,
props,
}
@ -280,10 +282,11 @@ impl OpSet {
actors: &ActorMap,
) -> Result<amp::Diff, AutomergeError> {
let object = self.get_obj(&object_id)?;
if object.is_seq() {
self.construct_list(object_id, object, actors)
} else {
self.construct_map(object_id, object, actors)
match object.obj_type {
amp::ObjType::Map(map_type) => self.construct_map(object_id, object, actors, map_type),
amp::ObjType::Sequence(seq_type) => {
self.construct_list(object_id, object, actors, seq_type)
}
}
}
@ -325,6 +328,7 @@ impl OpSet {
pending: &[PendingDiff],
pending_diffs: &mut HashMap<ObjectID, Vec<PendingDiff>>,
actors: &ActorMap,
seq_type: amp::SequenceType,
) -> Result<amp::Diff, AutomergeError> {
let mut props = HashMap::new();
let edits = pending.iter().filter_map(|p| p.edit()).collect();
@ -352,7 +356,7 @@ impl OpSet {
}
Ok(amp::SeqDiff {
object_id: actors.export_obj(obj_id),
obj_type: obj.obj_type,
obj_type: seq_type,
edits,
props,
}
@ -366,6 +370,7 @@ impl OpSet {
pending: &[PendingDiff],
pending_diffs: &mut HashMap<ObjectID, Vec<PendingDiff>>,
actors: &ActorMap,
map_type: amp::MapType,
) -> Result<amp::Diff, AutomergeError> {
let mut props = HashMap::new();
// I may have duplicate keys - I do this to make sure I visit each one only once
@ -391,7 +396,7 @@ impl OpSet {
}
Ok(amp::MapDiff {
object_id: actors.export_obj(obj_id),
obj_type: obj.obj_type,
obj_type: map_type,
props,
}
.into())
@ -405,10 +410,13 @@ impl OpSet {
) -> Result<amp::Diff, AutomergeError> {
let obj = self.get_obj(obj_id)?;
if let Some(pending) = pending_diffs.remove(obj_id) {
if obj.is_seq() {
self.gen_seq_diff(obj_id, obj, &pending, pending_diffs, actors)
} else {
self.gen_map_diff(obj_id, obj, &pending, pending_diffs, actors)
match obj.obj_type {
amp::ObjType::Sequence(seq_type) => {
self.gen_seq_diff(obj_id, obj, &pending, pending_diffs, actors, seq_type)
}
amp::ObjType::Map(map_type) => {
self.gen_map_diff(obj_id, obj, &pending, pending_diffs, actors, map_type)
}
}
} else {
Ok(amp::Diff::Unchanged(amp::ObjDiff {

View file

@ -16,10 +16,10 @@ impl Serialize for OpType {
S: Serializer,
{
let s = match self {
OpType::Make(amp::ObjType::Map) => "makeMap",
OpType::Make(amp::ObjType::Table) => "makeTable",
OpType::Make(amp::ObjType::List) => "makeList",
OpType::Make(amp::ObjType::Text) => "makeText",
OpType::Make(amp::ObjType::Map(amp::MapType::Map)) => "makeMap",
OpType::Make(amp::ObjType::Map(amp::MapType::Table)) => "makeTable",
OpType::Make(amp::ObjType::Sequence(amp::SequenceType::List)) => "makeList",
OpType::Make(amp::ObjType::Sequence(amp::SequenceType::Text)) => "makeText",
OpType::Del => "del",
OpType::Link(_) => "link",
OpType::Inc(_) => "inc",

View file

@ -2,8 +2,8 @@ extern crate automerge_backend;
use automerge_backend::{AutomergeError, Backend, UnencodedChange};
use automerge_backend::{OpType, Operation};
use automerge_protocol::{
ActorID, Diff, DiffEdit, ElementID, Key, MapDiff, ObjDiff, ObjType, ObjectID, Patch, SeqDiff,
Value,
ActorID, Diff, DiffEdit, ElementID, Key, MapDiff, MapType, ObjDiff, ObjType, ObjectID, Patch,
SeqDiff, SequenceType, Value,
};
use maplit::hashmap;
use std::convert::TryInto;
@ -39,7 +39,7 @@ fn test_incremental_diffs_in_a_map() {
can_redo: false,
diffs: Some(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!( "bird".into() => hashmap!( "1@7b7723afd9e6480397a4d467b7693156".try_into().unwrap() => "magpie".into() ))
}.into()),
};
@ -91,7 +91,7 @@ fn test_increment_key_in_map() -> Result<(), AutomergeError> {
diffs: Some(
MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!(
"counter".into() => hashmap!{
"1@cdee6963c1664645920be8b41a933c2b".try_into().unwrap() => Value::Counter(3).into(),
@ -155,7 +155,7 @@ fn test_conflict_on_assignment_to_same_map_key() {
diffs: Some(
MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!( "bird".into() => hashmap!(
"1@ac11".try_into().unwrap() => "magpie".into(),
"2@ac22".try_into().unwrap() => "blackbird".into(),
@ -218,7 +218,7 @@ fn delete_key_from_map() {
can_redo: false,
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"bird".into() => hashmap!{}
},
@ -243,7 +243,7 @@ fn create_nested_maps() {
message: None,
operations: vec![
Operation {
action: OpType::Make(ObjType::Map),
action: OpType::Make(ObjType::Map(MapType::Map)),
obj: ObjectID::Root,
key: Key::Map("birds".into()),
pred: Vec::new(),
@ -270,12 +270,12 @@ fn create_nested_maps() {
version: 1,
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@d6226fcd55204b82b396f2473da3e26f".try_into().unwrap() => Diff::Map(MapDiff{
object_id: "1@d6226fcd55204b82b396f2473da3e26f".try_into().unwrap(),
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!{
"wrens".into() => hashmap!{
"2@d6226fcd55204b82b396f2473da3e26f".try_into().unwrap() => Diff::Value(Value::F64(3.0))
@ -304,7 +304,7 @@ fn test_assign_to_nested_keys_in_map() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::Map),
action: OpType::Make(ObjType::Map(MapType::Map)),
obj: ObjectID::Root,
key: "birds".into(),
pred: Vec::new(),
@ -350,12 +350,12 @@ fn test_assign_to_nested_keys_in_map() {
deps: vec![change2.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@3c39c994039042778f4779a01a59a917".try_into().unwrap() => Diff::Map(MapDiff{
object_id: "1@3c39c994039042778f4779a01a59a917".try_into().unwrap(),
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!{
"sparrows".into() => hashmap!{
"3@3c39c994039042778f4779a01a59a917".try_into().unwrap() => Diff::Value(Value::F64(15.0))
@ -384,7 +384,7 @@ fn test_create_lists() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "birds".into(),
pred: Vec::new(),
@ -413,12 +413,12 @@ fn test_create_lists() {
deps: vec![change.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@f82cb62dabe64372ab87466b77792010".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@f82cb62dabe64372ab87466b77792010".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: vec![DiffEdit::Insert{ index: 0 }],
props: hashmap!{
0 => hashmap!{
@ -448,7 +448,7 @@ fn test_apply_updates_inside_lists() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "birds".into(),
pred: Vec::new(),
@ -494,12 +494,12 @@ fn test_apply_updates_inside_lists() {
seq: None,
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@4ee4a0d033b841c4b26d73d70a879547".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@4ee4a0d033b841c4b26d73d70a879547".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: Vec::new(),
props: hashmap!{
0 => hashmap!{
@ -530,7 +530,7 @@ fn test_delete_list_elements() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "birds".into(),
pred: Vec::new(),
@ -578,12 +578,12 @@ fn test_delete_list_elements() {
deps: vec![change2.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@8a3d4716fdca49f4aa5835901f2034c7".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@8a3d4716fdca49f4aa5835901f2034c7".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
props: hashmap!{},
edits: vec![DiffEdit::Remove{index: 0}]
})
@ -609,7 +609,7 @@ fn test_handle_list_element_insertion_and_deletion_in_same_change() {
message: None,
deps: Vec::new(),
operations: vec![Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "birds".into(),
pred: Vec::new(),
@ -658,12 +658,12 @@ fn test_handle_list_element_insertion_and_deletion_in_same_change() {
deps: vec![change2.hash, change1.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@ca95bc759404486bbe7b9dd2be779fa8".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@ca95bc759404486bbe7b9dd2be779fa8".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: vec![
DiffEdit::Insert{index: 0},
DiffEdit::Remove{index: 0},
@ -693,7 +693,7 @@ fn test_handle_changes_within_conflicted_objects() {
message: None,
deps: Vec::new(),
operations: vec![Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "conflict".into(),
pred: Vec::new(),
@ -710,7 +710,7 @@ fn test_handle_changes_within_conflicted_objects() {
message: None,
deps: Vec::new(),
operations: vec![Operation {
action: OpType::Make(ObjType::Map),
action: OpType::Make(ObjType::Map(MapType::Map)),
obj: ObjectID::Root,
key: "conflict".into(),
pred: Vec::new(),
@ -749,16 +749,16 @@ fn test_handle_changes_within_conflicted_objects() {
deps: vec![change1.hash, change3.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"conflict".into() => hashmap!{
"1@9f17517523e54ee888e9cd51dfd7a572".try_into().unwrap() => Diff::Unchanged(ObjDiff{
object_id: "1@9f17517523e54ee888e9cd51dfd7a572".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: ObjType::Sequence(SequenceType::List),
}),
"1@83768a19a13842beb6dde8c68a662fad".try_into().unwrap() => Diff::Map(MapDiff{
object_id: "1@83768a19a13842beb6dde8c68a662fad".try_into().unwrap(),
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!{
"sparrow".into() => hashmap!{
"2@83768a19a13842beb6dde8c68a662fad".try_into().unwrap() => Diff::Value(Value::F64(12.0))
@ -809,7 +809,7 @@ fn test_support_date_objects_at_root() {
deps: vec![change.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"now".into() => hashmap!{
"1@955afa3bbcc140b3b4bac8836479d650".try_into().unwrap() => Diff::Value(Value::Timestamp(1_586_528_122_277))
@ -835,7 +835,7 @@ fn test_support_date_objects_in_a_list() {
message: None,
operations: vec![
Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "list".into(),
pred: Vec::new(),
@ -864,12 +864,12 @@ fn test_support_date_objects_in_a_list() {
seq: None,
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"list".into() => hashmap!{
"1@27d467ecb1a640fb9bed448ce7cf6a44".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@27d467ecb1a640fb9bed448ce7cf6a44".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: vec![DiffEdit::Insert{index: 0}],
props: hashmap!{
0 => hashmap!{

View file

@ -3,8 +3,8 @@ use automerge_backend::{Backend, UnencodedChange};
use automerge_backend::{OpType, Operation};
use automerge_protocol as protocol;
use automerge_protocol::{
ActorID, ChangeHash, DataType, Diff, DiffEdit, ElementID, MapDiff, ObjType, ObjectID, Op,
Patch, Request, RequestType, SeqDiff,
ActorID, ChangeHash, DataType, Diff, DiffEdit, ElementID, MapDiff, MapType, ObjType, ObjectID,
Op, Patch, Request, RequestType, SeqDiff, SequenceType,
};
use maplit::hashmap;
use std::convert::TryInto;
@ -67,7 +67,7 @@ fn test_apply_local_change() {
deps: vec![changes[0].hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"bird".into() => hashmap!{
"1@eb738e04ef8848ce8b77309b6c7f7e39".try_into().unwrap() => Diff::Value("magpie".into())
@ -271,7 +271,7 @@ fn test_transform_list_indexes_into_element_ids() {
message: None,
deps: Vec::new(),
operations: vec![Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
key: "birds".into(),
obj: ObjectID::Root,
pred: Vec::new(),
@ -522,12 +522,12 @@ fn test_handle_list_insertion_and_deletion_in_same_change() {
deps: Vec::new(),
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@0723d2a1940744868ffd6b294ada813f".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@0723d2a1940744868ffd6b294ada813f".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: vec![
DiffEdit::Insert{index: 0},
DiffEdit::Remove{index: 0},
@ -559,7 +559,7 @@ fn test_handle_list_insertion_and_deletion_in_same_change() {
deps: Vec::new(),
operations: vec![Operation {
obj: ObjectID::Root,
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
key: "birds".into(),
insert: false,
pred: Vec::new(),

View file

@ -2,7 +2,8 @@ extern crate automerge_backend;
use automerge_backend::{Backend, UnencodedChange};
use automerge_backend::{OpType, Operation};
use automerge_protocol::{
ActorID, Diff, DiffEdit, ElementID, MapDiff, ObjType, ObjectID, Patch, SeqDiff, Value,
ActorID, Diff, DiffEdit, ElementID, MapDiff, MapType, ObjType, ObjectID, Patch, SeqDiff,
SequenceType, Value,
};
use maplit::hashmap;
use std::convert::TryInto;
@ -56,7 +57,7 @@ fn test_include_most_recent_value_for_key() {
deps: vec![change2.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"bird".into() => hashmap!{
"2@ec28cfbcdb9e4f32ad24b3c776e651b0".try_into().unwrap() => Diff::Value("blackbird".into())
@ -122,7 +123,7 @@ fn test_includes_conflicting_values_for_key() {
deps: vec![change1.hash, change2.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"bird".into() => hashmap!{
"1@111111".try_into().unwrap() => Diff::Value("magpie".into()),
@ -187,7 +188,7 @@ fn test_handles_counter_increment_at_keys_in_a_map() {
deps: vec![change2.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"counter".into() => hashmap!{
"1@46c92088e4484ae5945dc63bf606a4a5".try_into().unwrap() => Diff::Value(Value::Counter(3))
@ -214,7 +215,7 @@ fn test_creates_nested_maps() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::Map),
action: OpType::Make(ObjType::Map(MapType::Map)),
obj: ObjectID::Root,
key: "birds".into(),
pred: Vec::new(),
@ -269,12 +270,12 @@ fn test_creates_nested_maps() {
deps: vec![change2.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@06148f9422cb40579fd02f1975c34a51".try_into().unwrap() => Diff::Map(MapDiff{
object_id: "1@06148f9422cb40579fd02f1975c34a51".try_into().unwrap(),
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!{
"sparrows".into() => hashmap!{
"4@06148f9422cb40579fd02f1975c34a51".try_into().unwrap() => Diff::Value(Value::F64(15.0))
@ -304,7 +305,7 @@ fn test_create_lists() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "birds".into(),
pred: Vec::new(),
@ -333,12 +334,12 @@ fn test_create_lists() {
deps: vec![change1.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
"1@90bf7df682f747fa82ac604b35010906".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@90bf7df682f747fa82ac604b35010906".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: vec![DiffEdit::Insert { index :0 }],
props: hashmap!{
0 => hashmap!{
@ -369,14 +370,14 @@ fn test_includes_latests_state_of_list() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "todos".into(),
pred: Vec::new(),
insert: false,
},
Operation {
action: OpType::Make(ObjType::Map),
action: OpType::Make(ObjType::Map(MapType::Map)),
obj: "1@6caaa2e433de42ae9c3fa65c9ff3f03e".try_into().unwrap(),
key: ElementID::Head.into(),
insert: true,
@ -412,18 +413,18 @@ fn test_includes_latests_state_of_list() {
deps: vec![change1.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"todos".into() => hashmap!{
"1@6caaa2e433de42ae9c3fa65c9ff3f03e".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@6caaa2e433de42ae9c3fa65c9ff3f03e".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: vec![DiffEdit::Insert{index: 0}],
props: hashmap!{
0 => hashmap!{
"2@6caaa2e433de42ae9c3fa65c9ff3f03e".try_into().unwrap() => Diff::Map(MapDiff{
object_id: "2@6caaa2e433de42ae9c3fa65c9ff3f03e".try_into().unwrap(),
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap!{
"title".into() => hashmap!{
"3@6caaa2e433de42ae9c3fa65c9ff3f03e".try_into().unwrap() => Diff::Value("water plants".into()),
@ -479,7 +480,7 @@ fn test_includes_date_objects_at_root() {
deps: vec![change1.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"now".into() => hashmap!{
"1@90f5dd5d4f524e95ad5929e08d1194f1".try_into().unwrap() => Diff::Value(Value::Timestamp(1_586_541_033_457))
@ -506,7 +507,7 @@ fn test_includes_date_objects_in_a_list() {
deps: Vec::new(),
operations: vec![
Operation {
action: OpType::Make(ObjType::List),
action: OpType::Make(ObjType::Sequence(SequenceType::List)),
obj: ObjectID::Root,
key: "list".into(),
pred: Vec::new(),
@ -535,12 +536,12 @@ fn test_includes_date_objects_in_a_list() {
deps: vec![change1.hash],
diffs: Some(Diff::Map(MapDiff {
object_id: ObjectID::Root,
obj_type: ObjType::Map,
obj_type: MapType::Map,
props: hashmap! {
"list".into() => hashmap!{
"1@08b050f976a249349021a2e63d99c8e8".try_into().unwrap() => Diff::Seq(SeqDiff{
object_id: "1@08b050f976a249349021a2e63d99c8e8".try_into().unwrap(),
obj_type: ObjType::List,
obj_type: SequenceType::List,
edits: vec![DiffEdit::Insert {index: 0}],
props: hashmap!{
0 => hashmap!{

View file

@ -1,7 +1,9 @@
use automerge_protocol::{Diff, DiffEdit, MapDiff, ObjType, ObjectID, OpID, SeqDiff};
use automerge_protocol::{
Diff, DiffEdit, MapDiff, MapType, ObjType, ObjectID, OpID, SeqDiff, SequenceType,
};
//use crate::AutomergeFrontendError;
use crate::object::{Object, Values};
use crate::{AutomergeFrontendError, MapType, SequenceType, Value};
use crate::{AutomergeFrontendError, Value};
use std::{cell::RefCell, collections::HashMap, rc::Rc};
/// A `ChangeContext` represents some kind of change which has not been applied
@ -136,7 +138,7 @@ impl<'a> ChangeContext<'a> {
props,
}) => {
match obj_type {
ObjType::Map => {
MapType::Map => {
let obj = Self::get_or_create_object(
object_id,
original_objects,
@ -173,7 +175,7 @@ impl<'a> ChangeContext<'a> {
};
Ok(obj)
}
ObjType::Table => {
MapType::Table => {
let obj = Self::get_or_create_object(
&object_id,
original_objects,
@ -214,7 +216,6 @@ impl<'a> ChangeContext<'a> {
};
Ok(obj)
}
_ => panic!("Invalid object type (not map or table) inside MapDiff"),
}
}
Diff::Seq(SeqDiff {
@ -224,7 +225,7 @@ impl<'a> ChangeContext<'a> {
props,
}) => {
match obj_type {
ObjType::List => {
SequenceType::List => {
let obj = Self::get_or_create_object(
object_id,
original_objects,
@ -266,7 +267,7 @@ impl<'a> ChangeContext<'a> {
};
Ok(obj)
}
ObjType::Text => {
SequenceType::Text => {
let obj = Self::get_or_create_object(
&object_id,
original_objects,
@ -308,7 +309,6 @@ impl<'a> ChangeContext<'a> {
};
Ok(obj)
}
_ => panic!("Invalid object type (not map or table) inside MapDiff"),
}
}
Diff::Value(v) => Ok(Rc::new(RefCell::new(Object::Primitive(v.clone())))),
@ -319,16 +319,16 @@ impl<'a> ChangeContext<'a> {
original_objects,
updated,
|| match subdiff.obj_type {
ObjType::Map => {
ObjType::Map(MapType::Map) => {
Object::Map(object_id.clone(), HashMap::new(), MapType::Map)
}
ObjType::Table => {
ObjType::Map(MapType::Table) => {
Object::Map(object_id.clone(), HashMap::new(), MapType::Table)
}
ObjType::List => {
ObjType::Sequence(SequenceType::List) => {
Object::Sequence(object_id.clone(), Vec::new(), SequenceType::List)
}
ObjType::Text => {
ObjType::Sequence(SequenceType::Text) => {
Object::Sequence(object_id.clone(), Vec::new(), SequenceType::Text)
}
},

View file

@ -1,4 +1,4 @@
use automerge_protocol::{ActorID, ObjectID, Op, OpID, Patch, Request, RequestType};
use automerge_protocol::{ActorID, MapType, ObjectID, Op, OpID, Patch, Request, RequestType};
mod change_context;
mod error;
@ -14,7 +14,7 @@ use std::convert::TryFrom;
use std::str::FromStr;
use std::time;
use std::{collections::HashMap, rc::Rc};
pub use value::{Conflicts, MapType, SequenceType, Value};
pub use value::{Conflicts, Value};
/// Tracks the possible states of the frontend
///

View file

@ -1,6 +1,6 @@
use crate::change_context::ChangeContext;
use crate::object::Object;
use crate::value::{random_op_id, value_to_op_requests, MapType, SequenceType};
use crate::value::{random_op_id, value_to_op_requests};
use crate::{AutomergeFrontendError, Value};
use automerge_protocol as amp;
use maplit::hashmap;
@ -247,8 +247,8 @@ impl<'a, 'b> MutationTracker<'a, 'b> {
// the enclosing diffs
#[derive(Debug)]
enum Intermediate {
Map(amp::ObjectID, MapType, String, Option<amp::OpID>),
Seq(amp::ObjectID, SequenceType, usize, Option<amp::OpID>),
Map(amp::ObjectID, amp::MapType, String, Option<amp::OpID>),
Seq(amp::ObjectID, amp::SequenceType, usize, Option<amp::OpID>),
};
let mut intermediates: Vec<Intermediate> = Vec::new();
@ -265,7 +265,7 @@ impl<'a, 'b> MutationTracker<'a, 'b> {
if let Some(target) = vals.get(k) {
intermediates.push(Intermediate::Map(
oid.clone(),
map_type.clone(),
*map_type,
k.clone(),
current_obj.default_op_id_for_key(amp::RequestKey::Str(k.clone())),
));
@ -277,7 +277,7 @@ impl<'a, 'b> MutationTracker<'a, 'b> {
if stack.is_empty() {
intermediates.push(Intermediate::Map(
oid.clone(),
map_type.clone(),
*map_type,
k.clone(),
current_obj.default_op_id_for_key(amp::RequestKey::Str(k.clone())),
))
@ -290,7 +290,7 @@ impl<'a, 'b> MutationTracker<'a, 'b> {
if let Some(Some(target)) = vals.get(*i) {
intermediates.push(Intermediate::Seq(
oid.clone(),
seq_type.clone(),
*seq_type,
*i,
current_obj.default_op_id_for_key(amp::RequestKey::Num(*i as u64)),
));
@ -304,7 +304,7 @@ impl<'a, 'b> MutationTracker<'a, 'b> {
if stack.is_empty() {
intermediates.push(Intermediate::Seq(
oid.clone(),
seq_type.clone(),
*seq_type,
*i,
current_obj.default_op_id_for_key(amp::RequestKey::Num(*i as u64)),
))
@ -326,12 +326,12 @@ impl<'a, 'b> MutationTracker<'a, 'b> {
.rfold(subdiff, |diff_so_far, intermediate| match intermediate {
Intermediate::Map(oid, map_type, k, opid) => amp::Diff::Map(amp::MapDiff {
object_id: oid,
obj_type: map_type.to_obj_type(),
obj_type: map_type,
props: hashmap! {k => hashmap!{opid.unwrap_or_else(random_op_id) => diff_so_far}},
}),
Intermediate::Seq(oid, seq_type, index, opid) => amp::Diff::Seq(amp::SeqDiff {
object_id: oid,
obj_type: seq_type.to_obj_type(),
obj_type: seq_type,
edits: Vec::new(),
props: hashmap! {index => hashmap!{opid.unwrap_or_else(random_op_id) => diff_so_far}},
}),
@ -343,7 +343,7 @@ impl<'a, 'b> MutationTracker<'a, 'b> {
/// the root object
fn wrap_root_assignment(&mut self, value: &Value) -> Result<(), AutomergeFrontendError> {
match value {
Value::Map(kvs, MapType::Map) => {
Value::Map(kvs, amp::MapType::Map) => {
for (k, v) in kvs.iter() {
self.add_change(LocalChange::set(Path::root().key(k), v.clone()))?;
}
@ -412,14 +412,14 @@ impl<'a, 'b> MutableDocument for MutationTracker<'a, 'b> {
let diff = match &*parent_obj {
Object::Map(oid, _, map_type) => amp::Diff::Map(amp::MapDiff {
object_id: oid.clone(),
obj_type: map_type.to_obj_type(),
obj_type: *map_type,
props: hashmap! {change.path.name().unwrap().to_string() => HashMap::new()},
}),
Object::Sequence(oid, _, seq_type) => {
if let Some(PathElement::Index(i)) = change.path.name() {
amp::Diff::Seq(amp::SeqDiff {
object_id: oid.clone(),
obj_type: seq_type.to_obj_type(),
obj_type: *seq_type,
edits: vec![amp::DiffEdit::Remove { index: *i }],
props: hashmap! {*i => HashMap::new()},
})
@ -497,7 +497,7 @@ impl<'a, 'b> MutableDocument for MutationTracker<'a, 'b> {
);
let seqdiff = amp::Diff::Seq(amp::SeqDiff {
object_id: oid.clone(),
obj_type: seq_type.to_obj_type(),
obj_type: *seq_type,
edits: vec![amp::DiffEdit::Insert { index: *index }],
props: hashmap! {
*index => hashmap!{

View file

@ -1,4 +1,4 @@
use crate::{MapType, SequenceType, Value};
use crate::Value;
use automerge_protocol as amp;
use std::{cell::RefCell, collections::HashMap, rc::Rc};
@ -42,8 +42,8 @@ impl Values {
/// Internal data type used to represent the values of an automerge document
#[derive(Clone, Debug)]
pub enum Object {
Sequence(amp::ObjectID, Vec<Option<Values>>, SequenceType),
Map(amp::ObjectID, HashMap<String, Values>, MapType),
Sequence(amp::ObjectID, Vec<Option<Values>>, amp::SequenceType),
Map(amp::ObjectID, HashMap<String, Values>, amp::MapType),
Primitive(amp::Value),
}
@ -54,13 +54,13 @@ impl Object {
vals.iter()
.filter_map(|v| v.clone().map(|v2| v2.to_value()))
.collect(),
seq_type.clone(),
*seq_type,
),
Object::Map(_, vals, map_type) => Value::Map(
vals.iter()
.map(|(k, v)| (k.to_string(), v.to_value()))
.collect(),
map_type.clone(),
*map_type,
),
Object::Primitive(v) => Value::Primitive(v.clone()),
}

View file

@ -4,36 +4,6 @@ use maplit::hashmap;
use serde::Serialize;
use std::{borrow::Borrow, collections::HashMap};
#[derive(Serialize, Clone, Debug, PartialEq)]
pub enum MapType {
Map,
Table,
}
impl MapType {
pub(crate) fn to_obj_type(&self) -> amp::ObjType {
match self {
MapType::Map => amp::ObjType::Map,
MapType::Table => amp::ObjType::Table,
}
}
}
#[derive(Serialize, Clone, Debug, PartialEq)]
pub enum SequenceType {
List,
Text,
}
impl SequenceType {
pub(crate) fn to_obj_type(&self) -> amp::ObjType {
match self {
SequenceType::List => amp::ObjType::List,
SequenceType::Text => amp::ObjType::Text,
}
}
}
#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct Conflicts(HashMap<amp::OpID, Value>);
@ -46,8 +16,8 @@ impl From<HashMap<amp::OpID, Value>> for Conflicts {
#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum Value {
Map(HashMap<String, Value>, MapType),
Sequence(Vec<Value>, SequenceType),
Map(HashMap<String, Value>, amp::MapType),
Sequence(Vec<Value>, amp::SequenceType),
Primitive(amp::Value),
}
@ -76,7 +46,7 @@ where
fn from(v: Vec<T>) -> Self {
Value::Sequence(
v.into_iter().map(|t| t.into()).collect(),
SequenceType::List,
amp::SequenceType::List,
)
}
}
@ -91,7 +61,7 @@ where
h.into_iter()
.map(|(k, v)| (k.borrow().to_string(), v.into()))
.collect(),
MapType::Map,
amp::MapType::Map,
)
}
}
@ -104,11 +74,11 @@ impl Value {
.iter()
.map(|(k, v)| (k.clone(), Value::from_json(v)))
.collect();
Value::Map(result, MapType::Map)
Value::Map(result, amp::MapType::Map)
}
serde_json::Value::Array(vs) => Value::Sequence(
vs.iter().map(Value::from_json).collect(),
SequenceType::List,
amp::SequenceType::List,
),
serde_json::Value::String(s) => Value::Primitive(amp::Value::Str(s.clone())),
serde_json::Value::Number(n) => {
@ -126,14 +96,15 @@ impl Value {
map.iter().map(|(k, v)| (k.clone(), v.to_json())).collect();
serde_json::Value::Object(result)
}
Value::Sequence(elements, SequenceType::List) => {
Value::Sequence(elements, amp::SequenceType::List) => {
serde_json::Value::Array(elements.iter().map(|v| v.to_json()).collect())
}
Value::Sequence(elements, SequenceType::Text) => serde_json::Value::String(
Value::Sequence(elements, amp::SequenceType::Text) => serde_json::Value::String(
elements
.iter()
.map(|v| match v {
Value::Primitive(amp::Value::Str(c)) => c.as_str(),
// TODO fix panic
_ => panic!("Non string element in text sequence"),
})
.collect(),
@ -179,8 +150,8 @@ pub(crate) fn value_to_op_requests(
match v {
Value::Sequence(vs, seq_type) => {
let make_action = match seq_type {
SequenceType::List => amp::OpType::MakeList,
SequenceType::Text => amp::OpType::MakeText,
amp::SequenceType::List => amp::OpType::MakeList,
amp::SequenceType::Text => amp::OpType::MakeText,
};
let list_id = new_object_id();
let make_op = amp::Op {
@ -211,10 +182,7 @@ pub(crate) fn value_to_op_requests(
.map(|(index, _)| amp::DiffEdit::Insert { index })
.collect(),
object_id: list_id,
obj_type: match seq_type {
SequenceType::List => amp::ObjType::List,
SequenceType::Text => amp::ObjType::Text,
},
obj_type: *seq_type,
props: child_requests_and_diffs
.into_iter()
.enumerate()
@ -227,8 +195,8 @@ pub(crate) fn value_to_op_requests(
}
Value::Map(kvs, map_type) => {
let make_action = match map_type {
MapType::Map => amp::OpType::MakeMap,
MapType::Table => amp::OpType::MakeTable,
amp::MapType::Map => amp::OpType::MakeMap,
amp::MapType::Table => amp::OpType::MakeTable,
};
let map_id = new_object_id();
let make_op = amp::Op {
@ -257,10 +225,7 @@ pub(crate) fn value_to_op_requests(
.collect();
let child_diff = amp::MapDiff {
object_id: map_id,
obj_type: match map_type {
MapType::Map => amp::ObjType::Map,
MapType::Table => amp::ObjType::Table,
},
obj_type: *map_type,
props: child_requests_and_diffs
.into_iter()
.map(|(k, (_, diff_link))| (k, hashmap! {random_op_id() => diff_link}))

View file

@ -17,10 +17,10 @@ fn set_object_root_properties() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"bird".into() => hashmap!{
actor.op_id_at(1).into() => "magpie".into()
actor.op_id_at(1) => "magpie".into()
}
},
})),
@ -60,11 +60,11 @@ fn reveal_conflicts_on_root_properties() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"favouriteBird".into() => hashmap!{
actor1.op_id_at(1).into() => amp::Diff::Value("robin".into()),
actor2.op_id_at(1).into() => amp::Diff::Value("wagtail".into()),
actor1.op_id_at(1) => amp::Diff::Value("robin".into()),
actor2.op_id_at(1) => amp::Diff::Value("wagtail".into()),
}
},
})),
@ -103,15 +103,15 @@ fn create_nested_maps() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Map(amp::MapDiff{
actor.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: actor.op_id_at(2).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"wrens".into() => hashmap!{
actor.op_id_at(2).into() => amp::Diff::Value(amp::Value::Int(3))
actor.op_id_at(2) => amp::Diff::Value(amp::Value::Int(3))
}
}
})
@ -142,15 +142,15 @@ fn apply_updates_inside_nested_maps() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Map(amp::MapDiff{
actor.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: actor.op_id_at(2).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"wrens".into() => hashmap!{
actor.op_id_at(2).into() => amp::Diff::Value(amp::Value::Int(3))
actor.op_id_at(2) => amp::Diff::Value(amp::Value::Int(3))
}
}
})
@ -175,15 +175,15 @@ fn apply_updates_inside_nested_maps() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Map(amp::MapDiff{
object_id: birds_id.into(),
obj_type: amp::ObjType::Map,
actor.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: birds_id,
obj_type: amp::MapType::Map,
props: hashmap!{
"sparrows".into() => hashmap!{
actor.op_id_at(3).into() => amp::Diff::Value(amp::Value::Int(15))
actor.op_id_at(3) => amp::Diff::Value(amp::Value::Int(15))
}
}
})
@ -229,24 +229,24 @@ fn apply_updates_inside_map_conflicts() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"favouriteBirds".into() => hashmap!{
actor1.op_id_at(1).into() => amp::Diff::Map(amp::MapDiff{
actor1.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: actor1.op_id_at(1).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"blackbirds".into() => hashmap!{
actor1.op_id_at(2).into() => amp::Diff::Value(amp::Value::Int(1)),
actor1.op_id_at(2) => amp::Diff::Value(amp::Value::Int(1)),
}
},
}),
actor2.op_id_at(1).into() => amp::Diff::Map(amp::MapDiff{
actor2.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: actor2.op_id_at(1).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"wrens".into() => hashmap!{
actor2.op_id_at(2).into() => amp::Diff::Value(amp::Value::Int(3)),
actor2.op_id_at(2) => amp::Diff::Value(amp::Value::Int(3)),
}
},
})
@ -287,21 +287,21 @@ fn apply_updates_inside_map_conflicts() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"favouriteBirds".into() => hashmap!{
actor1.op_id_at(1).into() => amp::Diff::Map(amp::MapDiff{
actor1.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: actor1.op_id_at(1).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"blackbirds".into() => hashmap!{
actor1.op_id_at(3).into() => amp::Diff::Value(amp::Value::Int(2)),
actor1.op_id_at(3) => amp::Diff::Value(amp::Value::Int(2)),
}
},
}),
actor2.op_id_at(1).into() => amp::Diff::Unchanged(amp::ObjDiff{
actor2.op_id_at(1) => amp::Diff::Unchanged(amp::ObjDiff{
object_id: actor2.op_id_at(1).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::ObjType::Map(amp::MapType::Map),
})
}
},
@ -344,13 +344,13 @@ fn delete_keys_in_maps() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"magpies".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Value(amp::Value::Int(2))
actor.op_id_at(1) => amp::Diff::Value(amp::Value::Int(2))
},
"sparrows".into() => hashmap!{
actor.op_id_at(2).into() => amp::Diff::Value(amp::Value::Int(15))
actor.op_id_at(2) => amp::Diff::Value(amp::Value::Int(15))
}
},
})),
@ -375,7 +375,7 @@ fn delete_keys_in_maps() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"magpies".into() => hashmap!{}
},
@ -405,16 +405,16 @@ fn create_lists() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
actor.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: actor.op_id_at(1).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert { index: 0 }],
props: hashmap!{
0 => hashmap!{
actor.op_id_at(2).into() => amp::Diff::Value("chaffinch".into())
actor.op_id_at(2) => amp::Diff::Value("chaffinch".into())
}
}
})
@ -446,16 +446,16 @@ fn apply_updates_inside_lists() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
actor.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: actor.op_id_at(1).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert { index: 0 }],
props: hashmap!{
0 => hashmap!{
actor.op_id_at(2).into() => amp::Diff::Value("chaffinch".into())
actor.op_id_at(2) => amp::Diff::Value("chaffinch".into())
}
}
})
@ -477,16 +477,16 @@ fn apply_updates_inside_lists() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
actor.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: actor.op_id_at(1).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: vec![],
props: hashmap!{
0 => hashmap!{
actor.op_id_at(3).into() => amp::Diff::Value("greenfinch".into())
actor.op_id_at(3) => amp::Diff::Value("greenfinch".into())
}
}
})
@ -532,36 +532,36 @@ fn apply_updates_inside_list_conflicts() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
other_actor.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
other_actor.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: other_actor.op_id_at(1).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert{ index: 0}],
props: hashmap!{
0 => hashmap!{
actor1.op_id_at(2).into() => amp::Diff::Map(amp::MapDiff{
actor1.op_id_at(2) => amp::Diff::Map(amp::MapDiff{
object_id: actor1.op_id_at(2).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"species".into() => hashmap!{
actor1.op_id_at(3).into() => amp::Diff::Value("woodpecker".into()),
actor1.op_id_at(3) => amp::Diff::Value("woodpecker".into()),
},
"numSeen".into() => hashmap!{
actor1.op_id_at(4).into() => amp::Diff::Value(amp::Value::Int(1)),
actor1.op_id_at(4) => amp::Diff::Value(amp::Value::Int(1)),
},
}
}),
actor2.op_id_at(2).into() => amp::Diff::Map(amp::MapDiff{
actor2.op_id_at(2) => amp::Diff::Map(amp::MapDiff{
object_id: actor2.op_id_at(2).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"species".into() => hashmap!{
actor2.op_id_at(3).into() => amp::Diff::Value("lapwing".into()),
actor2.op_id_at(3) => amp::Diff::Value("lapwing".into()),
},
"numSeen".into() => hashmap!{
actor2.op_id_at(4).into() => amp::Diff::Value(amp::Value::Int(2)),
actor2.op_id_at(4) => amp::Diff::Value(amp::Value::Int(2)),
},
}
}),
@ -611,27 +611,27 @@ fn apply_updates_inside_list_conflicts() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
other_actor.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
other_actor.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: other_actor.op_id_at(1).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: Vec::new(),
props: hashmap!{
0 => hashmap!{
actor1.op_id_at(2).into() => amp::Diff::Map(amp::MapDiff{
actor1.op_id_at(2) => amp::Diff::Map(amp::MapDiff{
object_id: actor1.op_id_at(2).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"numSeen".into() => hashmap!{
actor1.op_id_at(5).into() => amp::Diff::Value(amp::Value::Int(2)),
actor1.op_id_at(5) => amp::Diff::Value(amp::Value::Int(2)),
},
}
}),
actor2.op_id_at(2).into() => amp::Diff::Unchanged(amp::ObjDiff{
actor2.op_id_at(2) => amp::Diff::Unchanged(amp::ObjDiff{
object_id: actor2.op_id_at(2).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::ObjType::Map(amp::MapType::Map),
}),
},
}
@ -683,19 +683,19 @@ fn delete_list_elements() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
actor.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: actor.op_id_at(1).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert { index: 0 }, amp::DiffEdit::Insert { index: 1 }],
props: hashmap!{
0 => hashmap!{
actor.op_id_at(2).into() => amp::Diff::Value("chaffinch".into())
actor.op_id_at(2) => amp::Diff::Value("chaffinch".into())
},
1 => hashmap!{
actor.op_id_at(3).into() => amp::Diff::Value("goldfinch".into())
actor.op_id_at(3) => amp::Diff::Value("goldfinch".into())
}
}
})
@ -721,12 +721,12 @@ fn delete_list_elements() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
actor.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: actor.op_id_at(1).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Remove{ index: 0 }],
props: hashmap!{}
})
@ -754,35 +754,35 @@ fn apply_updates_at_different_levels_of_object_tree() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"counts".into() => hashmap!{
actor.op_id_at(1).into() => amp::Diff::Map(amp::MapDiff{
actor.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: actor.op_id_at(1).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"magpie".into() => hashmap!{
actor.op_id_at(2).into() => amp::Diff::Value(amp::Value::Int(2))
actor.op_id_at(2) => amp::Diff::Value(amp::Value::Int(2))
}
}
})
},
"details".into() => hashmap!{
actor.op_id_at(3).into() => amp::Diff::Seq(amp::SeqDiff{
actor.op_id_at(3) => amp::Diff::Seq(amp::SeqDiff{
object_id: actor.op_id_at(3).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert{ index: 0 }],
props: hashmap!{
0 => hashmap!{
actor.op_id_at(4).into() => amp::Diff::Map(amp::MapDiff{
actor.op_id_at(4) => amp::Diff::Map(amp::MapDiff{
object_id: actor.op_id_at(4).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"species".into() => hashmap!{
actor.op_id_at(5).into() => amp::Diff::Value("magpie".into())
actor.op_id_at(5) => amp::Diff::Value("magpie".into())
},
"family".into() => hashmap!{
actor.op_id_at(6).into() => amp::Diff::Value("Corvidae".into())
actor.op_id_at(6) => amp::Diff::Value("Corvidae".into())
}
}
})
@ -818,12 +818,12 @@ fn apply_updates_at_different_levels_of_object_tree() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"counts".into() => hashmap!{
actor.op_id_at(1) => amp::Diff::Map(amp::MapDiff{
object_id: actor.op_id_at(1).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"magpie".into() => hashmap!{
actor.op_id_at(7) => amp::Diff::Value(amp::Value::Int(3))
@ -834,13 +834,13 @@ fn apply_updates_at_different_levels_of_object_tree() {
"details".into() => hashmap!{
actor.op_id_at(3) => amp::Diff::Seq(amp::SeqDiff{
object_id: actor.op_id_at(3).into(),
obj_type: amp::ObjType::List,
obj_type: amp::SequenceType::List,
edits: Vec::new(),
props: hashmap!{
0 => hashmap!{
actor.op_id_at(4) => amp::Diff::Map(amp::MapDiff{
object_id: actor.op_id_at(4).into(),
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"species".into() => hashmap!{
actor.op_id_at(8) => amp::Diff::Value("Eurasian magpie".into())

View file

@ -28,7 +28,7 @@ fn use_version_and_sequence_number_from_backend() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"blackbirds".into() => hashmap!{
random_op_id() => amp::Diff::Value(amp::Value::F64(24.0))
@ -120,7 +120,7 @@ fn remove_pending_requests_once_handled() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"blackbirds".into() => hashmap!{
random_op_id() => amp::Diff::Value(amp::Value::Int(24))
@ -154,7 +154,7 @@ fn remove_pending_requests_once_handled() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"partridges".into() => hashmap!{
random_op_id() => amp::Diff::Value(amp::Value::Int(1))
@ -214,7 +214,7 @@ fn leave_request_queue_unchanged_on_remote_changes() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"pheasants".into() => hashmap!{
random_op_id() => amp::Diff::Value(amp::Value::Int(2))
@ -248,7 +248,7 @@ fn leave_request_queue_unchanged_on_remote_changes() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"blackbirds".into() => hashmap!{
random_op_id() => amp::Diff::Value(amp::Value::Int(24))
@ -300,7 +300,7 @@ fn dont_allow_out_of_order_request_patches() {
can_redo: false,
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"partridges".to_string() => hashmap!{
random_op_id() => amp::Diff::Value(amp::Value::Int(1))
@ -345,12 +345,12 @@ fn handle_concurrent_insertions_into_lists() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".to_string() => hashmap!{
doc.actor_id.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
object_id: birds_id.clone().into(),
obj_type: amp::ObjType::List,
doc.actor_id.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: birds_id.clone(),
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert{ index: 0 }],
props: hashmap!{
0 => hashmap!{
@ -411,16 +411,16 @@ fn handle_concurrent_insertions_into_lists() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff {
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap! {
"birds".into() => hashmap!{
doc.actor_id.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
object_id: birds_id.clone().into(),
obj_type: amp::ObjType::List,
doc.actor_id.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: birds_id.clone(),
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert{ index: 1 }],
props: hashmap!{
1 => hashmap!{
remote.op_id_at(1).into() => amp::Diff::Value("bullfinch".into())
remote.op_id_at(1) => amp::Diff::Value("bullfinch".into())
}
}
})
@ -452,19 +452,19 @@ fn handle_concurrent_insertions_into_lists() {
deps: Vec::new(),
diffs: Some(amp::Diff::Map(amp::MapDiff{
object_id: amp::ObjectID::Root,
obj_type: amp::ObjType::Map,
obj_type: amp::MapType::Map,
props: hashmap!{
"birds".to_string() => hashmap!{
doc.actor_id.op_id_at(1).into() => amp::Diff::Seq(amp::SeqDiff{
object_id: birds_id.into(),
obj_type: amp::ObjType::List,
doc.actor_id.op_id_at(1) => amp::Diff::Seq(amp::SeqDiff{
object_id: birds_id,
obj_type: amp::SequenceType::List,
edits: vec![amp::DiffEdit::Insert { index: 0 }, amp::DiffEdit::Insert{ index: 2 }],
props: hashmap!{
0 => hashmap!{
doc.actor_id.op_id_at(2).into() => amp::Diff::Value("chaffinch".into()),
doc.actor_id.op_id_at(2) => amp::Diff::Value("chaffinch".into()),
},
2 => hashmap!{
doc.actor_id.op_id_at(3).into() => amp::Diff::Value("greenfinch".into()),
doc.actor_id.op_id_at(3) => amp::Diff::Value("greenfinch".into()),
}
}
})

View file

@ -1,6 +1,4 @@
use automerge_frontend::{
AutomergeFrontendError, Frontend, LocalChange, MapType, Path, SequenceType, Value,
};
use automerge_frontend::{AutomergeFrontendError, Frontend, LocalChange, Path, Value};
use automerge_protocol as amp;
use maplit::hashmap;
@ -272,7 +270,7 @@ fn create_lists() {
.change(None, |doc| {
doc.add_change(LocalChange::set(
Path::root().key("birds"),
Value::Sequence(vec!["chaffinch".into()], SequenceType::List),
Value::Sequence(vec!["chaffinch".into()], amp::SequenceType::List),
))?;
Ok(())
})
@ -340,7 +338,7 @@ fn apply_updates_inside_lists() {
.change(None, |doc| {
doc.add_change(LocalChange::set(
Path::root().key("birds"),
Value::Sequence(vec!["chaffinch".into()], SequenceType::List),
Value::Sequence(vec!["chaffinch".into()], amp::SequenceType::List),
))?;
Ok(())
})
@ -474,7 +472,7 @@ fn handle_counters_inside_maps() {
hashmap! {
"wrens".into() => Value::Primitive(amp::Value::Counter(0))
},
MapType::Map
amp::MapType::Map
)
);
@ -484,7 +482,7 @@ fn handle_counters_inside_maps() {
hashmap! {
"wrens".into() => Value::Primitive(amp::Value::Counter(1))
},
MapType::Map
amp::MapType::Map
)
);
@ -564,7 +562,7 @@ fn handle_counters_inside_lists() {
hashmap! {
"counts".into() => vec![Value::Primitive(amp::Value::Counter(1))].into()
},
MapType::Map
amp::MapType::Map
)
);
@ -574,7 +572,7 @@ fn handle_counters_inside_lists() {
hashmap! {
"counts".into() => vec![Value::Primitive(amp::Value::Counter(3))].into()
},
MapType::Map
amp::MapType::Map
)
);

View file

@ -11,3 +11,7 @@ hex = "^0.4.2"
uuid = { version = "^0.5.1", features=["v4"] }
thiserror = "1.0.16"
serde = { version = "^1.0", features=["derive"] }
[dev-dependencies]
maplit = "^1.0.2"
serde_json = "^1.0"

View file

@ -35,12 +35,42 @@ impl ActorID {
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Copy, Hash)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "camelCase", untagged)]
pub enum ObjType {
Map(MapType),
Sequence(SequenceType),
}
impl ObjType {
pub fn map() -> ObjType {
ObjType::Map(MapType::Map)
}
pub fn table() -> ObjType {
ObjType::Map(MapType::Table)
}
pub fn text() -> ObjType {
ObjType::Sequence(SequenceType::Text)
}
pub fn list() -> ObjType {
ObjType::Sequence(SequenceType::List)
}
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Copy, Hash)]
#[serde(rename_all = "camelCase")]
pub enum MapType {
Map,
Table,
Text,
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Copy, Hash)]
#[serde(rename_all = "camelCase")]
pub enum SequenceType {
List,
Text,
}
#[derive(Eq, PartialEq, Hash, Clone)]
@ -215,10 +245,10 @@ impl Op {
pub fn obj_type(&self) -> Option<ObjType> {
match self.action {
OpType::MakeMap => Some(ObjType::Map),
OpType::MakeTable => Some(ObjType::Table),
OpType::MakeList => Some(ObjType::List),
OpType::MakeText => Some(ObjType::Text),
OpType::MakeMap => Some(ObjType::Map(MapType::Map)),
OpType::MakeTable => Some(ObjType::Map(MapType::Table)),
OpType::MakeList => Some(ObjType::Sequence(SequenceType::List)),
OpType::MakeText => Some(ObjType::Sequence(SequenceType::Text)),
_ => None,
}
}
@ -292,7 +322,7 @@ pub enum Diff {
pub struct MapDiff {
pub object_id: ObjectID,
#[serde(rename = "type")]
pub obj_type: ObjType,
pub obj_type: MapType,
pub props: HashMap<String, HashMap<OpID, Diff>>,
}
@ -301,7 +331,7 @@ pub struct MapDiff {
pub struct SeqDiff {
pub object_id: ObjectID,
#[serde(rename = "type")]
pub obj_type: ObjType,
pub obj_type: SequenceType,
pub edits: Vec<DiffEdit>,
pub props: HashMap<usize, HashMap<OpID, Diff>>,
}

View file

@ -87,27 +87,28 @@ impl<'de> Deserialize<'de> for Diff {
let object_id = object_id.ok_or_else(|| Error::missing_field("objectId"))?;
let obj_type = obj_type.ok_or_else(|| Error::missing_field("type"))?;
if let Some(mut props) = props {
if obj_type == ObjType::Text || obj_type == ObjType::List {
let edits = edits.ok_or_else(|| Error::missing_field("edits"))?;
let mut new_props = HashMap::new();
for (k, v) in props.drain() {
let index = k.parse().map_err(|_| {
Error::invalid_type(Unexpected::Str(&k), &"an integer")
})?;
new_props.insert(index, v);
match obj_type {
ObjType::Sequence(seq_type) => {
let edits = edits.ok_or_else(|| Error::missing_field("edits"))?;
let mut new_props = HashMap::new();
for (k, v) in props.drain() {
let index = k.parse().map_err(|_| {
Error::invalid_type(Unexpected::Str(&k), &"an integer")
})?;
new_props.insert(index, v);
}
Ok(Diff::Seq(SeqDiff {
object_id,
obj_type: seq_type,
edits,
props: new_props,
}))
}
Ok(Diff::Seq(SeqDiff {
ObjType::Map(map_type) => Ok(Diff::Map(MapDiff {
object_id,
obj_type,
edits,
props: new_props,
}))
} else {
Ok(Diff::Map(MapDiff {
object_id,
obj_type,
obj_type: map_type,
props,
}))
})),
}
} else {
Ok(Diff::Unchanged(ObjDiff {
@ -141,3 +142,66 @@ fn maybe_add_datatype_to_value(value: Value, datatype: DataType) -> Value {
_ => value,
}
}
#[cfg(test)]
mod tests {
use crate::{Diff, MapDiff, MapType, ObjectID, OpID, SeqDiff, SequenceType};
use maplit::hashmap;
use std::str::FromStr;
#[test]
fn map_diff_serialization_round_trip() {
let json = serde_json::json!({
"objectId": "1@6121f8757d5d46609b665218b2b3a141",
"type": "map",
"props": {
"key": {
"1@4a093244de2b4fd0a4203724e15dfc16": {
"value": "value"
}
}
}
});
let diff = Diff::Map(MapDiff {
object_id: ObjectID::from_str("1@6121f8757d5d46609b665218b2b3a141").unwrap(),
obj_type: MapType::Map,
props: hashmap! {
"key".to_string() => hashmap!{
OpID::from_str("1@4a093244de2b4fd0a4203724e15dfc16").unwrap() => "value".into()
}
},
});
assert_eq!(json, serde_json::to_value(diff.clone()).unwrap());
assert_eq!(serde_json::from_value::<Diff>(json).unwrap(), diff);
}
#[test]
fn seq_diff_serialization_round_trip() {
let json = serde_json::json!({
"objectId": "1@6121f8757d5d46609b665218b2b3a141",
"type": "list",
"edits": [],
"props": {
"0": {
"1@4a093244de2b4fd0a4203724e15dfc16": {
"value": "value"
}
}
}
});
let diff = Diff::Seq(SeqDiff {
object_id: ObjectID::from_str("1@6121f8757d5d46609b665218b2b3a141").unwrap(),
obj_type: SequenceType::List,
edits: Vec::new(),
props: hashmap! {
0 => hashmap!{
OpID::from_str("1@4a093244de2b4fd0a4203724e15dfc16").unwrap() => "value".into()
}
},
});
assert_eq!(json, serde_json::to_value(diff.clone()).unwrap());
assert_eq!(serde_json::from_value::<Diff>(json).unwrap(), diff);
}
}