Renamed Value to JsonValue to make things a little more clear

This commit is contained in:
Dave Hrycyszyn
2024-05-30 15:45:38 +01:00
parent 0733e12539
commit 3120ceee5d
7 changed files with 108 additions and 102 deletions

View File

@@ -2,7 +2,7 @@
extern crate test; extern crate test;
use bft_json_crdt::{ use bft_json_crdt::{
json_crdt::Value, keypair::make_author, list_crdt::ListCrdt, op::Op, op::ROOT_ID, json_crdt::JsonValue, keypair::make_author, list_crdt::ListCrdt, op::Op, op::ROOT_ID,
}; };
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use test::Bencher; use test::Bencher;
@@ -35,7 +35,7 @@ fn bench_insert_many_agents_conflicts(b: &mut Bencher) {
const N: u8 = 50; const N: u8 = 50;
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut crdts: Vec<ListCrdt<i64>> = Vec::with_capacity(N as usize); let mut crdts: Vec<ListCrdt<i64>> = Vec::with_capacity(N as usize);
let mut logs: Vec<Op<Value>> = Vec::new(); let mut logs: Vec<Op<JsonValue>> = Vec::new();
for i in 0..N { for i in 0..N {
let list = ListCrdt::new(make_author(i), vec![]); let list = ListCrdt::new(make_author(i), vec![]);
crdts.push(list); crdts.push(list);

View File

@@ -90,8 +90,8 @@ pub fn derive_json_crdt(input: OgTokenStream) -> OgTokenStream {
let expanded = quote! { let expanded = quote! {
impl #impl_generics #crate_name::json_crdt::CrdtNodeFromValue for #ident #ty_generics #where_clause { impl #impl_generics #crate_name::json_crdt::CrdtNodeFromValue for #ident #ty_generics #where_clause {
fn node_from(value: #crate_name::json_crdt::Value, id: #crate_name::keypair::AuthorId, path: Vec<#crate_name::op::PathSegment>) -> Result<Self, String> { fn node_from(value: #crate_name::json_crdt::JsonValue, id: #crate_name::keypair::AuthorId, path: Vec<#crate_name::op::PathSegment>) -> Result<Self, String> {
if let #crate_name::json_crdt::Value::Object(mut obj) = value { if let #crate_name::json_crdt::JsonValue::Object(mut obj) = value {
Ok(#ident { Ok(#ident {
path: path.clone(), path: path.clone(),
id, id,
@@ -119,7 +119,7 @@ pub fn derive_json_crdt(input: OgTokenStream) -> OgTokenStream {
} }
impl #impl_generics #crate_name::json_crdt::CrdtNode for #ident #ty_generics #where_clause { impl #impl_generics #crate_name::json_crdt::CrdtNode for #ident #ty_generics #where_clause {
fn apply(&mut self, op: #crate_name::op::Op<#crate_name::json_crdt::Value>) -> #crate_name::json_crdt::OpState { fn apply(&mut self, op: #crate_name::op::Op<#crate_name::json_crdt::JsonValue>) -> #crate_name::json_crdt::OpState {
let path = op.path.clone(); let path = op.path.clone();
let author = op.id.clone(); let author = op.id.clone();
if !#crate_name::op::ensure_subpath(&self.path, &op.path) { if !#crate_name::op::ensure_subpath(&self.path, &op.path) {
@@ -143,10 +143,10 @@ pub fn derive_json_crdt(input: OgTokenStream) -> OgTokenStream {
} }
} }
fn view(&self) -> #crate_name::json_crdt::Value { fn view(&self) -> #crate_name::json_crdt::JsonValue {
let mut view_map = std::collections::HashMap::new(); let mut view_map = std::collections::HashMap::new();
#(view_map.insert(#ident_strings.to_string(), self.#ident_literals.view().into());)* #(view_map.insert(#ident_strings.to_string(), self.#ident_literals.view().into());)*
#crate_name::json_crdt::Value::Object(view_map) #crate_name::json_crdt::JsonValue::Object(view_map)
} }
fn new(id: #crate_name::keypair::AuthorId, path: Vec<#crate_name::op::PathSegment>) -> Self { fn new(id: #crate_name::keypair::AuthorId, path: Vec<#crate_name::op::PathSegment>) -> Self {

View File

@@ -23,9 +23,9 @@ pub trait CrdtNode: CrdtNodeFromValue + Hashable + Clone {
/// Create a new CRDT of this type /// Create a new CRDT of this type
fn new(id: AuthorId, path: Vec<PathSegment>) -> Self; fn new(id: AuthorId, path: Vec<PathSegment>) -> Self;
/// Apply an operation to this CRDT, forwarding if necessary /// Apply an operation to this CRDT, forwarding if necessary
fn apply(&mut self, op: Op<Value>) -> OpState; fn apply(&mut self, op: Op<JsonValue>) -> OpState;
/// Get a JSON representation of the value in this node /// Get a JSON representation of the value in this node
fn view(&self) -> Value; fn view(&self) -> JsonValue;
} }
/// Enum representing possible outcomes of applying an operation to a CRDT /// Enum representing possible outcomes of applying an operation to a CRDT
@@ -60,14 +60,14 @@ pub enum OpState {
} }
/// The following types can be used as a 'terminal' type in CRDTs /// The following types can be used as a 'terminal' type in CRDTs
pub trait MarkPrimitive: Into<Value> + Default {} pub trait MarkPrimitive: Into<JsonValue> + Default {}
impl MarkPrimitive for bool {} impl MarkPrimitive for bool {}
impl MarkPrimitive for i32 {} impl MarkPrimitive for i32 {}
impl MarkPrimitive for i64 {} impl MarkPrimitive for i64 {}
impl MarkPrimitive for f64 {} impl MarkPrimitive for f64 {}
impl MarkPrimitive for char {} impl MarkPrimitive for char {}
impl MarkPrimitive for String {} impl MarkPrimitive for String {}
impl MarkPrimitive for Value {} impl MarkPrimitive for JsonValue {}
/// Implement CrdtNode for non-CRDTs /// Implement CrdtNode for non-CRDTs
/// This is a stub implementation so most functions don't do anything/log an error /// This is a stub implementation so most functions don't do anything/log an error
@@ -75,11 +75,11 @@ impl<T> CrdtNode for T
where where
T: CrdtNodeFromValue + MarkPrimitive + Hashable + Clone, T: CrdtNodeFromValue + MarkPrimitive + Hashable + Clone,
{ {
fn apply(&mut self, _op: Op<Value>) -> OpState { fn apply(&mut self, _op: Op<JsonValue>) -> OpState {
OpState::ErrApplyOnPrimitive OpState::ErrApplyOnPrimitive
} }
fn view(&self) -> Value { fn view(&self) -> JsonValue {
self.to_owned().into() self.to_owned().into()
} }
@@ -113,7 +113,7 @@ pub struct SignedOp {
author: AuthorId, author: AuthorId,
/// Signed hash using priv key of author. Effectively [`OpID`] Use this as the ID to figure out what has been delivered already /// Signed hash using priv key of author. Effectively [`OpID`] Use this as the ID to figure out what has been delivered already
pub signed_digest: SignedDigest, pub signed_digest: SignedDigest,
pub inner: Op<Value>, pub inner: Op<JsonValue>,
/// List of causal dependencies /// List of causal dependencies
pub depends_on: Vec<SignedDigest>, pub depends_on: Vec<SignedDigest>,
} }
@@ -245,26 +245,26 @@ impl<T: CrdtNode + DebugView> BaseCrdt<T> {
/// An enum representing a JSON value /// An enum representing a JSON value
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Value { pub enum JsonValue {
Null, Null,
Bool(bool), Bool(bool),
Number(f64), Number(f64),
String(String), String(String),
Array(Vec<Value>), Array(Vec<JsonValue>),
Object(HashMap<String, Value>), Object(HashMap<String, JsonValue>),
} }
impl Display for Value { impl Display for JsonValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(
f, f,
"{}", "{}",
match self { match self {
Value::Null => "null".to_string(), JsonValue::Null => "null".to_string(),
Value::Bool(b) => b.to_string(), JsonValue::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(), JsonValue::Number(n) => n.to_string(),
Value::String(s) => format!("\"{s}\""), JsonValue::String(s) => format!("\"{s}\""),
Value::Array(arr) => { JsonValue::Array(arr) => {
if arr.len() > 1 { if arr.len() > 1 {
format!( format!(
"[\n{}\n]", "[\n{}\n]",
@@ -283,7 +283,7 @@ impl Display for Value {
) )
} }
} }
Value::Object(obj) => format!( JsonValue::Object(obj) => format!(
"{{ {} }}", "{{ {} }}",
obj.iter() obj.iter()
.map(|(k, v)| format!(" \"{k}\": {v}")) .map(|(k, v)| format!(" \"{k}\": {v}"))
@@ -295,7 +295,7 @@ impl Display for Value {
} }
} }
impl Default for Value { impl Default for JsonValue {
fn default() -> Self { fn default() -> Self {
Self::Null Self::Null
} }
@@ -303,17 +303,19 @@ impl Default for Value {
/// Allow easy conversion to and from serde's JSON format. This allows us to use the [`json!`] /// Allow easy conversion to and from serde's JSON format. This allows us to use the [`json!`]
/// macro /// macro
impl From<Value> for serde_json::Value { impl From<JsonValue> for serde_json::Value {
fn from(value: Value) -> Self { fn from(value: JsonValue) -> Self {
match value { match value {
Value::Null => serde_json::Value::Null, JsonValue::Null => serde_json::Value::Null,
Value::Bool(x) => serde_json::Value::Bool(x), JsonValue::Bool(x) => serde_json::Value::Bool(x),
Value::Number(x) => serde_json::Value::Number(serde_json::Number::from_f64(x).unwrap()), JsonValue::Number(x) => {
Value::String(x) => serde_json::Value::String(x), serde_json::Value::Number(serde_json::Number::from_f64(x).unwrap())
Value::Array(x) => { }
JsonValue::String(x) => serde_json::Value::String(x),
JsonValue::Array(x) => {
serde_json::Value::Array(x.iter().map(|a| a.clone().into()).collect()) serde_json::Value::Array(x.iter().map(|a| a.clone().into()).collect())
} }
Value::Object(x) => serde_json::Value::Object( JsonValue::Object(x) => serde_json::Value::Object(
x.iter() x.iter()
.map(|(k, v)| (k.clone(), v.clone().into())) .map(|(k, v)| (k.clone(), v.clone().into()))
.collect(), .collect(),
@@ -322,17 +324,17 @@ impl From<Value> for serde_json::Value {
} }
} }
impl From<serde_json::Value> for Value { impl From<serde_json::Value> for JsonValue {
fn from(value: serde_json::Value) -> Self { fn from(value: serde_json::Value) -> Self {
match value { match value {
serde_json::Value::Null => Value::Null, serde_json::Value::Null => JsonValue::Null,
serde_json::Value::Bool(x) => Value::Bool(x), serde_json::Value::Bool(x) => JsonValue::Bool(x),
serde_json::Value::Number(x) => Value::Number(x.as_f64().unwrap()), serde_json::Value::Number(x) => JsonValue::Number(x.as_f64().unwrap()),
serde_json::Value::String(x) => Value::String(x), serde_json::Value::String(x) => JsonValue::String(x),
serde_json::Value::Array(x) => { serde_json::Value::Array(x) => {
Value::Array(x.iter().map(|a| a.clone().into()).collect()) JsonValue::Array(x.iter().map(|a| a.clone().into()).collect())
} }
serde_json::Value::Object(x) => Value::Object( serde_json::Value::Object(x) => JsonValue::Object(
x.iter() x.iter()
.map(|(k, v)| (k.clone(), v.clone().into())) .map(|(k, v)| (k.clone(), v.clone().into()))
.collect(), .collect(),
@@ -341,73 +343,73 @@ impl From<serde_json::Value> for Value {
} }
} }
impl Value { impl JsonValue {
pub fn into_json(self) -> serde_json::Value { pub fn into_json(self) -> serde_json::Value {
self.into() self.into()
} }
} }
/// Conversions from primitive types to [`Value`] /// Conversions from primitive types to [`Value`]
impl From<bool> for Value { impl From<bool> for JsonValue {
fn from(val: bool) -> Self { fn from(val: bool) -> Self {
Value::Bool(val) JsonValue::Bool(val)
} }
} }
impl From<i64> for Value { impl From<i64> for JsonValue {
fn from(val: i64) -> Self { fn from(val: i64) -> Self {
Value::Number(val as f64) JsonValue::Number(val as f64)
} }
} }
impl From<i32> for Value { impl From<i32> for JsonValue {
fn from(val: i32) -> Self { fn from(val: i32) -> Self {
Value::Number(val as f64) JsonValue::Number(val as f64)
} }
} }
impl From<f64> for Value { impl From<f64> for JsonValue {
fn from(val: f64) -> Self { fn from(val: f64) -> Self {
Value::Number(val) JsonValue::Number(val)
} }
} }
impl From<String> for Value { impl From<String> for JsonValue {
fn from(val: String) -> Self { fn from(val: String) -> Self {
Value::String(val) JsonValue::String(val)
} }
} }
impl From<char> for Value { impl From<char> for JsonValue {
fn from(val: char) -> Self { fn from(val: char) -> Self {
Value::String(val.into()) JsonValue::String(val.into())
} }
} }
impl<T> From<Option<T>> for Value impl<T> From<Option<T>> for JsonValue
where where
T: CrdtNode, T: CrdtNode,
{ {
fn from(val: Option<T>) -> Self { fn from(val: Option<T>) -> Self {
match val { match val {
Some(x) => x.view(), Some(x) => x.view(),
None => Value::Null, None => JsonValue::Null,
} }
} }
} }
impl<T> From<Vec<T>> for Value impl<T> From<Vec<T>> for JsonValue
where where
T: CrdtNode, T: CrdtNode,
{ {
fn from(value: Vec<T>) -> Self { fn from(value: Vec<T>) -> Self {
Value::Array(value.iter().map(|x| x.view()).collect()) JsonValue::Array(value.iter().map(|x| x.view()).collect())
} }
} }
/// Fallibly create a CRDT Node from a JSON Value /// Fallibly create a CRDT Node from a JSON Value
pub trait CrdtNodeFromValue: Sized { pub trait CrdtNodeFromValue: Sized {
fn node_from(value: Value, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String>; fn node_from(value: JsonValue, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String>;
} }
/// Fallibly cast a JSON Value into a CRDT Node /// Fallibly cast a JSON Value into a CRDT Node
@@ -416,7 +418,7 @@ pub trait IntoCrdtNode<T>: Sized {
} }
/// [`CrdtNodeFromValue`] implies [`IntoCRDTNode<T>`] /// [`CrdtNodeFromValue`] implies [`IntoCRDTNode<T>`]
impl<T> IntoCrdtNode<T> for Value impl<T> IntoCrdtNode<T> for JsonValue
where where
T: CrdtNodeFromValue, T: CrdtNodeFromValue,
{ {
@@ -426,16 +428,16 @@ where
} }
/// Trivial conversion from Value to Value as CrdtNodeFromValue /// Trivial conversion from Value to Value as CrdtNodeFromValue
impl CrdtNodeFromValue for Value { impl CrdtNodeFromValue for JsonValue {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
Ok(value) Ok(value)
} }
} }
/// Conversions from primitives to CRDTs /// Conversions from primitives to CRDTs
impl CrdtNodeFromValue for bool { impl CrdtNodeFromValue for bool {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Bool(x) = value { if let JsonValue::Bool(x) = value {
Ok(x) Ok(x)
} else { } else {
Err(format!("failed to convert {value:?} -> bool")) Err(format!("failed to convert {value:?} -> bool"))
@@ -444,8 +446,8 @@ impl CrdtNodeFromValue for bool {
} }
impl CrdtNodeFromValue for f64 { impl CrdtNodeFromValue for f64 {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Number(x) = value { if let JsonValue::Number(x) = value {
Ok(x) Ok(x)
} else { } else {
Err(format!("failed to convert {value:?} -> f64")) Err(format!("failed to convert {value:?} -> f64"))
@@ -454,8 +456,8 @@ impl CrdtNodeFromValue for f64 {
} }
impl CrdtNodeFromValue for i64 { impl CrdtNodeFromValue for i64 {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Number(x) = value { if let JsonValue::Number(x) = value {
Ok(x as i64) Ok(x as i64)
} else { } else {
Err(format!("failed to convert {value:?} -> f64")) Err(format!("failed to convert {value:?} -> f64"))
@@ -464,8 +466,8 @@ impl CrdtNodeFromValue for i64 {
} }
impl CrdtNodeFromValue for String { impl CrdtNodeFromValue for String {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::String(x) = value { if let JsonValue::String(x) = value {
Ok(x) Ok(x)
} else { } else {
Err(format!("failed to convert {value:?} -> String")) Err(format!("failed to convert {value:?} -> String"))
@@ -474,8 +476,8 @@ impl CrdtNodeFromValue for String {
} }
impl CrdtNodeFromValue for char { impl CrdtNodeFromValue for char {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::String(x) = value.clone() { if let JsonValue::String(x) = value.clone() {
x.chars().next().ok_or(format!( x.chars().next().ok_or(format!(
"failed to convert {value:?} -> char: found a zero-length string" "failed to convert {value:?} -> char: found a zero-length string"
)) ))
@@ -489,7 +491,7 @@ impl<T> CrdtNodeFromValue for LwwRegisterCrdt<T>
where where
T: CrdtNode, T: CrdtNode,
{ {
fn node_from(value: Value, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String> {
let mut crdt = LwwRegisterCrdt::new(id, path); let mut crdt = LwwRegisterCrdt::new(id, path);
crdt.set(value); crdt.set(value);
Ok(crdt) Ok(crdt)
@@ -500,8 +502,8 @@ impl<T> CrdtNodeFromValue for ListCrdt<T>
where where
T: CrdtNode, T: CrdtNode,
{ {
fn node_from(value: Value, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String> { fn node_from(value: JsonValue, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Array(arr) = value { if let JsonValue::Array(arr) = value {
let mut crdt = ListCrdt::new(id, path); let mut crdt = ListCrdt::new(id, path);
let result: Result<(), String> = let result: Result<(), String> =
arr.into_iter().enumerate().try_for_each(|(i, val)| { arr.into_iter().enumerate().try_for_each(|(i, val)| {
@@ -521,7 +523,7 @@ mod test {
use serde_json::json; use serde_json::json;
use crate::{ use crate::{
json_crdt::{add_crdt_fields, BaseCrdt, CrdtNode, IntoCrdtNode, OpState, Value}, json_crdt::{add_crdt_fields, BaseCrdt, CrdtNode, IntoCrdtNode, JsonValue, OpState},
keypair::make_keypair, keypair::make_keypair,
list_crdt::ListCrdt, list_crdt::ListCrdt,
lww_crdt::LwwRegisterCrdt, lww_crdt::LwwRegisterCrdt,
@@ -697,7 +699,7 @@ mod test {
.set(3000.0) .set(3000.0)
.sign_with_dependencies(&kp1, vec![&_add_money]); .sign_with_dependencies(&kp1, vec![&_add_money]);
let sword: Value = json!({ let sword: JsonValue = json!({
"name": "Sword", "name": "Sword",
"soulbound": true, "soulbound": true,
}) })
@@ -748,8 +750,8 @@ mod test {
let mut base2 = BaseCrdt::<Game>::new(&kp2); let mut base2 = BaseCrdt::<Game>::new(&kp2);
// init a 2d grid // init a 2d grid
let row0: Value = json!([true, false]).into(); let row0: JsonValue = json!([true, false]).into();
let row1: Value = json!([false, true]).into(); let row1: JsonValue = json!([false, true]).into();
let construct1 = base1.doc.grid.insert_idx(0, row0).sign(&kp1); let construct1 = base1.doc.grid.insert_idx(0, row0).sign(&kp1);
let construct2 = base1.doc.grid.insert_idx(1, row1).sign(&kp1); let construct2 = base1.doc.grid.insert_idx(1, row1).sign(&kp1);
@@ -800,13 +802,13 @@ mod test {
#[add_crdt_fields] #[add_crdt_fields]
#[derive(Clone, CrdtNode)] #[derive(Clone, CrdtNode)]
struct Test { struct Test {
reg: LwwRegisterCrdt<Value>, reg: LwwRegisterCrdt<JsonValue>,
} }
let kp1 = make_keypair(); let kp1 = make_keypair();
let mut base1 = BaseCrdt::<Test>::new(&kp1); let mut base1 = BaseCrdt::<Test>::new(&kp1);
let base_val: Value = json!({ let base_val: JsonValue = json!({
"a": true, "a": true,
"b": "asdf", "b": "asdf",
"c": { "c": {
@@ -856,11 +858,11 @@ mod test {
assert_eq!(crdt.doc.reg.view(), json!(true).into()); assert_eq!(crdt.doc.reg.view(), json!(true).into());
// set nested // set nested
let mut list_view: Value = crdt.doc.strct.view().into(); let mut list_view: JsonValue = crdt.doc.strct.view().into();
assert_eq!(list_view, json!([]).into()); assert_eq!(list_view, json!([]).into());
// only keeps actual numbers // only keeps actual numbers
let list: Value = json!({"list": [0, 123, -0.45, "char", []]}).into(); let list: JsonValue = json!({"list": [0, 123, -0.45, "char", []]}).into();
crdt.doc.strct.insert_idx(0, list); crdt.doc.strct.insert_idx(0, list);
list_view = crdt.doc.strct.view().into(); list_view = crdt.doc.strct.view().into();
assert_eq!(list_view, json!([{ "list": [0, 123, -0.45]}]).into()); assert_eq!(list_view, json!([{ "list": [0, 123, -0.45]}]).into());

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
debug::debug_path_mismatch, debug::debug_path_mismatch,
json_crdt::{CrdtNode, OpState, Value}, json_crdt::{CrdtNode, JsonValue, OpState},
keypair::AuthorId, keypair::AuthorId,
op::*, op::*,
}; };
@@ -48,7 +48,7 @@ where
} }
/// Locally insert some content causally after the given operation /// Locally insert some content causally after the given operation
pub fn insert<U: Into<Value>>(&mut self, after: OpId, content: U) -> Op<Value> { pub fn insert<U: Into<JsonValue>>(&mut self, after: OpId, content: U) -> Op<JsonValue> {
let mut op = Op::new( let mut op = Op::new(
after, after,
self.our_id, self.our_id,
@@ -67,7 +67,11 @@ where
} }
/// Shorthand function to insert at index locally. Indexing ignores deleted items /// Shorthand function to insert at index locally. Indexing ignores deleted items
pub fn insert_idx<U: Into<Value> + Clone>(&mut self, idx: usize, content: U) -> Op<Value> { pub fn insert_idx<U: Into<JsonValue> + Clone>(
&mut self,
idx: usize,
content: U,
) -> Op<JsonValue> {
let mut i = 0; let mut i = 0;
for op in &self.ops { for op in &self.ops {
if !op.is_deleted { if !op.is_deleted {
@@ -97,7 +101,7 @@ where
/// Mark a node as deleted. If the node doesn't exist, it will be stuck /// Mark a node as deleted. If the node doesn't exist, it will be stuck
/// waiting for that node to be created. /// waiting for that node to be created.
pub fn delete(&mut self, id: OpId) -> Op<Value> { pub fn delete(&mut self, id: OpId) -> Op<JsonValue> {
let op = Op::new( let op = Op::new(
id, id,
self.our_id, self.our_id,
@@ -117,7 +121,7 @@ where
/// Apply an operation (both local and remote) to this local list CRDT. /// Apply an operation (both local and remote) to this local list CRDT.
/// Forwards it to a nested CRDT if necessary. /// Forwards it to a nested CRDT if necessary.
pub fn apply(&mut self, op: Op<Value>) -> OpState { pub fn apply(&mut self, op: Op<JsonValue>) -> OpState {
if !op.is_valid_hash() { if !op.is_valid_hash() {
return OpState::ErrHashMismatch; return OpState::ErrHashMismatch;
} }
@@ -308,11 +312,11 @@ impl<T> CrdtNode for ListCrdt<T>
where where
T: CrdtNode, T: CrdtNode,
{ {
fn apply(&mut self, op: Op<Value>) -> OpState { fn apply(&mut self, op: Op<JsonValue>) -> OpState {
self.apply(op.into()) self.apply(op.into())
} }
fn view(&self) -> Value { fn view(&self) -> JsonValue {
self.view().into() self.view().into()
} }

View File

@@ -1,5 +1,5 @@
use crate::debug::DebugView; use crate::debug::DebugView;
use crate::json_crdt::{CrdtNode, OpState, Value}; use crate::json_crdt::{CrdtNode, OpState, JsonValue};
use crate::op::{join_path, print_path, Op, PathSegment, SequenceNumber}; use crate::op::{join_path, print_path, Op, PathSegment, SequenceNumber};
use std::cmp::{max, Ordering}; use std::cmp::{max, Ordering};
use std::fmt::Debug; use std::fmt::Debug;
@@ -38,7 +38,7 @@ where
} }
/// Sets the current value of the register /// Sets the current value of the register
pub fn set<U: Into<Value>>(&mut self, content: U) -> Op<Value> { pub fn set<U: Into<JsonValue>>(&mut self, content: U) -> Op<JsonValue> {
let mut op = Op::new( let mut op = Op::new(
self.value.id, self.value.id,
self.our_id, self.our_id,
@@ -57,7 +57,7 @@ where
} }
/// Apply an operation (both local and remote) to this local register CRDT. /// Apply an operation (both local and remote) to this local register CRDT.
pub fn apply(&mut self, op: Op<Value>) -> OpState { pub fn apply(&mut self, op: Op<JsonValue>) -> OpState {
if !op.is_valid_hash() { if !op.is_valid_hash() {
return OpState::ErrHashMismatch; return OpState::ErrHashMismatch;
} }
@@ -100,11 +100,11 @@ impl<T> CrdtNode for LwwRegisterCrdt<T>
where where
T: CrdtNode, T: CrdtNode,
{ {
fn apply(&mut self, op: Op<Value>) -> OpState { fn apply(&mut self, op: Op<JsonValue>) -> OpState {
self.apply(op.into()) self.apply(op.into())
} }
fn view(&self) -> Value { fn view(&self) -> JsonValue {
self.view().into() self.view().into()
} }

View File

@@ -1,5 +1,5 @@
use crate::debug::{debug_path_mismatch, debug_type_mismatch}; use crate::debug::{debug_path_mismatch, debug_type_mismatch};
use crate::json_crdt::{CrdtNode, CrdtNodeFromValue, IntoCrdtNode, SignedOp, Value}; use crate::json_crdt::{CrdtNode, CrdtNodeFromValue, IntoCrdtNode, JsonValue, SignedOp};
use crate::keypair::{sha256, AuthorId}; use crate::keypair::{sha256, AuthorId};
use fastcrypto::ed25519::Ed25519KeyPair; use fastcrypto::ed25519::Ed25519KeyPair;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -112,7 +112,7 @@ where
} }
/// Conversion from Op<Value> -> Op<T> given that T is a CRDT that can be created from a JSON value /// Conversion from Op<Value> -> Op<T> given that T is a CRDT that can be created from a JSON value
impl Op<Value> { impl Op<JsonValue> {
pub fn into<T: CrdtNodeFromValue + CrdtNode>(self) -> Op<T> { pub fn into<T: CrdtNodeFromValue + CrdtNode>(self) -> Op<T> {
let content = if let Some(inner_content) = self.content { let content = if let Some(inner_content) = self.content {
match inner_content.into_node(self.id, self.path.clone()) { match inner_content.into_node(self.id, self.path.clone()) {

View File

@@ -1,7 +1,7 @@
use bft_json_crdt::{ use bft_json_crdt::{
keypair::make_author, keypair::make_author,
list_crdt::ListCrdt, list_crdt::ListCrdt,
op::{Op, OpId, ROOT_ID}, json_crdt::{CrdtNode, Value}, op::{Op, OpId, ROOT_ID}, json_crdt::{CrdtNode, JsonValue},
}; };
use rand::{rngs::ThreadRng, seq::SliceRandom, Rng}; use rand::{rngs::ThreadRng, seq::SliceRandom, Rng};
@@ -14,9 +14,9 @@ const TEST_N: usize = 100;
#[test] #[test]
fn test_list_fuzz_commutative() { fn test_list_fuzz_commutative() {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut op_log = Vec::<Op<Value>>::new(); let mut op_log = Vec::<Op<JsonValue>>::new();
let mut op_log1 = Vec::<Op<Value>>::new(); let mut op_log1 = Vec::<Op<JsonValue>>::new();
let mut op_log2 = Vec::<Op<Value>>::new(); let mut op_log2 = Vec::<Op<JsonValue>>::new();
let mut l1 = ListCrdt::<char>::new(make_author(1), vec![]); let mut l1 = ListCrdt::<char>::new(make_author(1), vec![]);
let mut l2 = ListCrdt::<char>::new(make_author(2), vec![]); let mut l2 = ListCrdt::<char>::new(make_author(2), vec![]);
let mut chk = ListCrdt::<char>::new(make_author(3), vec![]); let mut chk = ListCrdt::<char>::new(make_author(3), vec![]);
@@ -62,8 +62,8 @@ fn test_list_fuzz_commutative() {
assert_eq!(l2_doc, chk_doc); assert_eq!(l2_doc, chk_doc);
// now, allow cross mixing between both // now, allow cross mixing between both
let mut op_log1 = Vec::<Op<Value>>::new(); let mut op_log1 = Vec::<Op<JsonValue>>::new();
let mut op_log2 = Vec::<Op<Value>>::new(); let mut op_log2 = Vec::<Op<JsonValue>>::new();
for _ in 0..TEST_N { for _ in 0..TEST_N {
let letter1: char = rng.gen_range(b'a'..=b'z') as char; let letter1: char = rng.gen_range(b'a'..=b'z') as char;
let letter2: char = rng.gen_range(b'a'..=b'z') as char; let letter2: char = rng.gen_range(b'a'..=b'z') as char;