arctic/raw/key/
unsized.rs1use 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
11pub unsafe trait Invariant:
19 Debug + Default + Hash + Eq + Ord + Send + Sync + 'static
20{
21 type Error: core::error::Error;
23
24 #[expect(private_bounds)]
27 type Terminate: Terminate;
28
29 fn validate(key: &[u8]) -> Result<(), Self::Error>;
31}
32
33#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
39pub struct NonNull;
40
41#[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
54unsafe 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#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
74pub struct Terminated<const TERMINATOR: u8>;
75
76#[derive(Clone, Debug)]
78pub enum TerminatedError {
79 Missing,
81 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
98unsafe 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#[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#[inline]
121fn read_u64(slice: &[u8]) -> u64 {
122 if slice.len() >= 8 {
123 cfg_select! {
124 any(target_arch = "x86", target_arch = "x86_64") => {
126 let buffer: u64;
132 unsafe {
133 core::arch::asm! {
134 "mov {}, [{}]",
135 out(reg) buffer,
136 in(reg) slice.as_ptr().cast::<u64>(),
137 options(pure, readonly, preserves_flags, nostack)
138 }
139 }
140 buffer
141 }
142 _ => unsafe {
143 slice.as_ptr().cast::<u64>().read_unaligned()
144 }
145 }
146 } else {
147 let mut buffer = [0u8; 8];
148 buffer[..slice.len()].copy_from_slice(slice);
149 u64::from_le_bytes(buffer)
150 }
151}
152
153mod seal {
154 pub trait Seal {}
155}
156
157pub(crate) trait Terminate:
158 Debug + Default + Eq + ribbit::Pack<Packed = Self> + Send + Sync + 'static + seal::Seal
159{
160 const FALSE: Self;
161 const TRUE: Self;
162
163 fn new(terminate: bool) -> Self;
164 fn get(self) -> bool;
165
166 fn try_compress(byte: u8) -> usize;
167
168 fn trim(slice: &[u8]) -> &[u8];
169}
170
171impl seal::Seal for () {}
172impl Terminate for () {
173 const FALSE: Self = ();
174 const TRUE: Self = ();
175
176 #[inline]
177 fn new(_: bool) -> Self {}
178
179 #[inline]
180 fn get(self) -> bool {
181 false
182 }
183
184 #[inline]
185 fn try_compress(_: u8) -> usize {
186 1
187 }
188
189 #[inline]
190 fn trim(slice: &[u8]) -> &[u8] {
191 slice
192 }
193}
194
195impl seal::Seal for bool {}
196impl Terminate for bool {
197 const FALSE: Self = false;
198 const TRUE: Self = true;
199
200 #[inline]
201 fn new(terminate: bool) -> Self {
202 terminate
203 }
204
205 #[inline]
206 fn get(self) -> bool {
207 self
208 }
209
210 #[inline]
211 fn try_compress(byte: u8) -> usize {
212 (byte > 0) as usize
213 }
214
215 #[inline]
216 fn trim(slice: &[u8]) -> &[u8] {
217 let (last, slice) = slice.split_last().expect("Non-empty");
218 validate_eq!(*last, 0);
219 slice
220 }
221}