use crate::Result as StorageResult;
#[cfg(feature = "alloc")]
use alloc::{
boxed::Box,
string::String,
vec::Vec,
};
#[cfg(feature = "std")]
use core::ops::Deref;
pub type Key = Vec<u8>;
pub type Value = alloc::sync::Arc<[u8]>;
pub type KVItem = StorageResult<(Key, Value)>;
pub type KVWriteItem = StorageResult<(Key, WriteOperation)>;
pub type KeyItem = StorageResult<Key>;
pub trait StorageColumn: Copy + core::fmt::Debug {
fn name(&self) -> String;
fn id(&self) -> u32;
fn as_usize(&self) -> usize {
self.id() as usize
}
}
#[impl_tools::autoimpl(for<T: trait> &T, &mut T, Box<T>)]
pub trait KeyValueInspect {
type Column: StorageColumn;
fn exists(&self, key: &[u8], column: Self::Column) -> StorageResult<bool> {
Ok(self.size_of_value(key, column)?.is_some())
}
fn size_of_value(
&self,
key: &[u8],
column: Self::Column,
) -> StorageResult<Option<usize>> {
Ok(self.get(key, column)?.map(|value| value.len()))
}
fn get(&self, key: &[u8], column: Self::Column) -> StorageResult<Option<Value>>;
fn read(
&self,
key: &[u8],
column: Self::Column,
offset: usize,
buf: &mut [u8],
) -> StorageResult<bool> {
let Some(value) = self.get(key, column)? else {
return Ok(false);
};
let bytes_len = value.as_ref().len();
let start = offset;
let buf_len = buf.len();
let end = offset.saturating_add(buf_len);
if end > bytes_len {
return Err(anyhow::anyhow!(
"Offset `{offset}` + buf_len `{buf_len}` read until {end} which is out of bounds `{bytes_len}` for key `{:?}`",
key
)
.into());
}
let starting_from_offset = &value.as_ref()[start..end];
buf[..].copy_from_slice(starting_from_offset);
Ok(true)
}
}
#[cfg(feature = "std")]
impl<T> KeyValueInspect for std::sync::Arc<T>
where
T: KeyValueInspect,
{
type Column = T::Column;
fn exists(&self, key: &[u8], column: Self::Column) -> StorageResult<bool> {
self.deref().exists(key, column)
}
fn size_of_value(
&self,
key: &[u8],
column: Self::Column,
) -> StorageResult<Option<usize>> {
self.deref().size_of_value(key, column)
}
fn get(&self, key: &[u8], column: Self::Column) -> StorageResult<Option<Value>> {
self.deref().get(key, column)
}
fn read(
&self,
key: &[u8],
column: Self::Column,
offset: usize,
buf: &mut [u8],
) -> StorageResult<bool> {
self.deref().read(key, column, offset, buf)
}
}
#[impl_tools::autoimpl(for<T: trait> &mut T, Box<T>)]
pub trait KeyValueMutate: KeyValueInspect {
fn put(
&mut self,
key: &[u8],
column: Self::Column,
value: Value,
) -> StorageResult<()> {
self.write(key, column, value.as_ref()).map(|_| ())
}
fn replace(
&mut self,
key: &[u8],
column: Self::Column,
value: Value,
) -> StorageResult<Option<Value>> {
let old_value = self.get(key, column)?;
self.put(key, column, value)?;
Ok(old_value)
}
fn write(
&mut self,
key: &[u8],
column: Self::Column,
buf: &[u8],
) -> StorageResult<usize>;
fn take(&mut self, key: &[u8], column: Self::Column) -> StorageResult<Option<Value>> {
let old_value = self.get(key, column)?;
self.delete(key, column)?;
Ok(old_value)
}
fn delete(&mut self, key: &[u8], column: Self::Column) -> StorageResult<()>;
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum WriteOperation {
Insert(Value),
Remove,
}
#[impl_tools::autoimpl(for<T: trait> &mut T, Box<T>)]
pub trait BatchOperations: KeyValueMutate {
fn batch_write<I>(&mut self, column: Self::Column, entries: I) -> StorageResult<()>
where
I: Iterator<Item = (Vec<u8>, WriteOperation)>;
}