jmbl 0.5.0

A high performance CRDT
Documentation
use std::convert::TryInto;
use thiserror::Error;

use crate::{
    list::list_view::ListView, map::map_view::MapView, ops::ObjID, text::text_view::TextView,
};

use super::ObjView;

#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub enum Value {
    Plain(litl::Val),
    ReadView(ObjView),
    WriteView(ObjView),
}

impl Value {
    pub fn str(value: &str) -> Value {
        Value::Plain(litl::Val::str(value))
    }

    pub fn plain(value: litl::Val) -> Value {
        Value::Plain(value)
    }

    pub(super) fn read_view(view: ObjView) -> Value {
        Value::ReadView(view)
    }

    pub(super) fn write_view(view: ObjView) -> Value {
        Value::WriteView(view)
    }
}

impl Value {
    pub fn if_obj(&self) -> Result<&ObjView, ValueError> {
        self.try_into()
    }

    pub fn if_map(&self) -> Result<&MapView, ValueError> {
        let obj: &ObjView = self.try_into()?;
        obj.try_into()
    }

    pub fn if_list(&self) -> Result<&ListView, ValueError> {
        let obj: &ObjView = self.try_into()?;
        obj.try_into()
    }

    pub fn if_text(&self) -> Result<&TextView, ValueError> {
        let obj: &ObjView = self.try_into()?;
        obj.try_into()
    }

    pub fn if_mut_obj(&mut self) -> Result<&mut ObjView, ValueError> {
        self.try_into()
    }

    pub fn if_map_mut(&mut self) -> Result<&mut MapView, ValueError> {
        let obj: &mut ObjView = self.try_into()?;
        obj.try_into()
    }

    pub fn if_list_mut(&mut self) -> Result<&mut ListView, ValueError> {
        let obj: &mut ObjView = self.try_into()?;
        obj.try_into()
    }

    pub fn if_text_mut(&mut self) -> Result<&mut TextView, ValueError> {
        let obj: &mut ObjView = self.try_into()?;
        obj.try_into()
    }

    pub fn if_plain(&self) -> Result<&litl::Val, ValueError> {
        match &self {
            Value::Plain(plain) => Ok(plain),
            Value::ReadView(view) | Value::WriteView(view) => {
                Err(ValueError::ExpectedPlainButGotCollaborative(view.clone()))
            }
        }
    }

    pub fn to_litl(&self) -> litl::Val {
        match &self {
            Value::Plain(value) => value.clone(),
            Value::ReadView(view) | Value::WriteView(view) => view.to_litl(),
        }
    }

    pub fn obj_id(&self) -> Option<ObjID> {
        match &self {
            Value::Plain(_) => None,
            Value::ReadView(view) | Value::WriteView(view) => Some(view.get_obj_id()),
        }
    }
}

impl TryInto<ObjView> for Value {
    type Error = ValueError;

    fn try_into(self) -> Result<ObjView, Self::Error> {
        match self {
            Value::ReadView(view) | Value::WriteView(view) => Ok(view),
            Value::Plain(val) => Err(ValueError::ExpectedCollaborativeButGotPlain(val)),
        }
    }
}

impl<'a> TryInto<&'a ObjView> for &'a Value {
    type Error = ValueError;

    fn try_into(self) -> Result<&'a ObjView, Self::Error> {
        match &self {
            Value::ReadView(view) | Value::WriteView(view) => Ok(view),
            Value::Plain(val) => Err(ValueError::ExpectedCollaborativeButGotPlain(val.clone())),
        }
    }
}

impl<'a> TryInto<&'a mut ObjView> for &'a mut Value {
    type Error = ValueError;

    fn try_into(self) -> Result<&'a mut ObjView, Self::Error> {
        match self {
            Value::ReadView(_) => Err(ValueError::ExpectedMutableCollaborativeObj),
            Value::WriteView(view) => Ok(view),
            Value::Plain(val) => Err(ValueError::ExpectedCollaborativeButGotPlain(val.clone())),
        }
    }
}

#[derive(Error, Debug, PartialEq, Eq)]
#[allow(clippy::enum_variant_names)]
pub enum ValueError {
    #[error("Expected plain value but got collaborative object {0:?}")]
    ExpectedPlainButGotCollaborative(ObjView),
    #[error("Expected collaborative object but got plain value {0:?}")]
    ExpectedCollaborativeButGotPlain(litl::Val),
    #[error("Expected collaborative map but got {0:?}")]
    ExpectedMap(ObjView),
    #[error("Expected collaborative list but got {0:?}")]
    ExpectedList(ObjView),
    #[error("Expected collaborative text but got {0:?}")]
    ExpectedText(ObjView),
    // TODO(refactor): #32 does this belong somewhere else?
    #[error("Expected mutable collaborative object")]
    ExpectedMutableCollaborativeObj,
}