aol/
types.rs

1use either::Either;
2
3use super::{buffer::VacantBuffer, *};
4
5/// Maybe a reference entry type or an owned entry.
6pub 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  /// Get the flag.
26  #[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  /// Get the record.
35  #[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  /// Consumes the `MaybeEntryRef`, returning the inner value.
44  #[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/// The entry in the append-only file.
65#[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  /// Create a new creation entry.
81  ///
82  /// ## Example
83  ///
84  /// ```rust
85  /// use aol::Entry;
86  ///
87  /// let entry = Entry::<()>::creation(());
88  /// ```
89  #[inline]
90  pub const fn creation(data: R) -> Self {
91    Self {
92      flag: EntryFlags::creation(),
93      data,
94    }
95  }
96
97  /// Create a new deletion entry.
98  ///
99  /// ## Example
100  ///
101  /// ```rust
102  /// use aol::Entry;
103  ///
104  /// let entry = Entry::<()>::deletion(());
105  /// ```
106  #[inline]
107  pub const fn deletion(data: R) -> Self {
108    Self {
109      flag: EntryFlags::deletion(),
110      data,
111    }
112  }
113
114  /// Create a new creation entry with custom flags.
115  ///
116  /// ## Example
117  ///
118  /// ```rust
119  /// use aol::{Entry, CustomFlags};
120  ///
121  /// let entry = Entry::creation_with_custom_flags(CustomFlags::empty(), ());
122  /// ```
123  #[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  /// Create a new deletion entry with custom flags.
132  ///
133  /// ## Example
134  ///
135  /// ```rust
136  /// use aol::{Entry, CustomFlags};
137  ///
138  /// let entry = Entry::deletion_with_custom_flags(CustomFlags::empty(), ());
139  /// ```
140  #[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  /// Create a new entry with given [`EntryFlags`].
149  ///
150  /// ## Example
151  ///
152  /// ```rust
153  /// use aol::{Entry, EntryFlags};
154  ///
155  /// let entry = Entry::with_flags(EntryFlags::creation(), ());
156  /// ```
157  #[inline]
158  pub const fn with_flags(flag: EntryFlags, data: R) -> Self {
159    Self { flag, data }
160  }
161
162  /// Get the flag.
163  ///
164  /// ## Example
165  ///
166  /// ```rust
167  /// use aol::{Entry, EntryFlags, CustomFlags};
168  ///
169  /// let entry = Entry::creation(());
170  ///
171  /// assert_eq!(entry.flag(), EntryFlags::creation());
172  /// ```
173  #[inline]
174  pub const fn flag(&self) -> EntryFlags {
175    self.flag
176  }
177
178  /// Maps an `Entry<T>` to `Entry<U>` by applying a function to a contained value.
179  ///
180  /// ## Example
181  ///
182  /// ```rust
183  /// use aol::Entry;
184  ///
185  /// let entry = Entry::<u32>::creation(0);
186  /// let entry = entry.map(|x| x as u64);
187  /// ```
188  #[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  /// Get the record.
200  #[inline]
201  pub const fn record(&self) -> &R {
202    &self.data
203  }
204
205  /// Into the record.
206  #[inline]
207  pub fn into_record(self) -> R {
208    self.data
209  }
210}
211
212/// Record for the [`Entry`].
213pub trait Record: Sized + core::fmt::Debug {
214  /// The error type returned by encoding.
215  type Error;
216
217  /// The reference type for the record.
218  type Ref<'a>: RecordRef<'a, Error = Self::Error>;
219
220  /// Returns the encoded size of the data.
221  fn encoded_size(&self) -> usize;
222
223  /// Encodes the data into the buffer, returning the number of bytes written.
224  fn encode(&self, buf: &mut VacantBuffer<'_>) -> Result<usize, Self::Error>;
225}
226
227/// The reference type for the record.
228pub trait RecordRef<'a>: Sized + core::fmt::Debug {
229  /// The error type returned.
230  type Error;
231
232  /// Decodes the data from the buffer, returning the number of bytes read.
233  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}