Skip to content

Commit

Permalink
Round trip (msgpack) on patches/changes works
Browse files Browse the repository at this point in the history
  • Loading branch information
vedantroy committed Jun 26, 2021
1 parent a001350 commit 5cb28b5
Show file tree
Hide file tree
Showing 16 changed files with 371 additions and 59 deletions.
@@ -0,0 +1,8 @@
{
"action": "multi-insert",
"index": 0,
"elemId": "9@8c8a54b01ce24c3a8dd9e05af04c862a",
"datatype": "int",
"values": [1, 2, 3]
}

Binary file not shown.
Binary file modified automerge-c-v2/examples/example-data/patch1.mpk
Binary file not shown.
Binary file modified automerge-c-v2/examples/example-data/patch2.mpk
Binary file not shown.
Binary file modified automerge-c-v2/examples/example-data/patch_small.mpk
Binary file not shown.
12 changes: 11 additions & 1 deletion automerge-c-v2/examples/generate_msgpack.rs
Expand Up @@ -9,7 +9,14 @@ fn main() {
let file_path = Path::new(file!()).parent().unwrap();
let cwd = std::env::current_dir().unwrap();
let root = cwd.join(file_path).join("example-data/");
let names = ["change1", "change2", "patch1", "patch2", "patch_small"];
let names = [
"change1",
"change2",
"patch1",
"patch2",
"patch_small",
"multi_element_insert",
];
for name in names {
let json_name = root.join(format!("{}.json", name));
let msgpack_name = root.join(format!("{}.mpk", name));
Expand All @@ -29,6 +36,9 @@ fn main() {
if name.contains("change") {
let change: amp::Change = serde_json::from_str(&json).unwrap();
change.serialize(&mut serializer).unwrap();
} else if name.contains("multi_element_insert") {
let multi: amp::DiffEdit = serde_json::from_str(&json).unwrap();
multi.serialize(&mut serializer).unwrap();
} else {
let patch: amp::Patch = serde_json::from_str(&json).unwrap();
// println!("{:?}", patch);
Expand Down
19 changes: 4 additions & 15 deletions automerge-protocol/src/lib.rs
Expand Up @@ -56,8 +56,7 @@ impl ActorId {
}
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Copy, Hash)]
#[serde(rename_all = "camelCase", untagged)]
#[derive(Debug, Clone, PartialEq, Copy, Hash)]
pub enum ObjType {
Map,
Table,
Expand Down Expand Up @@ -100,16 +99,14 @@ impl fmt::Display for ObjType {
}
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Copy, Hash)]
#[derive(Debug, Clone, PartialEq, Copy, Hash)]
#[cfg_attr(feature = "derive-arbitrary", derive(arbitrary::Arbitrary))]
#[serde(rename_all = "camelCase")]
pub enum MapType {
Map,
Table,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Copy, Hash)]
#[serde(rename_all = "camelCase")]
#[derive(Debug, Clone, PartialEq, Copy, Hash)]
pub enum SequenceType {
List,
Text,
Expand Down Expand Up @@ -219,23 +216,15 @@ impl Key {
}
}

#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, Copy)]
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum DataType {
#[serde(rename = "counter")]
Counter,
#[serde(rename = "timestamp")]
Timestamp,
#[serde(rename = "bytes")]
Bytes,
#[serde(rename = "cursor")]
Cursor,
#[serde(rename = "uint")]
Uint,
#[serde(rename = "int")]
Int,
#[serde(rename = "float64")]
F64,
#[serde(rename = "undefined")]
Undefined,
}

Expand Down
53 changes: 53 additions & 0 deletions automerge-protocol/src/serde_impls/data_type.rs
@@ -0,0 +1,53 @@
// See comment in map_type.rs
use serde::{de::Error, Deserialize, Deserializer, Serialize};

use crate::DataType;

impl Serialize for DataType {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
DataType::Counter => s.serialize_str("counter"),
DataType::Timestamp => s.serialize_str("timestamp"),
DataType::Bytes => s.serialize_str("bytes"),
DataType::Cursor => s.serialize_str("cursor"),
DataType::Uint => s.serialize_str("uint"),
DataType::Int => s.serialize_str("int"),
DataType::F64 => s.serialize_str("float64"),
DataType::Undefined => s.serialize_str("undefined"),
}
}
}

impl<'de> Deserialize<'de> for DataType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
const VARIANTS: &[&str] = &[
"counter",
"timestamp",
"bytes",
"cursor",
"uint",
"int",
"float64",
"undefined",
];
// TODO: Probably more efficient to deserialize to a `&str`
let raw_type = String::deserialize(deserializer)?;
match raw_type.as_str() {
"counter" => Ok(DataType::Counter),
"timestamp" => Ok(DataType::Timestamp),
"bytes" => Ok(DataType::Bytes),
"cursor" => Ok(DataType::Cursor),
"uint" => Ok(DataType::Uint),
"int" => Ok(DataType::Int),
"float64" => Ok(DataType::F64),
"undefined" => Ok(DataType::Undefined),
other => Err(Error::unknown_variant(other, VARIANTS)),
}
}
}
41 changes: 41 additions & 0 deletions automerge-protocol/src/serde_impls/map_type.rs
@@ -0,0 +1,41 @@
// By default, msgpack-rust serializes enums
// as maps with a single K/V pair. This is unnecessary,
// so we override that decision and manually serialize
// to a string

// The downside of this is that we cannot deserialize data structures
// that use this enum b/c the msgpack deserializer will expect
// enums to be encoded as a map with a single K/V pair
// Luckily, we don't need to deserialize data structures
// that use this enum
use serde::{de::Error, Deserialize, Deserializer, Serialize};

