use crate::crdts::ValueType;
use std::convert::Infallible;
pub trait Sentinel {
type Error;
}
pub trait KeySentinel: Sentinel {
fn create_key(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn delete_key(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
#[expect(unused_variables)]
pub trait TypeSentinel<Custom>: Sentinel {
fn set_type(&mut self, value_type: ValueType<Custom>) -> Result<(), Self::Error> {
Ok(())
}
fn unset_type(&mut self, value_type: ValueType<Custom>) -> Result<(), Self::Error> {
Ok(())
}
}
#[expect(unused_variables)]
pub trait ValueSentinel<V>: Sentinel {
fn set(&mut self, value: &V) -> Result<(), Self::Error> {
Ok(())
}
fn unset(&mut self, value: V) -> Result<(), Self::Error> {
Ok(())
}
}
#[expect(unused_variables)]
pub trait Visit<K>: Sentinel {
fn enter(&mut self, key: &K) -> Result<(), Self::Error> {
Ok(())
}
fn exit(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
pub struct DummySentinel;
impl Sentinel for DummySentinel {
type Error = Infallible;
}
impl KeySentinel for DummySentinel {}
impl<C> TypeSentinel<C> for DummySentinel {}
impl<K> Visit<K> for DummySentinel {}
impl<V> ValueSentinel<V> for DummySentinel {}
#[cfg(test)]
pub(crate) mod test {
use super::*;
use std::{collections::BTreeMap, fmt};
pub struct NoChangeValidator;
impl Sentinel for NoChangeValidator {
type Error = ();
}
impl<K> Visit<K> for NoChangeValidator {}
impl KeySentinel for NoChangeValidator {
fn create_key(&mut self) -> Result<(), Self::Error> {
Err(())
}
fn delete_key(&mut self) -> Result<(), Self::Error> {
Err(())
}
}
impl<C> TypeSentinel<C> for NoChangeValidator {
fn set_type(&mut self, _value_type: ValueType<C>) -> Result<(), Self::Error> {
Err(())
}
fn unset_type(&mut self, _value_type: ValueType<C>) -> Result<(), Self::Error> {
Err(())
}
}
impl<V> ValueSentinel<V> for NoChangeValidator {
fn set(&mut self, _value: &V) -> Result<(), Self::Error> {
Err(())
}
fn unset(&mut self, _value: V) -> Result<(), Self::Error> {
Err(())
}
}
#[derive(Debug, Default)]
pub struct KeyCountingValidator {
pub added: usize,
pub removed: usize,
}
impl Sentinel for KeyCountingValidator {
type Error = ();
}
impl<K> Visit<K> for KeyCountingValidator {}
impl KeySentinel for KeyCountingValidator {
fn create_key(&mut self) -> Result<(), Self::Error> {
self.added += 1;
Ok(())
}
fn delete_key(&mut self) -> Result<(), Self::Error> {
self.removed += 1;
Ok(())
}
}
impl<C> TypeSentinel<C> for KeyCountingValidator {
fn set_type(&mut self, _value_type: crate::crdts::ValueType<C>) -> Result<(), Self::Error> {
Err(())
}
fn unset_type(
&mut self,
_value_type: crate::crdts::ValueType<C>,
) -> Result<(), Self::Error> {
Err(())
}
}
impl<V> ValueSentinel<V> for KeyCountingValidator {}
#[derive(Debug)]
pub struct ValueCountingValidator<V> {
pub added: BTreeMap<V, usize>,
pub removed: BTreeMap<V, usize>,
path: Vec<String>,
permissive: bool,
}
impl<V> Default for ValueCountingValidator<V> {
fn default() -> Self {
Self {
added: Default::default(),
removed: Default::default(),
path: Default::default(),
permissive: false,
}
}
}
impl<V> ValueCountingValidator<V> {
pub fn new(permissive: bool) -> Self {
Self {
permissive,
..Default::default()
}
}
}
impl<V> Sentinel for ValueCountingValidator<V> {
type Error = String;
}
impl<K, V> Visit<K> for ValueCountingValidator<V>
where
K: std::fmt::Debug,
{
fn enter(&mut self, key: &K) -> Result<(), Self::Error> {
self.path.push(format!("{key:?}"));
Ok(())
}
fn exit(&mut self) -> Result<(), Self::Error> {
self.path.pop();
Ok(())
}
}
impl<V> KeySentinel for ValueCountingValidator<V> {
fn create_key(&mut self) -> Result<(), Self::Error> {
self.permissive
.then_some(())
.ok_or(format!("create_key at {}", self.path.join("/")))
}
fn delete_key(&mut self) -> Result<(), Self::Error> {
self.permissive
.then_some(())
.ok_or(format!("delete_key at {}", self.path.join("/")))
}
}
impl<C, V> TypeSentinel<C> for ValueCountingValidator<V>
where
C: fmt::Debug,
{
fn set_type(&mut self, value_type: crate::crdts::ValueType<C>) -> Result<(), Self::Error> {
self.permissive.then_some(()).ok_or(format!(
"set_type: {value_type:?} at {}",
self.path.join("/")
))
}
fn unset_type(
&mut self,
value_type: crate::crdts::ValueType<C>,
) -> Result<(), Self::Error> {
self.permissive.then_some(()).ok_or(format!(
"unset_type: {value_type:?} at {}",
self.path.join("/")
))
}
}
impl<V> ValueSentinel<V> for ValueCountingValidator<V>
where
V: std::fmt::Debug + Ord + Clone,
{
fn set(&mut self, value: &V) -> Result<(), Self::Error> {
*self.added.entry(value.clone()).or_default() += 1;
Ok(())
}
fn unset(&mut self, value: V) -> Result<(), Self::Error> {
*self.removed.entry(value).or_default() += 1;
Ok(())
}
}
}