use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::fmt;
use crate::Result;
use crate::error::Error;
use crate::fetcher::RawKey;
use crate::memory::LockedBytes;
mod interleaved;
mod layered;
mod random;
mod standard;
pub(crate) mod util;
pub use self::interleaved::InterleavedFragmenter;
pub use self::layered::LayeredFragmenter;
pub use self::random::RandomFragmenter;
pub use self::standard::StandardFragmenter;
pub struct Fragments {
chunks: Vec<LockedBytes>,
layout: LockedBytes,
total_len: usize,
}
impl Fragments {
pub(crate) fn from_parts(
chunks: Vec<LockedBytes>,
layout: LockedBytes,
total_len: usize,
) -> Self {
Self {
chunks,
layout,
total_len,
}
}
pub(crate) fn total_len(&self) -> usize {
self.total_len
}
#[must_use]
pub fn chunk_count(&self) -> usize {
self.chunks.len()
}
pub(crate) fn chunks(&self) -> &[LockedBytes] {
&self.chunks
}
pub(crate) fn layout(&self) -> &LockedBytes {
&self.layout
}
pub(crate) fn into_parts(self) -> (Vec<LockedBytes>, LockedBytes, usize) {
(self.chunks, self.layout, self.total_len)
}
}
impl fmt::Debug for Fragments {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Fragments")
.field("chunks", &self.chunks.len())
.field("total_len", &self.total_len)
.field("contents", &"<opaque>")
.finish_non_exhaustive()
}
}
pub trait FragmentStrategy: Send + Sync {
fn fragment(&self, key: &RawKey) -> Result<Fragments>;
fn defragment(&self, fragments: &Fragments) -> Result<RawKey>;
fn defragment_into(&self, fragments: &Fragments, out: &mut [u8]) -> Result<()> {
if out.len() != fragments.total_len() {
return Err(Error::Defragment(alloc::string::ToString::to_string(
"scratch buffer size does not match fragments.total_len()",
)));
}
let raw = self.defragment(fragments)?;
out.copy_from_slice(raw.as_bytes());
Ok(())
}
fn describe(&self) -> Cow<'_, str>;
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
#[test]
fn fragments_debug_is_opaque() {
let chunks = alloc::vec![LockedBytes::from_slice(&[1, 2, 3])];
let layout = LockedBytes::from_slice(&[0, 0, 0, 0]);
let f = Fragments::from_parts(chunks, layout, 3);
let rendered = format!("{f:?}");
assert!(rendered.contains("<opaque>"));
assert!(rendered.contains("chunks: 1"));
assert!(rendered.contains("total_len: 3"));
}
}