Skip to main content

arctic/raw/key/
unsized.rs

1//! Support for dynamically sized keys.
2
3use core::fmt;
4use core::fmt::Debug;
5use core::fmt::Display;
6use core::hash::Hash;
7
8pub(crate) mod boxed_slice;
9pub(crate) mod slice;
10
11/// An invariant of `[u8]` that is sufficient to guarantee the
12/// prefix property (no key is a prefix of another key).
13///
14/// # Safety
15///
16/// Caller must ensure that if `validate` returns `Ok(())`,
17/// then `key` satisfies the prefix property.
18pub unsafe trait Invariant:
19    Debug + Default + Hash + Eq + Ord + Send + Sync + 'static
20{
21    /// Validation error.
22    type Error: core::error::Error;
23
24    /// Implementation detail: some invariants append
25    /// a logical terminator byte to the end of each key.
26    #[expect(private_bounds)]
27    type Terminate: Terminate;
28
29    /// Returns `Ok(())` if and only if `key` satisfies this invariant.
30    fn validate(key: &[u8]) -> Result<(), Self::Error>;
31}
32
33/// [`Invariant`] ZST indicating this key does not contain any null bytes.
34///
35/// Allows a null byte to be internally appended to each key,
36/// which guarantees the prefix property and does not change
37/// the lexicographic ordering of the key.
38#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
39pub struct NonNull;
40
41/// Index at which a null byte was found within a key.
42#[derive(Clone, Debug)]
43pub struct NonNullError(usize);
44
45impl core::error::Error for NonNullError {}
46
47impl Display for NonNullError {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "Null byte at index ")?;
50        Display::fmt(&self.0, f)
51    }
52}
53
54// SAFETY: a non-null key that appends a null byte terminator
55// satisfies the precondition property.
56unsafe impl Invariant for NonNull {
57    type Error = NonNullError;
58    type Terminate = bool;
59
60    fn validate(key: &[u8]) -> Result<(), Self::Error> {
61        if let Some(index) = key.iter().position(|byte| *byte == 0) {
62            return Err(NonNullError(index));
63        }
64
65        Ok(())
66    }
67}
68
69/// [`Invariant`] ZST indicating this key contains exactly one
70/// `TERMINATOR` byte at the end of the key.
71///
72/// Implies the prefix property.
73#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
74pub struct Terminated<const TERMINATOR: u8>;
75
76/// Information about why a key does not satisfy the [`Terminated`] invariant.
77#[derive(Clone, Debug)]
78pub enum TerminatedError {
79    /// Terminator byte is missing from key.
80    Missing,
81    /// Terminator byte was found before end of key.
82    Internal(usize),
83}
84
85impl core::error::Error for TerminatedError {}
86
87impl Display for TerminatedError {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            Self::Missing => write!(f, "Missing terminator byte"),
91            Self::Internal(index) => {
92                write!(f, "Internal terminator byte at index {index}")
93            }
94        }
95    }
96}
97
98// SAFETY: a key that ends in a terminator satisfies the precondition property.
99unsafe impl<const TERMINATOR: u8> Invariant for Terminated<TERMINATOR> {
100    type Error = TerminatedError;
101    type Terminate = ();
102
103    fn validate(key: &[u8]) -> Result<(), Self::Error> {
104        match key.iter().position(|byte| *byte == TERMINATOR) {
105            None => Err(TerminatedError::Missing),
106            Some(index) if index < key.len() - 1 => Err(TerminatedError::Internal(index)),
107            Some(_) => Ok(()),
108        }
109    }
110}
111
112// TODO: optimize?
113#[inline]
114fn common_prefix(left: &[u8], right: &[u8]) -> usize {
115    core::iter::zip(left, right)
116        .position(|(l, r)| l != r)
117        .unwrap_or_else(|| left.len().min(right.len()))
118}
119
120// TODO: optimize?
121#[inline]
122fn read_u64(slice: &[u8]) -> u64 {
123    if slice.len() >= 8 {
124        return unsafe { slice.as_ptr().cast::<u64>().read_unaligned() };
125    }
126
127    // FIXME: try to avoid memcpy?
128    // https://github.com/llvm/llvm-project/issues/87440
129    // https://github.com/rust-lang/rust/issues/92993
130    // https://github.com/rust-lang/rust/pull/37573
131    let mut buffer = [0u8; 8];
132    buffer[..slice.len()].copy_from_slice(slice);
133
134    u64::from_le_bytes(buffer)
135}
136
137mod seal {
138    pub trait Seal {}
139}
140
141pub(crate) trait Terminate:
142    Debug + Default + Eq + ribbit::Pack<Packed = Self> + Send + Sync + 'static + seal::Seal
143{
144    const FALSE: Self;
145    const TRUE: Self;
146
147    fn new(terminate: bool) -> Self;
148    fn get(self) -> bool;
149
150    fn try_compress(byte: u8) -> usize;
151
152    fn trim(slice: &[u8]) -> &[u8];
153}
154
155impl seal::Seal for () {}
156impl Terminate for () {
157    const FALSE: Self = ();
158    const TRUE: Self = ();
159
160    #[inline]
161    fn new(_: bool) -> Self {}
162
163    #[inline]
164    fn get(self) -> bool {
165        false
166    }
167
168    #[inline]
169    fn try_compress(_: u8) -> usize {
170        1
171    }
172
173    #[inline]
174    fn trim(slice: &[u8]) -> &[u8] {
175        slice
176    }
177}
178
179impl seal::Seal for bool {}
180impl Terminate for bool {
181    const FALSE: Self = false;
182    const TRUE: Self = true;
183
184    #[inline]
185    fn new(terminate: bool) -> Self {
186        terminate
187    }
188
189    #[inline]
190    fn get(self) -> bool {
191        self
192    }
193
194    #[inline]
195    fn try_compress(byte: u8) -> usize {
196        (byte > 0) as usize
197    }
198
199    #[inline]
200    fn trim(slice: &[u8]) -> &[u8] {
201        let (last, slice) = slice.split_last().expect("Non-empty");
202        validate_eq!(*last, 0);
203        slice
204    }
205}