use std::iter;
use std::num::NonZero;
use std::sync::Arc;
use crate::BytesBuf;
use crate::mem::testing::std_alloc_block;
use crate::mem::{BlockSize, Memory};
#[derive(Clone, Debug)]
pub struct FixedBlockMemory {
inner: Arc<FixedBlockMemoryInner>,
}
impl FixedBlockMemory {
#[must_use]
pub fn new(block_size: NonZero<BlockSize>) -> Self {
Self {
inner: Arc::new(FixedBlockMemoryInner::new(block_size)),
}
}
#[must_use]
pub fn reserve(&self, min_bytes: usize) -> crate::BytesBuf {
self.inner.reserve(min_bytes)
}
}
impl Memory for FixedBlockMemory {
#[cfg_attr(test, mutants::skip)] fn reserve(&self, min_bytes: usize) -> crate::BytesBuf {
self.reserve(min_bytes)
}
}
#[derive(Debug)]
struct FixedBlockMemoryInner {
block_size: NonZero<BlockSize>,
}
impl FixedBlockMemoryInner {
#[must_use]
pub(crate) const fn new(block_size: NonZero<BlockSize>) -> Self {
Self { block_size }
}
}
impl FixedBlockMemoryInner {
fn reserve(&self, min_bytes: usize) -> crate::BytesBuf {
let Some(min_bytes) = NonZero::new(min_bytes) else {
return BytesBuf::default();
};
let blocks_required = min_bytes.get().div_ceil(self.block_size.get() as usize);
let blocks = iter::repeat_with(|| std_alloc_block::allocate(self.block_size)).take(blocks_required);
BytesBuf::from_blocks(blocks)
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use new_zealand::nz;
use static_assertions::assert_impl_all;
use super::*;
use crate::BytesView;
use crate::mem::MemoryShared;
assert_impl_all!(FixedBlockMemory: MemoryShared);
#[test]
fn byte_by_byte() {
let memory = FixedBlockMemory::new(nz!(1));
let buf = memory.reserve(0);
assert_eq!(buf.len(), 0);
assert_eq!(buf.capacity(), 0);
let mut data = BytesView::copied_from_slice(b"Hello, world", &memory);
assert_eq!(data, b"Hello, world");
assert_eq!(data.first_slice().len(), 1);
let mut chunks_encountered: usize = 0;
data.consume_all_slices(|chunk| {
chunks_encountered = chunks_encountered.saturating_add(1);
assert_eq!(chunk.len(), 1);
});
assert_eq!(chunks_encountered, 12);
}
}