use crate::error::CoreError;
use crate::slab_store::SlabStore;
pub trait SlabSource: Send + Sync {
#[must_use]
fn plaintext_for(&self, drop_id: &[u8; 32]) -> Option<Result<Vec<u8>, CoreError>>;
fn decoded_range_into(
&self,
drop_id: &[u8; 32],
off: u64,
buf: &mut [u8],
) -> Option<Result<usize, CoreError>> {
if buf.is_empty() {
return Some(Ok(0));
}
match self.plaintext_for(drop_id) {
None => None,
Some(Err(e)) => Some(Err(e)),
Some(Ok(full)) => {
let total = full.len() as u64;
Some(if off >= total {
Ok(0)
} else {
let avail = usize::try_from(total - off).unwrap_or(0).min(buf.len());
buf[..avail].copy_from_slice(&full[off as usize..off as usize + avail]);
Ok(avail)
})
}
}
}
#[must_use]
fn slab_count(&self) -> usize;
#[must_use]
fn drop_count(&self) -> usize;
}
pub struct MmapSlabSource {
inner: SlabStore,
}
impl MmapSlabSource {
#[must_use]
pub fn new(inner: SlabStore) -> Self {
Self { inner }
}
#[must_use]
pub fn inner(&self) -> &SlabStore {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut SlabStore {
&mut self.inner
}
}
pub struct ChainedSlabSource<'a> {
chain: Vec<&'a dyn SlabSource>,
}
impl<'a> ChainedSlabSource<'a> {
#[must_use]
pub fn new(chain: Vec<&'a dyn SlabSource>) -> Self {
Self { chain }
}
}
pub struct OwnedSlabChain {
sources: Vec<Box<dyn SlabSource>>,
}
impl OwnedSlabChain {
#[must_use]
pub fn new(sources: Vec<Box<dyn SlabSource>>) -> Self {
Self { sources }
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.sources.is_empty()
}
}
impl SlabSource for OwnedSlabChain {
fn plaintext_for(&self, drop_id: &[u8; 32]) -> Option<Result<Vec<u8>, CoreError>> {
self.sources.iter().find_map(|s| s.plaintext_for(drop_id))
}
fn slab_count(&self) -> usize {
self.sources.iter().map(|s| s.slab_count()).sum()
}
fn drop_count(&self) -> usize {
self.sources.iter().map(|s| s.drop_count()).sum()
}
}
impl SlabSource for ChainedSlabSource<'_> {
fn plaintext_for(&self, drop_id: &[u8; 32]) -> Option<Result<Vec<u8>, CoreError>> {
self.chain.iter().find_map(|s| s.plaintext_for(drop_id))
}
fn slab_count(&self) -> usize {
self.chain.iter().map(|s| s.slab_count()).sum()
}
fn drop_count(&self) -> usize {
self.chain.iter().map(|s| s.drop_count()).sum()
}
}
impl SlabSource for MmapSlabSource {
fn plaintext_for(&self, drop_id: &[u8; 32]) -> Option<Result<Vec<u8>, CoreError>> {
self.inner.plaintext_for(drop_id)
}
fn slab_count(&self) -> usize {
self.inner.slab_count()
}
fn drop_count(&self) -> usize {
self.inner.drop_count()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mmap_source_delegates_to_inner() {
let store = SlabStore::default();
let source = MmapSlabSource::new(store);
assert_eq!(source.slab_count(), 0);
assert_eq!(source.drop_count(), 0);
let drop_id = [0u8; 32];
assert!(source.plaintext_for(&drop_id).is_none());
}
}