#![doc = include_str!("../README.md")]
#[cfg(feature = "serde")]
pub mod lexico;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
const MAGIC_FLOOR: u8 = 0b0111_1111;
pub(crate) const MAGIC_CEIL: u8 = 0b1000_0000;
const MID_LOW: u8 = 0b0100_0000;
const MID_HIGH: u8 = 0b1100_0000;
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
enum FractionByte {
Magic,
Byte(u8),
}
impl Default for FractionByte {
fn default() -> Self {
FractionByte::Magic
}
}
impl PartialOrd for FractionByte {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FractionByte {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(FractionByte::Magic, FractionByte::Magic) => Ordering::Equal,
(FractionByte::Byte(lhs), FractionByte::Magic) => {
if *lhs <= MAGIC_FLOOR {
Ordering::Less
} else {
Ordering::Greater
}
}
(FractionByte::Magic, FractionByte::Byte(rhs)) => {
if *rhs <= MAGIC_FLOOR {
Ordering::Greater
} else {
Ordering::Less
}
}
(FractionByte::Byte(lhs), FractionByte::Byte(rhs)) => lhs.cmp(rhs),
}
}
}
#[derive(PartialEq, Eq, Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ZenoIndex(Vec<u8>);
fn new_before(bytes: &[u8]) -> Vec<u8> {
for i in 0..bytes.len() {
if bytes[i] > MAGIC_FLOOR {
let bytes: Vec<u8> = bytes[0..i].into();
return bytes;
}
if bytes[i] > u8::MIN {
let mut bytes: Vec<u8> = bytes[0..=i].into();
bytes[i] -= 1;
return bytes;
}
}
let mut bytes = bytes.to_vec();
bytes.push(MID_LOW);
bytes
}
fn new_after(bytes: &[u8]) -> Vec<u8> {
for i in 0..bytes.len() {
if bytes[i] < MAGIC_CEIL {
let bytes: Vec<u8> = bytes[0..i].into();
return bytes;
}
if bytes[i] < u8::MAX {
let mut bytes: Vec<u8> = bytes[0..=i].into();
bytes[i] += 1;
return bytes;
}
}
let mut bytes = bytes.to_vec();
bytes.push(MID_HIGH);
bytes
}
fn new_between(left: &[u8], right: &[u8]) -> Option<Vec<u8>> {
let shortest_length = left.len().min(right.len());
for i in 0..shortest_length {
match left[i].cmp(&right[i]) {
Ordering::Less => {
if (left[i]..right[i]).contains(&MAGIC_FLOOR) {
let prefix = left[0..i].to_vec();
return Some(prefix);
} else if left[i] < right[i] - 1 {
let mid_value = ((right[i] - left[i]) / 2) + left[i];
let mut bytes: Vec<u8> = left[0..i].to_vec();
bytes.push(mid_value);
return Some(bytes);
}
if left.len() <= right.len() {
let (prefix, suffix) = left.split_at(i + 1);
let mut bytes = prefix.to_vec();
bytes.extend_from_slice(&new_after(suffix));
return Some(bytes);
}
let (prefix, suffix) = right.split_at(i + 1);
let mut bytes = prefix.to_vec();
bytes.extend_from_slice(&new_before(suffix));
return Some(bytes);
}
Ordering::Greater => {
return None;
}
Ordering::Equal => (),
}
}
match left.len().cmp(&right.len()) {
Ordering::Less => match right[shortest_length].cmp(&MAGIC_CEIL) {
Ordering::Greater => {
let mut bytes = right[0..=shortest_length].to_vec();
bytes[shortest_length] -= 1;
Some(bytes)
}
Ordering::Equal => {
let (prefix, suffix) = right.split_at(shortest_length + 1);
let mut bytes = prefix.to_vec();
bytes.extend_from_slice(&new_before(suffix));
Some(bytes)
}
Ordering::Less => None,
},
Ordering::Greater => match left[shortest_length].cmp(&MAGIC_FLOOR) {
Ordering::Less => {
let mut bytes = left[0..=shortest_length].to_vec();
bytes[shortest_length] += 1;
Some(bytes)
}
Ordering::Equal => {
let (prefix, suffix) = left.split_at(shortest_length + 1);
let mut bytes = prefix.to_vec();
bytes.extend_from_slice(&new_after(suffix));
Some(bytes)
}
Ordering::Greater => None,
},
Ordering::Equal => None,
}
}
impl ZenoIndex {
pub fn from_bytes(bytes: Vec<u8>) -> Self {
ZenoIndex(bytes)
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
fn digit(&self, i: usize) -> FractionByte {
self.0
.get(i)
.copied()
.map(FractionByte::Byte)
.unwrap_or_default()
}
#[must_use]
pub fn new_before(fs: &ZenoIndex) -> ZenoIndex {
ZenoIndex(new_before(&fs.0))
}
#[must_use]
pub fn new_after(fs: &ZenoIndex) -> ZenoIndex {
ZenoIndex(new_after(&fs.0))
}
#[must_use]
pub fn new_between(left: &ZenoIndex, right: &ZenoIndex) -> Option<ZenoIndex> {
new_between(&left.0, &right.0).map(ZenoIndex)
}
}
impl PartialOrd for ZenoIndex {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ZenoIndex {
fn cmp(&self, other: &Self) -> Ordering {
for i in 0..=self.0.len() {
let sd = self.digit(i);
let od = other.digit(i);
#[allow(clippy::comparison_chain)]
if sd < od {
return Ordering::Less;
} else if sd > od {
return Ordering::Greater;
}
}
Ordering::Equal
}
}
#[cfg(test)]
mod tests {
use super::{
FractionByte::{Byte, Magic},
*,
};
#[test]
fn test_zeno_index() {
let mut indices: Vec<ZenoIndex> = Vec::new();
let c = ZenoIndex::default();
{
let mut m = c.clone();
let mut low = Vec::new();
for _ in 0..20 {
m = ZenoIndex::new_before(&m);
low.push(m.clone())
}
low.reverse();
indices.append(&mut low)
}
indices.push(c.clone());
{
let mut m = c.clone();
let mut high = Vec::new();
for _ in 0..20 {
m = ZenoIndex::new_after(&m);
high.push(m.clone())
}
indices.append(&mut high)
}
for i in 0..(indices.len() - 1) {
assert!(indices[i] < indices[i + 1])
}
for _ in 0..12 {
let mut new_indices: Vec<ZenoIndex> = Vec::new();
for i in 0..(indices.len() - 1) {
let cb = ZenoIndex::new_between(&indices[i], &indices[i + 1]).unwrap();
assert!(&indices[i] < &cb);
assert!(&cb < &indices[i + 1]);
new_indices.push(cb);
new_indices.push(indices[i + 1].clone());
}
indices = new_indices;
}
}
#[test]
fn test_fraction_byte_comparisons() {
assert!(Byte(0) < Magic);
assert!(Byte(255) > Magic);
assert!(Byte(127) < Magic);
assert!(Byte(128) > Magic);
assert_eq!(Magic, Magic);
assert_eq!(Byte(128), Byte(128));
assert!(Byte(8) < Byte(9));
}
}