use super::list_translator::ListTranslator;
use crate::{
ops::ObjID,
ops::OpKind,
view::{
jmbl_view::{JMBLViewRef, TranslatorRef},
value::Value,
},
};
use std::rc::Rc;
#[derive(Clone)]
pub struct ListView {
pub(crate) obj_id: ObjID,
ctx: JMBLViewRef,
}
impl ListView {
pub(crate) fn new(obj_id: ObjID, ctx: JMBLViewRef) -> ListView {
ListView { obj_id, ctx }
}
fn translator_state(&self) -> Rc<ListTranslator> {
match self
.ctx
.get_mut()
.current_translator_for(&self.obj_id)
.expect("Should have translator for list view")
{
TranslatorRef::List(list_translator) => list_translator,
_ => panic!("Expected List Translator"),
}
}
pub fn len(&self) -> usize {
self.translator_state().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn val(&self) -> Vec<Value> {
self.translator_state()
.iter_items()
.map(|item| self.ctx.litl_to_value(item.clone()))
.collect()
}
pub fn val_with_deleted(&self) -> Vec<Value> {
todo!("Not #33 yet implemented");
}
pub fn at(&self, idx: usize) -> Value {
match self.translator_state().at(idx) {
Some(item) => self.ctx.litl_to_value(item.clone()),
None => Value::plain(litl::Val::null()),
}
}
pub fn insert_at<I: Into<Value>>(&mut self, idx: usize, item: I) {
let prev = self.translator_state().prev_op_for_insert_at(idx);
self.ctx
.get_mut()
.apply_edit_op(self.obj_id, prev, OpKind::ListInsertAfter, Some(item.into().to_litl_or_ref()));
}
pub fn delete_at(&mut self, idx: usize) {
let prev = self.translator_state().prev_op_for_delete_at(idx);
self.ctx
.get_mut()
.apply_edit_op(self.obj_id, prev, OpKind::Undo, None);
}
pub fn push<I: Into<Value>>(&mut self, item: I) {
self.insert_at(self.len(), item);
}
pub fn pop(&mut self) -> Option<Value> {
let translator_state = self.translator_state();
let len = translator_state.len();
let val = translator_state
.op_before_index
.get(len)
.map(|op| match op.kind {
OpKind::ListInsertAfter => self
.ctx
.litl_to_value(op.val.clone().expect("List insert should have value")),
_ => panic!("Expected ListInsert OpEntry"),
});
self.delete_at(len - 1);
val
}
pub fn val_to_litl(&self) -> litl::Val {
litl::Val::array(
self.val()
.into_iter()
.map(|apparent_value| apparent_value.val_to_litl()),
)
}
}
impl std::fmt::Debug for ListView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ListView")
.field("value", &self.val())
.finish()
}
}
impl std::cmp::PartialEq for ListView {
fn eq(&self, other: &Self) -> bool {
self.obj_id == other.obj_id && self.translator_state() == other.translator_state()
}
}
impl std::cmp::Eq for ListView {}
impl std::hash::Hash for ListView {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.translator_state().hash(state);
}
}