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

@@ -23,9 +23,9 @@ pub trait CrdtNode: CrdtNodeFromValue + Hashable + Clone {
/// Create a new CRDT of this type
fn new(id: AuthorId, path: Vec<PathSegment>) -> Self;
/// 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
fn view(&self) -> Value;
fn view(&self) -> JsonValue;
}
/// 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
pub trait MarkPrimitive: Into<Value> + Default {}
pub trait MarkPrimitive: Into<JsonValue> + Default {}
impl MarkPrimitive for bool {}
impl MarkPrimitive for i32 {}
impl MarkPrimitive for i64 {}
impl MarkPrimitive for f64 {}
impl MarkPrimitive for char {}
impl MarkPrimitive for String {}
impl MarkPrimitive for Value {}
impl MarkPrimitive for JsonValue {}
/// Implement CrdtNode for non-CRDTs
/// 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
T: CrdtNodeFromValue + MarkPrimitive + Hashable + Clone,
{
fn apply(&mut self, _op: Op<Value>) -> OpState {
fn apply(&mut self, _op: Op<JsonValue>) -> OpState {
OpState::ErrApplyOnPrimitive
}
fn view(&self) -> Value {
fn view(&self) -> JsonValue {
self.to_owned().into()
}
@@ -113,7 +113,7 @@ pub struct SignedOp {
author: AuthorId,
/// 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 inner: Op<Value>,
pub inner: Op<JsonValue>,
/// List of causal dependencies
pub depends_on: Vec<SignedDigest>,
}
@@ -245,26 +245,26 @@ impl<T: CrdtNode + DebugView> BaseCrdt<T> {
/// An enum representing a JSON value
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
pub enum JsonValue {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<Value>),
Object(HashMap<String, Value>),
Array(Vec<JsonValue>),
Object(HashMap<String, JsonValue>),
}
impl Display for Value {
impl Display for JsonValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Value::Null => "null".to_string(),
Value::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(),
Value::String(s) => format!("\"{s}\""),
Value::Array(arr) => {
JsonValue::Null => "null".to_string(),
JsonValue::Bool(b) => b.to_string(),
JsonValue::Number(n) => n.to_string(),
JsonValue::String(s) => format!("\"{s}\""),
JsonValue::Array(arr) => {
if arr.len() > 1 {
format!(
"[\n{}\n]",
@@ -283,7 +283,7 @@ impl Display for Value {
)
}
}
Value::Object(obj) => format!(
JsonValue::Object(obj) => format!(
"{{ {} }}",
obj.iter()
.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 {
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!`]
/// macro
impl From<Value> for serde_json::Value {
fn from(value: Value) -> Self {
impl From<JsonValue> for serde_json::Value {
fn from(value: JsonValue) -> Self {
match value {
Value::Null => serde_json::Value::Null,
Value::Bool(x) => serde_json::Value::Bool(x),
Value::Number(x) => serde_json::Value::Number(serde_json::Number::from_f64(x).unwrap()),
Value::String(x) => serde_json::Value::String(x),
Value::Array(x) => {
JsonValue::Null => serde_json::Value::Null,
JsonValue::Bool(x) => serde_json::Value::Bool(x),
JsonValue::Number(x) => {
serde_json::Value::Number(serde_json::Number::from_f64(x).unwrap())
}
JsonValue::String(x) => serde_json::Value::String(x),
JsonValue::Array(x) => {
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()
.map(|(k, v)| (k.clone(), v.clone().into()))
.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 {
match value {
serde_json::Value::Null => Value::Null,
serde_json::Value::Bool(x) => Value::Bool(x),
serde_json::Value::Number(x) => Value::Number(x.as_f64().unwrap()),
serde_json::Value::String(x) => Value::String(x),
serde_json::Value::Null => JsonValue::Null,
serde_json::Value::Bool(x) => JsonValue::Bool(x),
serde_json::Value::Number(x) => JsonValue::Number(x.as_f64().unwrap()),
serde_json::Value::String(x) => JsonValue::String(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()
.map(|(k, v)| (k.clone(), v.clone().into()))
.collect(),
@@ -341,73 +343,73 @@ impl From<serde_json::Value> for Value {
}
}
impl Value {
impl JsonValue {
pub fn into_json(self) -> serde_json::Value {
self.into()
}
}
/// Conversions from primitive types to [`Value`]
impl From<bool> for Value {
impl From<bool> for JsonValue {
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 {
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 {
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 {
Value::Number(val)
JsonValue::Number(val)
}
}
impl From<String> for Value {
impl From<String> for JsonValue {
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 {
Value::String(val.into())
JsonValue::String(val.into())
}
}
impl<T> From<Option<T>> for Value
impl<T> From<Option<T>> for JsonValue
where
T: CrdtNode,
{
fn from(val: Option<T>) -> Self {
match val {
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
T: CrdtNode,
{
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
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
@@ -416,7 +418,7 @@ pub trait IntoCrdtNode<T>: Sized {
}
/// [`CrdtNodeFromValue`] implies [`IntoCRDTNode<T>`]
impl<T> IntoCrdtNode<T> for Value
impl<T> IntoCrdtNode<T> for JsonValue
where
T: CrdtNodeFromValue,
{
@@ -426,16 +428,16 @@ where
}
/// Trivial conversion from Value to Value as CrdtNodeFromValue
impl CrdtNodeFromValue for Value {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
impl CrdtNodeFromValue for JsonValue {
fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
Ok(value)
}
}
/// Conversions from primitives to CRDTs
impl CrdtNodeFromValue for bool {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Bool(x) = value {
fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let JsonValue::Bool(x) = value {
Ok(x)
} else {
Err(format!("failed to convert {value:?} -> bool"))
@@ -444,8 +446,8 @@ impl CrdtNodeFromValue for bool {
}
impl CrdtNodeFromValue for f64 {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Number(x) = value {
fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let JsonValue::Number(x) = value {
Ok(x)
} else {
Err(format!("failed to convert {value:?} -> f64"))
@@ -454,8 +456,8 @@ impl CrdtNodeFromValue for f64 {
}
impl CrdtNodeFromValue for i64 {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Number(x) = value {
fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let JsonValue::Number(x) = value {
Ok(x as i64)
} else {
Err(format!("failed to convert {value:?} -> f64"))
@@ -464,8 +466,8 @@ impl CrdtNodeFromValue for i64 {
}
impl CrdtNodeFromValue for String {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::String(x) = value {
fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let JsonValue::String(x) = value {
Ok(x)
} else {
Err(format!("failed to convert {value:?} -> String"))
@@ -474,8 +476,8 @@ impl CrdtNodeFromValue for String {
}
impl CrdtNodeFromValue for char {
fn node_from(value: Value, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::String(x) = value.clone() {
fn node_from(value: JsonValue, _id: AuthorId, _path: Vec<PathSegment>) -> Result<Self, String> {
if let JsonValue::String(x) = value.clone() {
x.chars().next().ok_or(format!(
"failed to convert {value:?} -> char: found a zero-length string"
))
@@ -489,7 +491,7 @@ impl<T> CrdtNodeFromValue for LwwRegisterCrdt<T>
where
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);
crdt.set(value);
Ok(crdt)
@@ -500,8 +502,8 @@ impl<T> CrdtNodeFromValue for ListCrdt<T>
where
T: CrdtNode,
{
fn node_from(value: Value, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String> {
if let Value::Array(arr) = value {
fn node_from(value: JsonValue, id: AuthorId, path: Vec<PathSegment>) -> Result<Self, String> {
if let JsonValue::Array(arr) = value {
let mut crdt = ListCrdt::new(id, path);
let result: Result<(), String> =
arr.into_iter().enumerate().try_for_each(|(i, val)| {
@@ -521,7 +523,7 @@ mod test {
use serde_json::json;
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,
list_crdt::ListCrdt,
lww_crdt::LwwRegisterCrdt,
@@ -697,7 +699,7 @@ mod test {
.set(3000.0)
.sign_with_dependencies(&kp1, vec![&_add_money]);
let sword: Value = json!({
let sword: JsonValue = json!({
"name": "Sword",
"soulbound": true,
})
@@ -748,8 +750,8 @@ mod test {
let mut base2 = BaseCrdt::<Game>::new(&kp2);
// init a 2d grid
let row0: Value = json!([true, false]).into();
let row1: Value = json!([false, true]).into();
let row0: JsonValue = json!([true, false]).into();
let row1: JsonValue = json!([false, true]).into();
let construct1 = base1.doc.grid.insert_idx(0, row0).sign(&kp1);
let construct2 = base1.doc.grid.insert_idx(1, row1).sign(&kp1);
@@ -800,13 +802,13 @@ mod test {
#[add_crdt_fields]
#[derive(Clone, CrdtNode)]
struct Test {
reg: LwwRegisterCrdt<Value>,
reg: LwwRegisterCrdt<JsonValue>,
}
let kp1 = make_keypair();
let mut base1 = BaseCrdt::<Test>::new(&kp1);
let base_val: Value = json!({
let base_val: JsonValue = json!({
"a": true,
"b": "asdf",
"c": {
@@ -856,11 +858,11 @@ mod test {
assert_eq!(crdt.doc.reg.view(), json!(true).into());
// 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());
// 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);
list_view = crdt.doc.strct.view().into();
assert_eq!(list_view, json!([{ "list": [0, 123, -0.45]}]).into());