use ankurah_proto::{EventId, 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};
use crate::event_dag::EventLayer;
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() -> &'static str
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: &[Operation]) -> Result<(), MutationError>;
fn apply_operations_with_event(&self, operations: &[Operation], event_id: EventId) -> Result<(), MutationError> {
let _ = event_id;
self.apply_operations(operations)
}
fn apply_layer(&self, layer: &EventLayer) -> Result<(), MutationError>;
fn listen_field(
&self,
field_name: &PropertyName,
listener: ankurah_signals::signal::Listener,
) -> ankurah_signals::signal::ListenerGuard;
}
pub(crate) fn notify_changed_fields<'a>(
field_broadcasts: &std::sync::Mutex<std::collections::BTreeMap<crate::property::PropertyName, ankurah_signals::broadcast::Broadcast>>,
changed: impl IntoIterator<Item = &'a crate::property::PropertyName>,
) {
let broadcasts = field_broadcasts.lock().expect("field_broadcasts lock is poisoned");
for field_name in changed {
if let Some(broadcast) = broadcasts.get(field_name) {
broadcast.send(());
}
}
}
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 {
Err(RetrievalError::Other(format!("unknown backend: {}", name)))
}
}