use core::ops::{Bound, RangeBounds};
use crate::Binary;
pub trait ToByteVec {
fn to_byte_vec(&self) -> Vec<u8>;
}
impl ToByteVec for Vec<u8> {
fn to_byte_vec(&self) -> Vec<u8> {
self.clone()
}
}
impl ToByteVec for [u8] {
fn to_byte_vec(&self) -> Vec<u8> {
self.to_vec()
}
}
impl<const N: usize> ToByteVec for [u8; N] {
fn to_byte_vec(&self) -> Vec<u8> {
self.to_vec()
}
}
impl ToByteVec for Binary {
fn to_byte_vec(&self) -> Vec<u8> {
self.to_vec()
}
}
pub fn range_to_bounds<'a, R, B>(range: &R) -> (Option<Vec<u8>>, Option<Vec<u8>>)
where
R: RangeBounds<&'a B>,
B: ToByteVec + 'a + ?Sized,
{
let start = match range.start_bound() {
Bound::Included(start) => Some(start.to_byte_vec()),
Bound::Excluded(start) => Some(key_after(start.to_byte_vec())),
Bound::Unbounded => None,
};
let end = match range.end_bound() {
Bound::Included(end) => Some(key_after(end.to_byte_vec())),
Bound::Excluded(end) => Some(end.to_byte_vec()),
Bound::Unbounded => None,
};
(start, end)
}
fn key_after(mut key: Vec<u8>) -> Vec<u8> {
key.push(0);
key
}
#[cfg(test)]
mod tests {
use crate::{testing::MockStorage, Order, Storage};
use super::*;
#[test]
fn range_to_bounds_works() {
let mut storage = MockStorage::new();
let keys: &[&[u8]] = &[
&[1, 2, 3],
&[1, 2, 4],
&[1, 2, 5],
&[1, 2, 6],
&[1, 2, 7],
&[1, 2, 7, 0],
&[1, 2, 7, 1],
&[1, 2, 7, 2],
&[1, 2, 8],
&[1, 2, 8, 0],
&[1, 2, 8, 1],
];
for (i, &key) in keys.iter().enumerate() {
storage.set(key, &[i as u8]);
}
for (idx0, &key0) in keys.iter().enumerate() {
for (idx1, &key1) in keys.iter().enumerate() {
assert_range(&storage, key0..key1, (idx0..idx1).map(|idx| idx as u8));
assert_range(&storage, key0..=key1, (idx0..=idx1).map(|idx| idx as u8));
}
assert_range(&storage, key0.., (idx0..keys.len()).map(|idx| idx as u8));
assert_range(&storage, ..key0, (0..idx0).map(|idx| idx as u8));
assert_range(&storage, ..=key0, (0..=idx0).map(|idx| idx as u8));
}
let zero: &[u8] = &[0u8];
let not_in_storage = &[1u8, 2, 7, 3];
assert_range(&storage, zero..not_in_storage, 0u8..=7);
assert_range(&storage, zero..=not_in_storage, 0u8..=7);
let after_last_key: &[u8] = &[1u8, 2, 8, 2];
assert_range(&storage, zero..after_last_key, 0u8..keys.len() as u8);
assert_range(&storage, zero..=after_last_key, 0u8..keys.len() as u8);
assert_range(&storage, .., 0u8..keys.len() as u8);
fn assert_range<'a>(
storage: &MockStorage,
range: impl RangeBounds<&'a [u8]>,
expected_values: impl DoubleEndedIterator<Item = u8> + Clone,
) {
let (s, e) = range_to_bounds(&range);
let values = storage
.range_values(s.as_deref(), e.as_deref(), Order::Ascending)
.collect::<Vec<_>>();
assert_eq!(
values,
expected_values.clone().map(|v| vec![v]).collect::<Vec<_>>()
);
let values = storage
.range_values(s.as_deref(), e.as_deref(), Order::Descending)
.collect::<Vec<_>>();
assert_eq!(
values,
expected_values.rev().map(|v| vec![v]).collect::<Vec<_>>()
);
}
}
}