automerge 0.11.0

A JSON-like data structure (a CRDT) that can be modified concurrently by different users, and merged again automatically
Documentation
use std::{collections::HashMap, fmt::Display};

use crate::{text_value::ConcreteTextValue, PatchAction, ScalarValue, TextEncoding};

use super::HydrateError;

#[derive(Clone, PartialEq)]
pub struct Text {
    value: ConcreteTextValue,
    marks: HashMap<String, ScalarValue>,
}

impl std::fmt::Debug for Text {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Text")
            .field("value", &self.value.make_string())
            .field("marks", &self.marks)
            .finish()
    }
}

impl Text {
    pub(crate) fn apply(
        &mut self,
        text_encoding: TextEncoding,
        patch: PatchAction,
    ) -> Result<(), HydrateError> {
        match patch {
            PatchAction::SpliceText { index, value, .. } => {
                self.value
                    .splice_text_value(index, &value)
                    .map_err(|_| HydrateError::InvalidEncoding)?;
                Ok(())
            }
            PatchAction::Insert { index, values } => {
                let mut index = index;
                for value in values.iter() {
                    let value = super::Value::new(value.0.clone(), text_encoding);
                    let text = value.as_str();
                    self.value.splice(index, text);
                    index += text_encoding.width(text);
                }
                Ok(())
            }
            PatchAction::PutSeq { index, value, .. } => {
                self.value.remove(index);
                let value = super::Value::new(value.0, text_encoding);
                self.value.splice(index, value.as_str());
                Ok(())
            }
            PatchAction::DeleteSeq { index, length } => {
                for _ in 0..length {
                    self.value.remove(index);
                }
                Ok(())
            }
            PatchAction::Mark { marks: _ } => {
                todo!()
            }
            p => Err(HydrateError::InvalidTextOp(p)),
        }
    }

    pub fn new<S: AsRef<str>>(text_encoding: TextEncoding, text: S) -> Self {
        Self {
            value: ConcreteTextValue::new(text.as_ref(), text_encoding),
            marks: Default::default(),
        }
    }
}

impl From<&Text> for String {
    fn from(text: &Text) -> Self {
        text.value.make_string()
    }
}

impl Display for Text {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.value.make_string())
    }
}

impl From<ConcreteTextValue> for Text {
    fn from(value: ConcreteTextValue) -> Self {
        Self {
            value,
            marks: Default::default(),
        }
    }
}

impl From<&ConcreteTextValue> for Text {
    fn from(value: &ConcreteTextValue) -> Self {
        Self::from(value.clone())
    }
}

impl From<ConcreteTextValue> for crate::hydrate::Value {
    fn from(value: ConcreteTextValue) -> Self {
        crate::hydrate::Value::Text(Text::from(value))
    }
}

impl From<&ConcreteTextValue> for crate::hydrate::Value {
    fn from(value: &ConcreteTextValue) -> Self {
        Self::from(value.clone())
    }
}