1use std::convert::TryInto;
2use thiserror::Error;
3
4use crate::{
5    list::list_view::ListView, map::map_view::MapView, ops::ObjID, text::text_view::TextView,
6};
7
8use super::ObjView;
9
10#[derive(PartialEq, Eq, Hash, Debug, Clone)]
11pub enum Value {
12    Plain(litl::Val),
13    ReadView(ObjView),
14    WriteView(ObjView),
15}
16
17impl Value {
18    pub fn str(value: &str) -> Value {
19        Value::Plain(litl::Val::str(value))
20    }
21
22    pub fn plain(value: litl::Val) -> Value {
23        Value::Plain(value)
24    }
25
26    pub(super) fn read_view(view: ObjView) -> Value {
27        Value::ReadView(view)
28    }
29
30    pub(super) fn write_view(view: ObjView) -> Value {
31        Value::WriteView(view)
32    }
33}
34
35impl Value {
36    pub fn if_obj(&self) -> Result<&ObjView, ValueError> {
37        self.try_into()
38    }
39
40    pub fn if_map(&self) -> Result<&MapView, ValueError> {
41        let obj: &ObjView = self.try_into()?;
42        obj.try_into()
43    }
44
45    pub fn if_list(&self) -> Result<&ListView, ValueError> {
46        let obj: &ObjView = self.try_into()?;
47        obj.try_into()
48    }
49
50    pub fn if_text(&self) -> Result<&TextView, ValueError> {
51        let obj: &ObjView = self.try_into()?;
52        obj.try_into()
53    }
54
55    pub fn if_mut_obj(&mut self) -> Result<&mut ObjView, ValueError> {
56        self.try_into()
57    }
58
59    pub fn if_map_mut(&mut self) -> Result<&mut MapView, ValueError> {
60        let obj: &mut ObjView = self.try_into()?;
61        obj.try_into()
62    }
63
64    pub fn if_list_mut(&mut self) -> Result<&mut ListView, ValueError> {
65        let obj: &mut ObjView = self.try_into()?;
66        obj.try_into()
67    }
68
69    pub fn if_text_mut(&mut self) -> Result<&mut TextView, ValueError> {
70        let obj: &mut ObjView = self.try_into()?;
71        obj.try_into()
72    }
73
74    pub fn if_plain(&self) -> Result<&litl::Val, ValueError> {
75        match &self {
76            Value::Plain(plain) => Ok(plain),
77            Value::ReadView(view) | Value::WriteView(view) => {
78                Err(ValueError::ExpectedPlainButGotCollaborative(view.clone()))
79            }
80        }
81    }
82
83    pub fn val_to_litl(&self) -> litl::Val {
84        match &self {
85            Value::Plain(value) => value.clone(),
86            Value::ReadView(view) | Value::WriteView(view) => view.to_litl(),
87        }
88    }
89
90    pub fn to_litl_or_ref(&self) -> litl::Val {
91        match &self {
92            Value::Plain(value) => value.clone(),
93            Value::ReadView(view) | Value::WriteView(view) => litl::to_val(view.get_obj_id()).unwrap(),
94        }
95    }
96
97    pub fn obj_id(&self) -> Option<ObjID> {
98        match &self {
99            Value::Plain(_) => None,
100            Value::ReadView(view) | Value::WriteView(view) => Some(view.get_obj_id()),
101        }
102    }
103}
104
105impl<'a> From<&'a str> for Value {
106    fn from(value: &str) -> Self {
107        Value::str(value)
108    }
109}
110
111impl TryInto<ObjView> for Value {
112    type Error = ValueError;
113
114    fn try_into(self) -> Result<ObjView, Self::Error> {
115        match self {
116            Value::ReadView(view) | Value::WriteView(view) => Ok(view),
117            Value::Plain(val) => Err(ValueError::ExpectedCollaborativeButGotPlain(val)),
118        }
119    }
120}
121
122impl<'a> TryInto<&'a ObjView> for &'a Value {
123    type Error = ValueError;
124
125    fn try_into(self) -> Result<&'a ObjView, Self::Error> {
126        match &self {
127            Value::ReadView(view) | Value::WriteView(view) => Ok(view),
128            Value::Plain(val) => Err(ValueError::ExpectedCollaborativeButGotPlain(val.clone())),
129        }
130    }
131}
132
133impl<'a> TryInto<&'a mut ObjView> for &'a mut Value {
134    type Error = ValueError;
135
136    fn try_into(self) -> Result<&'a mut ObjView, Self::Error> {
137        match self {
138            Value::ReadView(_) => Err(ValueError::ExpectedMutableCollaborativeObj),
139            Value::WriteView(view) => Ok(view),
140            Value::Plain(val) => Err(ValueError::ExpectedCollaborativeButGotPlain(val.clone())),
141        }
142    }
143}
144
145#[derive(Error, Debug, PartialEq, Eq)]
146#[allow(clippy::enum_variant_names)]
147pub enum ValueError {
148    #[error("Expected plain value but got collaborative object {0:?}")]
149    ExpectedPlainButGotCollaborative(ObjView),
150    #[error("Expected collaborative object but got plain value {0:?}")]
151    ExpectedCollaborativeButGotPlain(litl::Val),
152    #[error("Expected collaborative map but got {0:?}")]
153    ExpectedMap(ObjView),
154    #[error("Expected collaborative list but got {0:?}")]
155    ExpectedList(ObjView),
156    #[error("Expected collaborative text but got {0:?}")]
157    ExpectedText(ObjView),
158    #[error("Expected mutable collaborative object")]
160    ExpectedMutableCollaborativeObj,
161}