mod constants;
pub mod entry_ref;
pub mod error;
mod frontier;
mod helpers;
#[cfg(test)]
#[macro_use]
mod joiner_tests;
#[cfg(test)]
#[macro_use]
mod splitter_tests;
mod joiner;
pub mod mode;
mod sync_joiner;
mod sync_read_at;
mod sync_splitter;
mod sync_splitter_parallel;
mod tree;
use crate::chunk::ChunkAddress;
#[cfg(feature = "encryption")]
use crate::chunk::encryption::EncryptedChunkRef;
use crate::store::{SyncChunkGet, SyncChunkPut};
#[cfg(feature = "encryption")]
pub use joiner::EncryptedJoiner;
#[cfg(feature = "tokio")]
pub use joiner::JoinerReader;
pub use joiner::{GenericJoiner, Joiner};
#[cfg(feature = "encryption")]
pub use sync_joiner::EncryptedSyncJoiner;
pub use sync_joiner::{GenericSyncJoiner, SyncJoiner};
pub use sync_read_at::SyncReadAt;
#[cfg(feature = "encryption")]
pub use sync_splitter::EncryptedSyncSplitter;
pub use sync_splitter::SyncSplitter;
#[cfg(feature = "encryption")]
pub use sync_splitter_parallel::EncryptedSyncParallelSplitter;
pub use sync_splitter_parallel::SyncParallelSplitter;
pub use entry_ref::EntryRef;
pub use error::FileError;
pub use tree::{ChunkRange, TreeParams};
mod join_ref_sealed {
pub trait Sealed {}
impl Sealed for crate::ChunkAddress {}
#[cfg(feature = "encryption")]
impl Sealed for crate::EncryptedChunkRef {}
}
pub trait JoinRef: join_ref_sealed::Sealed + Clone + Send + Sync + 'static {
type Mode: mode::JoinMode + Send + Sync;
fn into_root_ref(self) -> <Self::Mode as mode::JoinMode>::RootRef;
}
impl JoinRef for ChunkAddress {
type Mode = mode::PlainMode;
fn into_root_ref(self) -> Self {
self
}
}
#[cfg(feature = "encryption")]
impl JoinRef for EncryptedChunkRef {
type Mode = mode::EncryptedMode;
fn into_root_ref(self) -> Self {
self
}
}
pub(crate) fn resolve_seek_position(
pos: std::io::SeekFrom,
current: u64,
span: u64,
) -> std::io::Result<u64> {
use std::io::{Error, ErrorKind::InvalidInput, SeekFrom};
let to_i64 = |v: u64, msg: &str| i64::try_from(v).map_err(|_| Error::new(InvalidInput, msg));
let new_pos = match pos {
SeekFrom::Start(off) => to_i64(off, "seek offset exceeds i64::MAX")?,
SeekFrom::End(off) => to_i64(span, "file span exceeds i64::MAX")? + off,
SeekFrom::Current(off) => to_i64(current, "current position exceeds i64::MAX")? + off,
};
if new_pos < 0 {
return Err(Error::new(InvalidInput, "seek to negative position"));
}
Ok(new_pos as u64)
}
pub async fn join<R, G, const BODY_SIZE: usize>(getter: G, root: R) -> error::Result<Vec<u8>>
where
R: JoinRef,
G: crate::store::ChunkGet<BODY_SIZE>,
{
GenericJoiner::<G, R::Mode, BODY_SIZE>::new(getter, root.into_root_ref())
.await?
.read_all()
.await
}
pub fn sync_split<const BODY_SIZE: usize>(
data: &[u8],
) -> error::Result<(ChunkAddress, crate::store::MemoryStore<BODY_SIZE>)> {
let store = crate::store::MemoryStore::<BODY_SIZE>::new();
let splitter = SyncParallelSplitter::new(store);
let root = splitter.split(&data)?;
Ok((root, splitter.into_store()))
}
#[cfg(feature = "encryption")]
pub fn sync_split_encrypted<const BODY_SIZE: usize>(
data: &[u8],
) -> error::Result<(EncryptedChunkRef, crate::store::MemoryStore<BODY_SIZE>)> {
let store = crate::store::MemoryStore::<BODY_SIZE>::new();
let splitter = EncryptedSyncParallelSplitter::new(store);
let root_ref = splitter.split(&data)?;
Ok((root_ref, splitter.into_store()))
}
pub fn sync_join<R, G, const BODY_SIZE: usize>(getter: G, root: R) -> error::Result<Vec<u8>>
where
R: JoinRef,
G: SyncChunkGet<BODY_SIZE> + Clone + Send + Sync,
{
GenericSyncJoiner::<G, R::Mode, BODY_SIZE>::new(getter, root.into_root_ref())?.read_all()
}
#[cfg(test)]
pub(crate) const fn levels(length: u64, chunk_size: usize) -> usize {
constants::tree_depth(length, chunk_size, constants::REF_SIZE)
}
pub trait ChunkGetExt<const BODY_SIZE: usize>: crate::store::ChunkGet<BODY_SIZE> {
fn joiner<R: JoinRef>(
self,
root: R,
) -> impl std::future::Future<Output = error::Result<GenericJoiner<Self, R::Mode, BODY_SIZE>>> + Send
where
Self: Sized + Clone + Send + Sync + 'static,
{
GenericJoiner::new(self, root.into_root_ref())
}
fn read_file<R: JoinRef>(
self,
root: R,
) -> impl std::future::Future<Output = error::Result<Vec<u8>>> + Send
where
Self: Sized + Clone + Send + Sync + 'static,
{
join(self, root)
}
}
impl<T, const BODY_SIZE: usize> ChunkGetExt<BODY_SIZE> for T where
T: crate::store::ChunkGet<BODY_SIZE>
{
}
pub trait SyncChunkGetExt<const BODY_SIZE: usize>: SyncChunkGet<BODY_SIZE> {
fn joiner<R: JoinRef>(
self,
root: R,
) -> error::Result<GenericSyncJoiner<Self, R::Mode, BODY_SIZE>>
where
Self: Clone + Send + Sync + Sized,
{
GenericSyncJoiner::new(self, root.into_root_ref())
}
fn read_file<R: JoinRef>(self, root: R) -> error::Result<Vec<u8>>
where
Self: Clone + Send + Sync + Sized,
{
sync_join(self, root)
}
}
impl<T, const BODY_SIZE: usize> SyncChunkGetExt<BODY_SIZE> for T where T: SyncChunkGet<BODY_SIZE> {}
pub trait SyncChunkPutExt<const BODY_SIZE: usize>: SyncChunkPut<BODY_SIZE> {
fn writer(&self, size: u64) -> SyncSplitter<&Self, BODY_SIZE>
where
Self: Sized,
{
SyncSplitter::new(self, size)
}
#[cfg(feature = "encryption")]
fn encrypted_writer(&self, size: u64) -> EncryptedSyncSplitter<&Self, BODY_SIZE>
where
Self: Sized,
{
EncryptedSyncSplitter::new(self, size)
}
fn write_file(&self, data: &[u8]) -> error::Result<ChunkAddress>
where
Self: Send + Sync + Sized,
{
SyncParallelSplitter::<&Self, BODY_SIZE>::new(self).split(&data)
}
#[cfg(feature = "encryption")]
fn write_encrypted_file(&self, data: &[u8]) -> error::Result<EncryptedChunkRef>
where
Self: Send + Sync + Sized,
{
EncryptedSyncParallelSplitter::<&Self, BODY_SIZE>::new(self).split(&data)
}
}
impl<T, const BODY_SIZE: usize> SyncChunkPutExt<BODY_SIZE> for T where T: SyncChunkPut<BODY_SIZE> {}
#[cfg(test)]
mod tests;