1use crate::Key;
2
3pub trait WriteHook<K: Key>: Send + Sync {
14 const NEEDS_OLD_VALUE: bool = true;
18
19 const NEEDS_INIT: bool = false;
23
24 fn on_write(&self, key: &K, old: Option<&[u8]>, new: Option<&[u8]>);
30
31 fn on_init(&self, _key: &K, _value: &[u8]) {}
34}
35
36pub struct NoHook;
38
39impl<K: Key> WriteHook<K> for NoHook {
40 const NEEDS_OLD_VALUE: bool = false;
41 const NEEDS_INIT: bool = false;
42
43 #[inline(always)]
44 fn on_write(&self, _key: &K, _old: Option<&[u8]>, _new: Option<&[u8]>) {}
45
46 #[inline(always)]
47 fn on_init(&self, _key: &K, _value: &[u8]) {}
48}
49
50#[cfg(feature = "typed-tree")]
55pub trait TypedWriteHook<K: Key, T>: Send + Sync {
56 const NEEDS_OLD_VALUE: bool = true;
59 const NEEDS_INIT: bool = false;
60
61 fn on_write(&self, key: &K, old: Option<&T>, new: Option<&T>);
62 fn on_init(&self, _key: &K, _value: &T) {}
63}
64
65#[cfg(feature = "typed-tree")]
66impl<K: Key, T> TypedWriteHook<K, T> for NoHook {
67 const NEEDS_OLD_VALUE: bool = false;
68 const NEEDS_INIT: bool = false;
69
70 #[inline(always)]
71 fn on_write(&self, _key: &K, _old: Option<&T>, _new: Option<&T>) {}
72
73 #[inline(always)]
74 fn on_init(&self, _key: &K, _value: &T) {}
75}
76
77pub struct ZeroHookAdapter<K, T, H> {
81 pub(crate) inner: H,
82 pub(crate) _marker: std::marker::PhantomData<fn() -> (K, T)>,
83}
84
85unsafe impl<K, T, H: Send> Send for ZeroHookAdapter<K, T, H> {}
88unsafe impl<K, T, H: Sync> Sync for ZeroHookAdapter<K, T, H> {}
89
90impl<K: Key, T: Copy, H: TypedWriteHook<K, T>> WriteHook<K> for ZeroHookAdapter<K, T, H> {
91 const NEEDS_OLD_VALUE: bool = H::NEEDS_OLD_VALUE;
92 const NEEDS_INIT: bool = H::NEEDS_INIT;
93
94 #[inline]
95 fn on_write(&self, key: &K, old: Option<&[u8]>, new: Option<&[u8]>) {
96 let read = |b: &[u8]| -> T {
97 debug_assert_eq!(b.len(), size_of::<T>());
98 unsafe { std::ptr::read(b.as_ptr().cast()) }
99 };
100 let old_val = old.map(read);
101 let new_val = new.map(read);
102 self.inner.on_write(key, old_val.as_ref(), new_val.as_ref());
103 }
104
105 #[inline]
106 fn on_init(&self, key: &K, value: &[u8]) {
107 debug_assert_eq!(value.len(), size_of::<T>());
108 let val: T = unsafe { std::ptr::read(value.as_ptr().cast()) };
109 self.inner.on_init(key, &val);
110 }
111}
112
113#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
121pub struct VarTypedHookAdapter<K, T, C, H> {
122 pub(crate) inner: H,
123 pub(crate) codec: C,
124 pub(crate) _marker: std::marker::PhantomData<fn() -> (K, T)>,
125}
126
127#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
130unsafe impl<K, T, C: Send, H: Send> Send for VarTypedHookAdapter<K, T, C, H> {}
131#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
132unsafe impl<K, T, C: Sync, H: Sync> Sync for VarTypedHookAdapter<K, T, C, H> {}
133
134#[cfg(all(feature = "typed-tree", feature = "var-collections"))]
135impl<K, T, C, H> WriteHook<K> for VarTypedHookAdapter<K, T, C, H>
136where
137 K: Key,
138 T: Send + Sync,
139 C: crate::codec::Codec<T>,
140 H: TypedWriteHook<K, T>,
141{
142 const NEEDS_OLD_VALUE: bool = H::NEEDS_OLD_VALUE;
143 const NEEDS_INIT: bool = H::NEEDS_INIT;
144
145 #[inline]
146 fn on_write(&self, key: &K, old: Option<&[u8]>, new: Option<&[u8]>) {
147 let old_t = old.and_then(|b| self.codec.decode_from(b).ok());
148 let new_t = new.and_then(|b| self.codec.decode_from(b).ok());
149 self.inner.on_write(key, old_t.as_ref(), new_t.as_ref());
150 }
151
152 #[inline]
153 fn on_init(&self, key: &K, value: &[u8]) {
154 if let Ok(val) = self.codec.decode_from(value) {
155 self.inner.on_init(key, &val);
156 }
157 }
158}