use std::{ collections::HashMap, sync::{Mutex, Weak}, }; use loro_internal::{ container::registry::ContainerInstance, context::Context, ContainerType, LoroError, LoroValue, Prelim, PrelimValue, }; use wasm_bindgen::prelude::*; use crate::JsResult; pub(crate) enum PrelimType { Text(PrelimText), Map(PrelimMap), List(PrelimList), } impl Prelim for PrelimType { fn convert_value(self) -> Result<(PrelimValue, Option), LoroError> { match self { PrelimType::Text(text) => { let (value, prelim) = text.convert_value()?; Ok((value, prelim.map(PrelimType::Text))) } PrelimType::Map(map) => { let (value, prelim) = map.convert_value()?; Ok((value, prelim.map(PrelimType::Map))) } PrelimType::List(list) => { let (value, prelim) = list.convert_value()?; Ok((value, prelim.map(PrelimType::List))) } } } fn integrate( self, ctx: &C, container: Weak>, ) -> Result<(), LoroError> { match self { PrelimType::Text(t) => t.integrate(ctx, container), PrelimType::Map(m) => m.integrate(ctx, container), PrelimType::List(l) => l.integrate(ctx, container), } } } #[wasm_bindgen] pub struct PrelimText(String); #[wasm_bindgen] impl PrelimText { #[wasm_bindgen(constructor)] pub fn new(text: Option) -> Self { Self(text.unwrap_or_default()) } pub fn insert(&mut self, index: usize, text: &str) { self.0.insert_str(index, text); } pub fn delete(&mut self, index: usize, len: usize) { self.0.drain(index..index + len); } #[wasm_bindgen(js_name = "value", method, getter)] pub fn get_value(&self) -> String { self.0.clone() } } #[wasm_bindgen] pub struct PrelimList(Vec); #[wasm_bindgen] impl PrelimList { #[wasm_bindgen(constructor)] pub fn new(list: Option>) -> Self { Self(list.unwrap_or_default()) } pub fn insert(&mut self, index: usize, value: JsValue) { self.0.insert(index, value); } pub fn delete(&mut self, index: usize, len: usize) { self.0.drain(index..index + len); } #[wasm_bindgen(js_name = "value", method, getter)] pub fn get_value(&self) -> Vec { self.0.clone() } } #[wasm_bindgen] pub struct PrelimMap(HashMap); #[wasm_bindgen] impl PrelimMap { #[wasm_bindgen(constructor)] pub fn new(obj: Option) -> Self { let map = if let Some(object) = obj { let mut map = HashMap::new(); let entries = js_sys::Object::entries(&object); for tuple in entries.iter() { let tuple = js_sys::Array::from(&tuple); let key = tuple.get(0).as_string().unwrap(); let value = tuple.get(1); map.insert(key, value); } map } else { HashMap::new() }; Self(map) } #[wasm_bindgen(js_name = set)] pub fn insert(&mut self, key: &str, value: JsValue) { self.0.insert(key.to_string(), value); } pub fn delete(&mut self, key: &str) { self.0.remove(key); } pub fn get(&self, key: &str) -> JsResult { if let Some(v) = self.0.get(key).cloned() { Ok(v) } else { Err(JsValue::from_str("Key not found")) } } // TODO: entries iterator #[wasm_bindgen(js_name = "value", method, getter)] pub fn get_value(&self) -> js_sys::Object { let object = js_sys::Object::new(); for (key, value) in self.0.iter() { js_sys::Reflect::set(&object, &key.into(), value).unwrap(); } object } } impl Prelim for PrelimText { fn convert_value(self) -> Result<(PrelimValue, Option), LoroError> { Ok((PrelimValue::Container(ContainerType::Text), Some(self))) } fn integrate( self, ctx: &C, container: Weak>, ) -> Result<(), LoroError> { let text = container.upgrade().unwrap(); let mut text = text.try_lock().unwrap(); let text = text.as_text_mut().unwrap(); text.insert(ctx, 0, &self.0); Ok(()) } } impl Prelim for PrelimList { fn convert_value(self) -> Result<(PrelimValue, Option), LoroError> { Ok((PrelimValue::Container(ContainerType::List), Some(self))) } fn integrate( self, ctx: &C, container: Weak>, ) -> Result<(), LoroError> { let list = container.upgrade().unwrap(); let mut list = list.try_lock().unwrap(); let list = list.as_list_mut().unwrap(); let values: Vec = self.0.into_iter().map(|v| v.into()).collect(); list.insert_batch(ctx, 0, values); Ok(()) } } impl Prelim for PrelimMap { fn convert_value(self) -> Result<(PrelimValue, Option), LoroError> { Ok((PrelimValue::Container(ContainerType::Map), Some(self))) } fn integrate( self, ctx: &C, container: Weak>, ) -> Result<(), LoroError> { let map = container.upgrade().unwrap(); let mut map = map.try_lock().unwrap(); let map = map.as_map_mut().unwrap(); for (key, value) in self.0.into_iter() { let value: LoroValue = value.into(); map.insert(ctx, key.into(), value)?; } Ok(()) } } impl From for PrelimType { fn from(p: PrelimText) -> Self { Self::Text(p) } } impl From for PrelimType { fn from(p: PrelimList) -> Self { Self::List(p) } } impl From for PrelimType { fn from(p: PrelimMap) -> Self { Self::Map(p) } }