1use either::Either;
2
3use super::{buffer::VacantBuffer, *};
4
5pub struct MaybeEntryRef<'a, R: Record>(Either<Entry<R::Ref<'a>>, Entry<R>>);
7
8impl<R: Record> core::fmt::Debug for MaybeEntryRef<'_, R> {
9 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
10 match &self.0 {
11 Either::Left(entry) => f.debug_tuple("MaybeEntryRef::Ref").field(entry).finish(),
12 Either::Right(entry) => f.debug_tuple("MaybeEntryRef::Owned").field(entry).finish(),
13 }
14 }
15}
16
17impl<R: Record> From<Entry<R>> for MaybeEntryRef<'_, R> {
18 #[inline]
19 fn from(entry: Entry<R>) -> Self {
20 Self(Either::Right(entry))
21 }
22}
23
24impl<'a, R: Record> MaybeEntryRef<'a, R> {
25 #[inline]
27 pub const fn flag(&self) -> EntryFlags {
28 match &self.0 {
29 Either::Left(entry) => entry.flag(),
30 Either::Right(entry) => entry.flag(),
31 }
32 }
33
34 #[inline]
36 pub const fn record(&self) -> Either<&R::Ref<'a>, &R> {
37 match &self.0 {
38 Either::Left(entry) => Either::Left(entry.record()),
39 Either::Right(entry) => Either::Right(entry.record()),
40 }
41 }
42
43 #[inline]
45 pub fn into_inner(self) -> Either<Entry<R::Ref<'a>>, Entry<R>> {
46 match self.0 {
47 Either::Left(entry) => Either::Left(entry),
48 Either::Right(entry) => Either::Right(entry),
49 }
50 }
51
52 #[cfg(feature = "std")]
53 #[inline]
54 pub(crate) fn left(ent: Entry<R::Ref<'a>>) -> Self {
55 Self(Either::Left(ent))
56 }
57
58 #[inline]
59 pub(crate) fn right(ent: Entry<R>) -> Self {
60 Self(Either::Right(ent))
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67pub struct Entry<R> {
68 pub(super) flag: EntryFlags,
69 pub(super) data: R,
70}
71
72impl<R> AsRef<Self> for Entry<R> {
73 #[inline]
74 fn as_ref(&self) -> &Self {
75 self
76 }
77}
78
79impl<R> Entry<R> {
80 #[inline]
90 pub const fn creation(data: R) -> Self {
91 Self {
92 flag: EntryFlags::creation(),
93 data,
94 }
95 }
96
97 #[inline]
107 pub const fn deletion(data: R) -> Self {
108 Self {
109 flag: EntryFlags::deletion(),
110 data,
111 }
112 }
113
114 #[inline]
124 pub const fn creation_with_custom_flags(flag: CustomFlags, data: R) -> Self {
125 Self {
126 flag: EntryFlags::creation_with_custom_flag(flag),
127 data,
128 }
129 }
130
131 #[inline]
141 pub const fn deletion_with_custom_flags(flag: CustomFlags, data: R) -> Self {
142 Self {
143 flag: EntryFlags::deletion_with_custom_flag(flag),
144 data,
145 }
146 }
147
148 #[inline]
158 pub const fn with_flags(flag: EntryFlags, data: R) -> Self {
159 Self { flag, data }
160 }
161
162 #[inline]
174 pub const fn flag(&self) -> EntryFlags {
175 self.flag
176 }
177
178 #[inline]
189 pub fn map<F, T>(self, f: F) -> Entry<T>
190 where
191 F: FnOnce(R) -> T,
192 {
193 Entry {
194 flag: self.flag,
195 data: f(self.data),
196 }
197 }
198
199 #[inline]
201 pub const fn record(&self) -> &R {
202 &self.data
203 }
204
205 #[inline]
207 pub fn into_record(self) -> R {
208 self.data
209 }
210}
211
212pub trait Record: Sized + core::fmt::Debug {
214 type Error;
216
217 type Ref<'a>: RecordRef<'a, Error = Self::Error>;
219
220 fn encoded_size(&self) -> usize;
222
223 fn encode(&self, buf: &mut VacantBuffer<'_>) -> Result<usize, Self::Error>;
225}
226
227pub trait RecordRef<'a>: Sized + core::fmt::Debug {
229 type Error;
231
232 fn decode(buf: &'a [u8]) -> Result<(usize, Self), Self::Error>;
234}
235
236impl<R: Record> Entry<R> {
237 #[cfg(feature = "std")]
238 #[inline]
239 pub(super) fn encode<C>(
240 &self,
241 data_encoded_len: usize,
242 buf: &mut [u8],
243 cks: &C,
244 ) -> Result<usize, R::Error>
245 where
246 C: dbutils::checksum::BuildChecksumer,
247 {
248 use core::ptr::NonNull;
249
250 let mut cursor = 0;
251 buf[cursor] = self.flag.value;
252 cursor += 1;
253 buf[cursor..cursor + LEN_BUF_SIZE].copy_from_slice(&(data_encoded_len as u32).to_le_bytes());
254 cursor += LEN_BUF_SIZE;
255 let mut vb = unsafe {
256 VacantBuffer::new(
257 data_encoded_len,
258 NonNull::new_unchecked(buf.as_mut_ptr().add(cursor)),
259 )
260 };
261 let encoded = self.data.encode(&mut vb)?;
262 debug_assert_eq!(
263 data_encoded_len, encoded,
264 "invalid data encoded size, expected {} got {}",
265 data_encoded_len, encoded,
266 );
267 cursor += encoded;
268
269 let cks = cks.checksum_one(&buf[..cursor]).to_le_bytes();
270 buf[cursor..cursor + CHECKSUM_SIZE].copy_from_slice(&cks);
271 cursor += CHECKSUM_SIZE;
272
273 debug_assert_eq!(
274 cursor,
275 FIXED_ENTRY_LEN + data_encoded_len,
276 "invalid encoded size, expected {} got {}",
277 cursor,
278 FIXED_ENTRY_LEN + data_encoded_len
279 );
280 Ok(cursor)
281 }
282
283 #[cfg(feature = "std")]
284 #[inline]
285 pub(super) fn decode<'a, C>(
286 buf: &'a [u8],
287 cks: &C,
288 ) -> Result<(usize, Entry<R::Ref<'a>>), Option<<R::Ref<'a> as RecordRef<'a>>::Error>>
289 where
290 C: dbutils::checksum::BuildChecksumer,
291 {
292 let buf_len = buf.len();
293 let cks = cks
294 .checksum_one(&buf[..buf_len - CHECKSUM_SIZE])
295 .to_le_bytes();
296 if cks != buf[buf_len - CHECKSUM_SIZE..buf_len] {
297 return Err(None);
298 }
299
300 let flag = EntryFlags { value: buf[0] };
301
302 let mut cursor = 1;
303 let len = u32::from_le_bytes(buf[cursor..cursor + LEN_BUF_SIZE].try_into().unwrap());
304 cursor += LEN_BUF_SIZE;
305
306 let (read, data) =
307 <R::Ref<'_> as RecordRef>::decode(&buf[cursor..cursor + len as usize]).map_err(Some)?;
308 debug_assert_eq!(
309 read, len as usize,
310 "invalid decoded size, expected {} got {}",
311 read, len
312 );
313
314 Ok((read + cursor, Entry { flag, data }))
315 }
316}