use bytes::Bytes;
use crate::LLError;
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct LLPath(Vec<Bytes>);
impl LLPath {
pub fn new() -> Self {
LLPath(Vec::new())
}
pub fn from_components(components: Vec<Bytes>) -> Self {
LLPath(components)
}
pub fn components(&self) -> &[Bytes] {
&self.0
}
pub fn into_components(self) -> Vec<Bytes> {
self.0
}
pub fn push(&mut self, component: Bytes) {
self.0.push(component);
}
pub fn as_byte_refs(&self) -> Vec<&[u8]> {
self.0.iter().map(|c| c.as_ref()).collect()
}
}
impl std::ops::Deref for LLPath {
type Target = [Bytes];
fn deref(&self) -> &[Bytes] {
&self.0
}
}
impl FromIterator<Bytes> for LLPath {
fn from_iter<I: IntoIterator<Item = Bytes>>(iter: I) -> Self {
LLPath(iter.into_iter().collect())
}
}
impl IntoIterator for LLPath {
type Item = Bytes;
type IntoIter = std::vec::IntoIter<Bytes>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a LLPath {
type Item = &'a Bytes;
type IntoIter = std::slice::Iter<'a, Bytes>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl From<Vec<Bytes>> for LLPath {
fn from(components: Vec<Bytes>) -> Self {
LLPath(components)
}
}
pub trait LLReader: Send + Sync {
fn ll_read(&mut self, path: &[&[u8]]) -> Result<Option<Bytes>, LLError>;
}
pub trait LLWriter: Send + Sync {
fn ll_write(&mut self, path: &[&[u8]], data: Bytes) -> Result<LLPath, LLError>;
}
pub trait LLStore: LLReader + LLWriter {}
impl<T: LLReader + LLWriter> LLStore for T {}
impl<T: LLReader + ?Sized> LLReader for &mut T {
fn ll_read(&mut self, path: &[&[u8]]) -> Result<Option<Bytes>, LLError> {
(*self).ll_read(path)
}
}
impl<T: LLWriter + ?Sized> LLWriter for &mut T {
fn ll_write(&mut self, path: &[&[u8]], data: Bytes) -> Result<LLPath, LLError> {
(*self).ll_write(path, data)
}
}
impl<T: LLReader + ?Sized> LLReader for Box<T> {
fn ll_read(&mut self, path: &[&[u8]]) -> Result<Option<Bytes>, LLError> {
self.as_mut().ll_read(path)
}
}
impl<T: LLWriter + ?Sized> LLWriter for Box<T> {
fn ll_write(&mut self, path: &[&[u8]], data: Bytes) -> Result<LLPath, LLError> {
self.as_mut().ll_write(path, data)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
struct TestLLStore {
data: HashMap<Vec<Vec<u8>>, Bytes>,
}
impl TestLLStore {
fn new() -> Self {
Self {
data: HashMap::new(),
}
}
}
impl LLReader for TestLLStore {
fn ll_read(&mut self, path: &[&[u8]]) -> Result<Option<Bytes>, LLError> {
let key: Vec<Vec<u8>> = path.iter().map(|c| c.to_vec()).collect();
Ok(self.data.get(&key).cloned())
}
}
impl LLWriter for TestLLStore {
fn ll_write(&mut self, path: &[&[u8]], data: Bytes) -> Result<LLPath, LLError> {
let key: Vec<Vec<u8>> = path.iter().map(|c| c.to_vec()).collect();
self.data.insert(key, data);
Ok(path.iter().map(|c| Bytes::copy_from_slice(c)).collect())
}
}
#[test]
fn basic_read_write_works() {
let mut store = TestLLStore::new();
let path = &[b"users".as_slice(), b"123".as_slice()];
let data = Bytes::from_static(b"hello world");
store.ll_write(path, data.clone()).unwrap();
let result = store.ll_read(path).unwrap();
assert_eq!(result, Some(data));
let result = store.ll_read(&[b"nonexistent"]).unwrap();
assert_eq!(result, None);
}
#[test]
fn object_safety_works() {
let mut store = TestLLStore::new();
let boxed: &mut dyn LLStore = &mut store;
boxed
.ll_write(&[b"test"], Bytes::from_static(b"data"))
.unwrap();
let result = boxed.ll_read(&[b"test"]).unwrap();
assert_eq!(result, Some(Bytes::from_static(b"data")));
}
#[test]
fn mut_ref_blanket_impl_works() {
let mut store = TestLLStore::new();
let store_ref: &mut TestLLStore = &mut store;
store_ref
.ll_write(&[b"ref_test"], Bytes::from_static(b"ref_data"))
.unwrap();
let result = store_ref.ll_read(&[b"ref_test"]).unwrap();
assert_eq!(result, Some(Bytes::from_static(b"ref_data")));
}
#[test]
fn box_blanket_impl_works() {
let store = TestLLStore::new();
let mut boxed: Box<TestLLStore> = Box::new(store);
boxed
.ll_write(&[b"box_test"], Bytes::from_static(b"box_data"))
.unwrap();
let result = boxed.ll_read(&[b"box_test"]).unwrap();
assert_eq!(result, Some(Bytes::from_static(b"box_data")));
}
#[test]
fn box_dyn_works() {
let store = TestLLStore::new();
let mut boxed: Box<dyn LLStore> = Box::new(store);
boxed
.ll_write(&[b"dyn_test"], Bytes::from_static(b"dyn_data"))
.unwrap();
let result = boxed.ll_read(&[b"dyn_test"]).unwrap();
assert_eq!(result, Some(Bytes::from_static(b"dyn_data")));
}
}