use crate::Key;
pub trait WriteHook<K: Key>: Send + Sync {
const NEEDS_OLD_VALUE: bool = true;
const NEEDS_INIT: bool = false;
fn on_write(&self, key: &K, old: Option<&[u8]>, new: Option<&[u8]>);
fn on_init(&self, _key: &K, _value: &[u8]) {}
}
pub struct NoHook;
impl<K: Key> WriteHook<K> for NoHook {
const NEEDS_OLD_VALUE: bool = false;
const NEEDS_INIT: bool = false;
#[inline(always)]
fn on_write(&self, _key: &K, _old: Option<&[u8]>, _new: Option<&[u8]>) {}
#[inline(always)]
fn on_init(&self, _key: &K, _value: &[u8]) {}
}
#[cfg(feature = "typed-tree")]
pub trait TypedWriteHook<K: Key, T>: Send + Sync {
const NEEDS_OLD_VALUE: bool = true;
const NEEDS_INIT: bool = false;
fn on_write(&self, key: &K, old: Option<&T>, new: Option<&T>);
fn on_init(&self, _key: &K, _value: &T) {}
}
#[cfg(feature = "typed-tree")]
impl<K: Key, T> TypedWriteHook<K, T> for NoHook {
const NEEDS_OLD_VALUE: bool = false;
const NEEDS_INIT: bool = false;
#[inline(always)]
fn on_write(&self, _key: &K, _old: Option<&T>, _new: Option<&T>) {}
#[inline(always)]
fn on_init(&self, _key: &K, _value: &T) {}
}
pub struct ZeroHookAdapter<K, T, H> {
pub(crate) inner: H,
pub(crate) _marker: std::marker::PhantomData<fn() -> (K, T)>,
}
unsafe impl<K, T, H: Send> Send for ZeroHookAdapter<K, T, H> {}
unsafe impl<K, T, H: Sync> Sync for ZeroHookAdapter<K, T, H> {}
impl<K: Key, T: Copy, H: TypedWriteHook<K, T>> WriteHook<K> for ZeroHookAdapter<K, T, H> {
const NEEDS_OLD_VALUE: bool = H::NEEDS_OLD_VALUE;
const NEEDS_INIT: bool = H::NEEDS_INIT;
#[inline]
fn on_write(&self, key: &K, old: Option<&[u8]>, new: Option<&[u8]>) {
let read = |b: &[u8]| -> T {
debug_assert_eq!(b.len(), size_of::<T>());
unsafe { std::ptr::read(b.as_ptr().cast()) }
};
let old_val = old.map(read);
let new_val = new.map(read);
self.inner.on_write(key, old_val.as_ref(), new_val.as_ref());
}
#[inline]
fn on_init(&self, key: &K, value: &[u8]) {
debug_assert_eq!(value.len(), size_of::<T>());
let val: T = unsafe { std::ptr::read(value.as_ptr().cast()) };
self.inner.on_init(key, &val);
}
}
#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
pub struct VarTypedHookAdapter<K, T, C, H> {
pub(crate) inner: H,
pub(crate) codec: C,
pub(crate) _marker: std::marker::PhantomData<fn() -> (K, T)>,
}
#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
unsafe impl<K, T, C: Send, H: Send> Send for VarTypedHookAdapter<K, T, C, H> {}
#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
unsafe impl<K, T, C: Sync, H: Sync> Sync for VarTypedHookAdapter<K, T, C, H> {}
#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
impl<K, T, C, H> WriteHook<K> for VarTypedHookAdapter<K, T, C, H>
where
K: Key,
T: Send + Sync,
C: crate::codec::Codec<T>,
H: TypedWriteHook<K, T>,
{
const NEEDS_OLD_VALUE: bool = H::NEEDS_OLD_VALUE;
const NEEDS_INIT: bool = H::NEEDS_INIT;
#[inline]
fn on_write(&self, key: &K, old: Option<&[u8]>, new: Option<&[u8]>) {
let old_t = old.and_then(|b| self.codec.decode_from(b).ok());
let new_t = new.and_then(|b| self.codec.decode_from(b).ok());
self.inner.on_write(key, old_t.as_ref(), new_t.as_ref());
}
#[inline]
fn on_init(&self, key: &K, value: &[u8]) {
if let Ok(val) = self.codec.decode_from(value) {
self.inner.on_init(key, &val);
}
}
}