use crate::MapType;

impl Serialize for MapType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
MapType::Map => serializer.serialize_str("map"),
MapType::Table => serializer.serialize_str("table"),
}
}
}

impl<'de> Deserialize<'de> for MapType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
const VARIANTS: &[&str] = &["map", "table"];
// TODO: Probably more efficient to deserialize to a `&str`
let raw_type = String::deserialize(deserializer)?;
match raw_type.as_str() {
"map" => Ok(MapType::Map),
"table" => Ok(MapType::Table),
other => Err(Error::unknown_variant(other, VARIANTS)),
}
}
}
4 changes: 4 additions & 0 deletions automerge-protocol/src/serde_impls/mod.rs
Expand Up @@ -6,16 +6,20 @@ use serde::{
mod actor_id;
mod change_hash;
mod cursor_diff;
mod data_type;
mod diff;
mod element_id;
mod key;
mod map_type;
mod multi_element_insert;
mod obj_type;
mod object_id;
mod op;
mod op_type;
mod opid;
mod root_diff;
mod scalar_value;
mod seq_type;

// Helper method for use in custom deserialize impls
pub(crate) fn read_field<'de, T, M>(
Expand Down
14 changes: 3 additions & 11 deletions automerge-protocol/src/serde_impls/multi_element_insert.rs
@@ -1,5 +1,3 @@
use std::convert::TryInto;

use serde::{
de::{Error, MapAccess, Visitor},
ser::{SerializeStruct, Serializer},
Expand All @@ -15,10 +13,9 @@ impl Serialize for MultiElementInsert {
where
S: Serializer,
{
//serializer.serialize_newtype_variant("foo", 0, "bar", value)
let datatype = self.values.as_numerical_datatype();
let mut ss =
serializer.serialize_struct("MultiElementInsert", datatype.map_or(4, |_| 5))?;
serializer.serialize_struct("MultiElementInsert", datatype.map_or(3, |_| 4))?;
ss.serialize_field("index", &self.index)?;
ss.serialize_field("elemId", &self.elem_id)?;
if let Some(datatype) = datatype {
Expand All @@ -30,7 +27,7 @@ impl Serialize for MultiElementInsert {
}

impl<'de> Deserialize<'de> for MultiElementInsert {
fn deserialize<D>(_: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Expand Down Expand Up @@ -74,11 +71,6 @@ impl<'de> Deserialize<'de> for MultiElementInsert {
formatter.write_str("A MultiElementInsert")
}
}

Ok(MultiElementInsert {
index: 0,
elem_id: crate::ElementId::Head,
values: vec![ScalarValue::Str("one".into())].try_into().unwrap(),
})
deserializer.deserialize_struct("MultiElementInsert", &FIELDS, MultiElementInsertVisitor)
}
}
36 changes: 36 additions & 0 deletions automerge-protocol/src/serde_impls/obj_type.rs
@@ -0,0 +1,36 @@
// See type in map_type.rs
use serde::{de::Error, Deserialize, Deserializer, Serialize};

use crate::ObjType;

impl Serialize for ObjType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
ObjType::Map => serializer.serialize_str("map"),
ObjType::Table => serializer.serialize_str("table"),
ObjType::List => serializer.serialize_str("list"),
ObjType::Text => serializer.serialize_str("text"),
}
}
}

impl<'de> Deserialize<'de> for ObjType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
const VARIANTS: &[&str] = &["map", "table", "list", "text"];
// TODO: Probably more efficient to deserialize to a `&str`
let raw_type = String::deserialize(deserializer)?;
match raw_type.as_str() {
"map" => Ok(ObjType::Map),
"table" => Ok(ObjType::Table),
"list" => Ok(ObjType::List),
"text" => Ok(ObjType::Text),
other => Err(Error::unknown_variant(other, VARIANTS)),
}
}
}
35 changes: 32 additions & 3 deletions automerge-protocol/src/serde_impls/root_diff.rs
Expand Up @@ -27,15 +27,44 @@ impl<'de> Deserialize<'de> for RootDiff {
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "camelCase")]
// NOTE: If you want to implement
enum Field {
ObjectId,
#[serde(rename = "type")]
ObjectType,
Props,
}

impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;

impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`objectId`, `type` or `props`")
}

fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"objectId" => Ok(Field::ObjectId),
"type" => Ok(Field::ObjectType),
"props" => Ok(Field::Props),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}

deserializer.deserialize_identifier(FieldVisitor)
}
}

struct RootDiffVisitor;

const FIELDS: &[&str] = &["objectId", "type", "props"];
Expand Down
32 changes: 32 additions & 0 deletions automerge-protocol/src/serde_impls/seq_type.rs
@@ -0,0 +1,32 @@
// See type in map_type.rs
use serde::{de::Error, Deserialize, Deserializer, Serialize};

use crate::SequenceType;

impl Serialize for SequenceType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
SequenceType::List => serializer.serialize_str("list"),
SequenceType::Text => serializer.serialize_str("text"),
}
}
}

impl<'de> Deserialize<'de> for SequenceType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
const VARIANTS: &[&str] = &["list", "text"];
// TODO: Probably more efficient to deserialize to a `&str`
let raw_type = String::deserialize(deserializer)?;
match raw_type.as_str() {
"list" => Ok(SequenceType::List),
"text" => Ok(SequenceType::Text),
other => Err(Error::unknown_variant(other, VARIANTS)),
}
}
}

0 comments on commit 5cb28b5

Please sign in to comment.