use smallvec::SmallVec;
use std::io;
mod io_stats;
pub const PREFIX_LEN: usize = 12;
pub type DBValue = Vec<u8>;
pub type DBKey = SmallVec<[u8; 32]>;
pub type DBKeyValue = (DBKey, DBValue);
pub use io_stats::{IoStats, Kind as IoStatsKind};
#[derive(Default, Clone, PartialEq)]
pub struct DBTransaction {
pub ops: Vec<DBOp>,
}
#[derive(Clone, PartialEq)]
pub enum DBOp {
Insert { col: u32, key: DBKey, value: DBValue },
Delete { col: u32, key: DBKey },
DeletePrefix { col: u32, prefix: DBKey },
}
impl DBOp {
pub fn key(&self) -> &[u8] {
match *self {
DBOp::Insert { ref key, .. } => key,
DBOp::Delete { ref key, .. } => key,
DBOp::DeletePrefix { ref prefix, .. } => prefix,
}
}
pub fn col(&self) -> u32 {
match *self {
DBOp::Insert { col, .. } => col,
DBOp::Delete { col, .. } => col,
DBOp::DeletePrefix { col, .. } => col,
}
}
}
impl DBTransaction {
pub fn new() -> DBTransaction {
DBTransaction::with_capacity(256)
}
pub fn with_capacity(cap: usize) -> DBTransaction {
DBTransaction { ops: Vec::with_capacity(cap) }
}
pub fn put(&mut self, col: u32, key: &[u8], value: &[u8]) {
self.ops
.push(DBOp::Insert { col, key: DBKey::from_slice(key), value: value.to_vec() })
}
pub fn put_vec(&mut self, col: u32, key: &[u8], value: Vec<u8>) {
self.ops.push(DBOp::Insert { col, key: DBKey::from_slice(key), value });
}
pub fn delete(&mut self, col: u32, key: &[u8]) {
self.ops.push(DBOp::Delete { col, key: DBKey::from_slice(key) });
}
pub fn delete_prefix(&mut self, col: u32, prefix: &[u8]) {
self.ops.push(DBOp::DeletePrefix { col, prefix: DBKey::from_slice(prefix) });
}
}
pub trait KeyValueDB: Sync + Send {
fn transaction(&self) -> DBTransaction {
DBTransaction::new()
}
fn get(&self, col: u32, key: &[u8]) -> io::Result<Option<DBValue>>;
fn get_by_prefix(&self, col: u32, prefix: &[u8]) -> io::Result<Option<DBValue>>;
fn write(&self, transaction: DBTransaction) -> io::Result<()>;
fn iter<'a>(&'a self, col: u32) -> Box<dyn Iterator<Item = io::Result<DBKeyValue>> + 'a>;
fn iter_with_prefix<'a>(
&'a self,
col: u32,
prefix: &'a [u8],
) -> Box<dyn Iterator<Item = io::Result<DBKeyValue>> + 'a>;
fn io_stats(&self, _kind: IoStatsKind) -> IoStats {
IoStats::empty()
}
fn has_key(&self, col: u32, key: &[u8]) -> io::Result<bool> {
self.get(col, key).map(|opt| opt.is_some())
}
fn has_prefix(&self, col: u32, prefix: &[u8]) -> io::Result<bool> {
self.get_by_prefix(col, prefix).map(|opt| opt.is_some())
}
}
pub fn end_prefix(prefix: &[u8]) -> Option<Vec<u8>> {
let mut end_range = prefix.to_vec();
while let Some(0xff) = end_range.last() {
end_range.pop();
}
if let Some(byte) = end_range.last_mut() {
*byte += 1;
Some(end_range)
} else {
None
}
}
#[cfg(test)]
mod test {
use super::end_prefix;
#[test]
fn end_prefix_test() {
assert_eq!(end_prefix(&[5, 6, 7]), Some(vec![5, 6, 8]));
assert_eq!(end_prefix(&[5, 6, 255]), Some(vec![5, 7]));
assert_ne!(end_prefix(&[5, 255, 255]), Some(vec![5, 255]));
assert_eq!(end_prefix(&[5, 255, 255]), Some(vec![6]));
assert_eq!(end_prefix(&[255, 255, 255]), None);
assert_eq!(end_prefix(&[0x00, 0xff]), Some(vec![0x01]));
assert_eq!(end_prefix(&[0xff]), None);
assert_eq!(end_prefix(&[]), None);
assert_eq!(end_prefix(b"0"), Some(b"1".to_vec()));
}
}