use ankurah_proto::Operation;
use anyhow::Result;
use std::any::Any;
use std::fmt::Debug;
use std::{collections::BTreeMap, sync::Arc};
pub mod lww;
pub mod yrs;
use crate::error::{MutationError, RetrievalError, StateError};
pub use lww::LWWBackend;
pub use yrs::YrsBackend;
use super::{PropertyName, Value};
pub trait PropertyBackend: Any + Send + Sync + Debug + 'static {
fn as_arc_dyn_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync + 'static>;
fn as_debug(&self) -> &dyn Debug;
fn fork(&self) -> Arc<dyn PropertyBackend>;
fn properties(&self) -> Vec<PropertyName>;
fn property_value(&self, property_name: &PropertyName) -> Option<Value> {
let mut map = self.property_values();
map.remove(property_name).flatten()
}
fn property_values(&self) -> BTreeMap<PropertyName, Option<Value>>;
fn property_backend_name() -> String
where Self: Sized;
fn to_state_buffer(&self) -> Result<Vec<u8>, StateError>;
fn from_state_buffer(state_buffer: &Vec<u8>) -> std::result::Result<Self, crate::error::RetrievalError>
where Self: Sized;
fn to_operations(&self) -> Result<Option<Vec<Operation>>, MutationError>;
fn apply_operations(&self, operations: &Vec<Operation>) -> Result<(), MutationError>;
fn listen_field(
&self,
field_name: &PropertyName,
listener: ankurah_signals::signal::Listener,
) -> ankurah_signals::signal::ListenerGuard;
}
pub fn backend_from_string(name: &str, buffer: Option<&Vec<u8>>) -> Result<Arc<dyn PropertyBackend>, RetrievalError> {
if name == "yrs" {
let backend = match buffer {
Some(buffer) => YrsBackend::from_state_buffer(buffer)?,
None => YrsBackend::new(),
};
Ok(Arc::new(backend))
} else if name == "lww" {
let backend = match buffer {
Some(buffer) => LWWBackend::from_state_buffer(buffer)?,
None => LWWBackend::new(),
};
Ok(Arc::new(backend))
}
else {
panic!("unknown backend: {:?}", name);
}
}