#![forbid(unsafe_code)]
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
pub type InlineWord = u64;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum InlineWidth {
Two,
Four,
Eight,
}
impl InlineWidth {
pub(crate) const fn byte_len(self) -> usize {
match self {
Self::Two => 2,
Self::Four => 4,
Self::Eight => 8,
}
}
}
pub trait InlineKey: Ord {
const WIDTH: InlineWidth = InlineWidth::Eight;
fn inline_key_at(&self, offset: usize) -> InlineWord;
}
impl InlineKey for [u8] {
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
crate::proof::ProvenInlineKey::inline_key_at(self, offset)
}
}
impl InlineKey for str {
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
self.as_bytes().inline_key_at(offset)
}
}
impl InlineKey for String {
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
self.as_bytes().inline_key_at(offset)
}
}
impl InlineKey for Vec<u8> {
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
self.as_slice().inline_key_at(offset)
}
}
impl<const N: usize> InlineKey for [u8; N] {
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
self.as_slice().inline_key_at(offset)
}
}
impl InlineKey for u64 {
const WIDTH: InlineWidth = InlineWidth::Two;
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
crate::proof::ProvenInlineKey::inline_key_at(self, offset)
}
}
impl InlineKey for u128 {
const WIDTH: InlineWidth = InlineWidth::Two;
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
crate::proof::ProvenInlineKey::inline_key_at(self, offset)
}
}
impl InlineKey for i64 {
const WIDTH: InlineWidth = InlineWidth::Two;
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
crate::proof::ProvenInlineKey::inline_key_at(self, offset)
}
}
impl InlineKey for i128 {
const WIDTH: InlineWidth = InlineWidth::Two;
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
crate::proof::ProvenInlineKey::inline_key_at(self, offset)
}
}
impl<T: InlineKey + ?Sized> InlineKey for &T {
const WIDTH: InlineWidth = T::WIDTH;
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
(**self).inline_key_at(offset)
}
}
impl<T: InlineKey + ?Sized> InlineKey for Box<T> {
const WIDTH: InlineWidth = T::WIDTH;
#[inline]
fn inline_key_at(&self, offset: usize) -> InlineWord {
(**self).inline_key_at(offset)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Auto;
#[derive(Clone, Copy, Debug, Default)]
pub struct WithInlineKey;
pub trait InlineKeyStrategy<K>: sealed::Sealed<K> {}
impl<K> InlineKeyStrategy<K> for Auto {}
impl<K: InlineKey> InlineKeyStrategy<K> for WithInlineKey {}
pub(crate) mod sealed {
use super::{Auto, InlineKey, InlineWidth, InlineWord, WithInlineKey};
pub enum InlineKeySource<K> {
RecognizedStdTypes,
InlineKeyTrait {
inline_key_at: fn(&K, usize) -> InlineWord,
width: InlineWidth,
},
}
pub trait Sealed<K> {
const SOURCE: InlineKeySource<K>;
const LATCHED: bool = false;
}
impl<K> Sealed<K> for Auto {
const SOURCE: InlineKeySource<K> = InlineKeySource::RecognizedStdTypes;
}
impl<K: InlineKey> Sealed<K> for WithInlineKey {
const SOURCE: InlineKeySource<K> = InlineKeySource::InlineKeyTrait {
inline_key_at: K::inline_key_at,
width: K::WIDTH,
};
}
}
#[cfg(test)]
mod tests {
use std::boxed::Box;
use std::string::String;
use std::vec::Vec;
use super::{InlineKey, InlineWidth, InlineWord};
use crate::tree::test_support::TestRng;
#[test]
fn windows_big_endian_and_zero_padded() {
assert_eq!("".inline_key_at(0), 0);
assert_eq!("a".inline_key_at(0), 0x6100_0000_0000_0000);
assert_eq!("abc".inline_key_at(0), 0x6162_6300_0000_0000);
assert_eq!(b"abcdefgh".inline_key_at(0), 0x6162_6364_6566_6768);
assert_eq!(b"abcdefghij".inline_key_at(0), b"abcdefgh".inline_key_at(0));
assert_eq!([0xff_u8; 3].inline_key_at(0), 0xffff_ff00_0000_0000);
assert_eq!(b"abcdefghij".inline_key_at(2), b"cdefghij".inline_key_at(0));
assert_eq!("abc".inline_key_at(1), 0x6263_0000_0000_0000);
assert_eq!("abc".inline_key_at(3), 0);
assert_eq!("abc".inline_key_at(usize::MAX), 0);
}
#[test]
fn windows_match_their_bytes() {
let bytes: Vec<u8> = (1..=24).collect();
for len in 0..=bytes.len() {
let key = &bytes[..len];
for offset in 0..len + 12 {
let expected =
core::array::from_fn(|index| key.get(offset + index).copied().unwrap_or(0));
assert_eq!(
key.inline_key_at(offset),
InlineWord::from_be_bytes(expected),
"{len} bytes at {offset}"
);
}
}
}
#[test]
fn std_byte_strings_agree() {
let text = "inline keys";
for offset in [0, 3, 11, 20] {
let expected = text.as_bytes().inline_key_at(offset);
assert_eq!(text.inline_key_at(offset), expected);
assert_eq!(String::from(text).inline_key_at(offset), expected);
assert_eq!(Vec::from(text).inline_key_at(offset), expected);
assert_eq!(Box::<str>::from(text).inline_key_at(offset), expected);
let boxed_bytes = Box::<[u8]>::from(text.as_bytes());
assert_eq!(boxed_bytes.inline_key_at(offset), expected);
assert_eq!((&text).inline_key_at(offset), expected);
assert_eq!((&text.as_bytes()).inline_key_at(offset), expected);
let array: [u8; 11] = text.as_bytes().try_into().unwrap();
assert_eq!(array.inline_key_at(offset), expected);
}
}
#[test]
fn differing_windows_order_like_the_bytes() {
let rng = TestRng::new(41);
let random_bytes = || -> Vec<u8> {
let len = rng.below(12);
(0..len).map(|_| [0, 1, b'a', 0xff][rng.below(4)]).collect()
};
let padded = |bytes: &[u8], index: usize| bytes.get(index).copied().unwrap_or(0);
let rounds = if cfg!(miri) { 300 } else { 30_000 };
let (mut ties, mut decided) = (0, 0);
for _ in 0..rounds {
let (a, b) = (random_bytes(), random_bytes());
let shared = (0..a.len().max(b.len()))
.take_while(|&index| padded(&a, index) == padded(&b, index))
.count();
for offset in 0..=shared {
let (window_a, window_b) = (a.inline_key_at(offset), b.inline_key_at(offset));
if window_a == window_b {
ties += 1;
} else {
decided += 1;
assert_eq!(
window_a.cmp(&window_b),
a.cmp(&b),
"{a:?} vs {b:?} at {offset}"
);
}
}
}
assert!(ties > 0 && decided > 0);
}
#[test]
fn integer_windows_are_their_big_endian_bytes() {
let rng = TestRng::new(42);
for _ in 0..if cfg!(miri) { 20 } else { 1000 } {
let high = (rng.below(1 << 30) as u64) << 34 | rng.below(1 << 30) as u64;
let low = (rng.below(1 << 30) as u64) << 34 | rng.below(1 << 30) as u64;
let wide = u128::from(high) << 64 | u128::from(low);
for offset in [0, 1, 3, 7, 8, 9, 15, 16, 17, usize::MAX] {
assert_eq!(
high.inline_key_at(offset),
high.to_be_bytes().inline_key_at(offset)
);
assert_eq!(
wide.inline_key_at(offset),
wide.to_be_bytes().inline_key_at(offset)
);
let signed = high.cast_signed();
let flipped = (signed.cast_unsigned() ^ (1 << 63)).to_be_bytes();
assert_eq!(signed.inline_key_at(offset), flipped.inline_key_at(offset));
let signed = wide.cast_signed();
let flipped = (signed.cast_unsigned() ^ (1 << 127)).to_be_bytes();
assert_eq!(signed.inline_key_at(offset), flipped.inline_key_at(offset));
}
}
assert_eq!(
0x0102_0304_0506_0708_u64.inline_key_at(2),
0x0304_0506_0708_0000
);
assert_eq!((-1_i64).inline_key_at(0), 0x7fff_ffff_ffff_ffff);
assert_eq!(0_i64.inline_key_at(0), 0x8000_0000_0000_0000);
assert_eq!(i128::MIN.inline_key_at(0), 0);
assert_eq!(u128::MAX.inline_key_at(9), 0xffff_ffff_ffff_ff00);
}
#[test]
fn integers_keep_two_bytes() {
assert_eq!(<u64 as InlineKey>::WIDTH, InlineWidth::Two);
assert_eq!(<i64 as InlineKey>::WIDTH, InlineWidth::Two);
assert_eq!(<u128 as InlineKey>::WIDTH, InlineWidth::Two);
assert_eq!(<i128 as InlineKey>::WIDTH, InlineWidth::Two);
assert_eq!(<&i64 as InlineKey>::WIDTH, InlineWidth::Two);
assert_eq!(<Box<u128> as InlineKey>::WIDTH, InlineWidth::Two);
assert_eq!(<String as InlineKey>::WIDTH, InlineWidth::Eight);
assert_eq!(<[u8; 16] as InlineKey>::WIDTH, InlineWidth::Eight);
}
#[test]
fn differing_integer_windows_order_like_the_integers() {
let rng = TestRng::new(43);
let random = || (rng.below(1 << 12) as i64 - (1 << 11)) << (8 * rng.below(7));
let (mut ties, mut decided) = (0, 0);
for _ in 0..if cfg!(miri) { 300 } else { 30_000 } {
let (a, b) = (random(), random());
let shared = (a.inline_key_at(0) ^ b.inline_key_at(0)).leading_zeros() as usize / 8;
for offset in 0..=shared.min(7) {
let kept = |window: InlineWord| window >> 48;
let (window_a, window_b) =
(kept(a.inline_key_at(offset)), kept(b.inline_key_at(offset)));
if window_a == window_b {
ties += 1;
} else {
decided += 1;
assert_eq!(window_a.cmp(&window_b), a.cmp(&b), "{a} vs {b} at {offset}");
}
}
}
assert!(ties > 0 && decided > 0);
}
}