use std::fmt;
use super::list::List;
use crate::crdt::{
CRDTError, Doc,
traits::{CRDT, Data},
};
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Value {
Null,
Bool(bool),
Int(i64),
Text(String),
Doc(Doc),
List(List),
Deleted,
}
impl Value {
pub fn is_leaf(&self) -> bool {
matches!(
self,
Value::Null | Value::Bool(_) | Value::Int(_) | Value::Text(_) | Value::Deleted
)
}
pub fn is_branch(&self) -> bool {
matches!(self, Value::Doc(_) | Value::List(_))
}
pub fn is_deleted(&self) -> bool {
matches!(self, Value::Deleted)
}
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
pub fn type_name(&self) -> &'static str {
match self {
Value::Null => "null",
Value::Bool(_) => "bool",
Value::Int(_) => "int",
Value::Text(_) => "text",
Value::Doc(_) => "doc",
Value::List(_) => "list",
Value::Deleted => "deleted",
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_bool_or(&self, default: bool) -> bool {
self.as_bool().unwrap_or(default)
}
pub fn as_bool_or_false(&self) -> bool {
self.as_bool().unwrap_or(false)
}
pub fn as_int(&self) -> Option<i64> {
match self {
Value::Int(n) => Some(*n),
_ => None,
}
}
pub fn as_int_or(&self, default: i64) -> i64 {
self.as_int().unwrap_or(default)
}
pub fn as_int_or_zero(&self) -> i64 {
self.as_int().unwrap_or(0)
}
pub fn as_text(&self) -> Option<&str> {
match self {
Value::Text(s) => Some(s),
_ => None,
}
}
pub fn as_text_or_empty(&self) -> &str {
self.as_text().unwrap_or("")
}
pub fn as_doc(&self) -> Option<&Doc> {
match self {
Value::Doc(node) => Some(node),
_ => None,
}
}
pub fn as_doc_mut(&mut self) -> Option<&mut Doc> {
match self {
Value::Doc(node) => Some(node),
_ => None,
}
}
pub fn as_list(&self) -> Option<&List> {
match self {
Value::List(list) => Some(list),
_ => None,
}
}
pub fn as_list_mut(&mut self) -> Option<&mut List> {
match self {
Value::List(list) => Some(list),
_ => None,
}
}
pub fn merge(&mut self, other: &Value) {
if matches!(self, Value::Deleted) {
*self = other.clone();
return;
}
if matches!(other, Value::Deleted) {
*self = Value::Deleted;
return;
}
match other {
Value::Doc(other_node) => {
if let Value::Doc(self_node) = self {
match self_node.merge(other_node) {
Ok(merged) => *self_node = merged,
Err(_) => *self = other.clone(), }
} else {
*self = other.clone();
}
}
Value::List(other_list) => {
if let Value::List(self_list) = self {
self_list.merge(other_list);
} else {
*self = other.clone();
}
}
_ => {
*self = other.clone();
}
}
}
pub fn to_json_string(&self) -> String {
match self {
Value::Null => "null".to_string(),
Value::Bool(b) => b.to_string(),
Value::Int(n) => n.to_string(),
Value::Text(s) => format!("\"{}\"", s.replace('\"', "\\\"")),
Value::Doc(doc) => doc.to_json_string(),
Value::List(list) => {
let mut result = String::with_capacity(list.len() * 8); result.push('[');
for (i, item) in list.iter().enumerate() {
if i > 0 {
result.push(',');
}
result.push_str(&item.to_json_string());
}
result.push(']');
result
}
Value::Deleted => "null".to_string(), }
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Null => write!(f, "null"),
Value::Bool(b) => write!(f, "{b}"),
Value::Int(n) => write!(f, "{n}"),
Value::Text(s) => write!(f, "{s}"),
Value::Doc(doc) => write!(f, "{doc}"),
Value::List(list) => {
write!(f, "[")?;
for (i, item) in list.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{item}")?;
}
write!(f, "]")
}
Value::Deleted => write!(f, "<deleted>"),
}
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Value::Bool(value)
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Value::Int(value)
}
}
impl From<u64> for Value {
fn from(value: u64) -> Self {
Value::Int(value as i64)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Value::Int(value as i64)
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Value::Int(value as i64)
}
}
impl From<u32> for Value {
fn from(value: u32) -> Self {
Value::Int(value as i64)
}
}
impl From<f32> for Value {
fn from(value: f32) -> Self {
Value::Int(value as i64)
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::Text(value)
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Value::Text(value.to_string())
}
}
impl From<Doc> for Value {
fn from(value: Doc) -> Self {
Value::Doc(value)
}
}
impl From<List> for Value {
fn from(value: List) -> Self {
Value::List(value)
}
}
impl TryFrom<&Value> for String {
type Error = CRDTError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::Text(s) => Ok(s.clone()),
_ => Err(CRDTError::TypeMismatch {
expected: "String".to_string(),
actual: format!("{value:?}"),
}),
}
}
}
impl<'a> TryFrom<&'a Value> for &'a str {
type Error = CRDTError;
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
match value {
Value::Text(s) => Ok(s),
_ => Err(CRDTError::TypeMismatch {
expected: "&str".to_string(),
actual: format!("{value:?}"),
}),
}
}
}
impl TryFrom<&Value> for i64 {
type Error = CRDTError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::Int(n) => Ok(*n),
_ => Err(CRDTError::TypeMismatch {
expected: "i64".to_string(),
actual: format!("{value:?}"),
}),
}
}
}
impl TryFrom<&Value> for bool {
type Error = CRDTError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::Bool(b) => Ok(*b),
_ => Err(CRDTError::TypeMismatch {
expected: "bool".to_string(),
actual: format!("{value:?}"),
}),
}
}
}
impl TryFrom<&Value> for Doc {
type Error = CRDTError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::Doc(doc) => Ok(doc.clone()),
_ => Err(CRDTError::TypeMismatch {
expected: "Doc".to_string(),
actual: format!("{value:?}"),
}),
}
}
}
impl TryFrom<&Value> for List {
type Error = CRDTError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::List(list) => Ok(list.clone()),
_ => Err(CRDTError::TypeMismatch {
expected: "List".to_string(),
actual: format!("{value:?}"),
}),
}
}
}
impl PartialEq<str> for Value {
fn eq(&self, other: &str) -> bool {
match self {
Value::Text(s) => s == other,
_ => false,
}
}
}
impl PartialEq<&str> for Value {
fn eq(&self, other: &&str) -> bool {
self == *other
}
}
impl PartialEq<String> for Value {
fn eq(&self, other: &String) -> bool {
match self {
Value::Text(s) => s == other,
_ => false,
}
}
}
impl PartialEq<i64> for Value {
fn eq(&self, other: &i64) -> bool {
match self {
Value::Int(n) => n == other,
_ => false,
}
}
}
impl PartialEq<i32> for Value {
fn eq(&self, other: &i32) -> bool {
match self {
Value::Int(n) => *n == *other as i64,
_ => false,
}
}
}
impl PartialEq<u32> for Value {
fn eq(&self, other: &u32) -> bool {
match self {
Value::Int(n) => *n == *other as i64,
_ => false,
}
}
}
impl PartialEq<bool> for Value {
fn eq(&self, other: &bool) -> bool {
match self {
Value::Bool(b) => b == other,
_ => false,
}
}
}
impl PartialEq<Value> for str {
fn eq(&self, other: &Value) -> bool {
other == self
}
}
impl PartialEq<Value> for &str {
fn eq(&self, other: &Value) -> bool {
other == *self
}
}
impl PartialEq<Value> for String {
fn eq(&self, other: &Value) -> bool {
other == self
}
}
impl PartialEq<Value> for i64 {
fn eq(&self, other: &Value) -> bool {
other == self
}
}
impl PartialEq<Value> for i32 {
fn eq(&self, other: &Value) -> bool {
other == self
}
}
impl PartialEq<Value> for u32 {
fn eq(&self, other: &Value) -> bool {
other == self
}
}
impl PartialEq<Value> for bool {
fn eq(&self, other: &Value) -> bool {
other == self
}
}
impl Data for Value {}