use anyhow::Result;
use bytes::BytesMut;
pub trait RendezvousWrite {
fn write_chunk(&mut self, offset: usize, data: &[u8]) -> Result<()>;
fn capacity(&self) -> usize;
}
impl RendezvousWrite for &mut [u8] {
fn write_chunk(&mut self, offset: usize, data: &[u8]) -> Result<()> {
let end = offset + data.len();
if end > self.len() {
anyhow::bail!(
"write_chunk out of bounds: offset={offset}, len={}, capacity={}",
data.len(),
self.len()
);
}
self[offset..end].copy_from_slice(data);
Ok(())
}
fn capacity(&self) -> usize {
self.len()
}
}
impl RendezvousWrite for BytesMut {
fn write_chunk(&mut self, offset: usize, data: &[u8]) -> Result<()> {
let end = offset + data.len();
if end > self.len() {
self.resize(end, 0);
}
self[offset..end].copy_from_slice(data);
Ok(())
}
fn capacity(&self) -> usize {
BytesMut::capacity(self)
}
}
impl RendezvousWrite for Vec<u8> {
fn write_chunk(&mut self, offset: usize, data: &[u8]) -> Result<()> {
let end = offset + data.len();
if end > self.len() {
self.resize(end, 0);
}
self[offset..end].copy_from_slice(data);
Ok(())
}
fn capacity(&self) -> usize {
Vec::capacity(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_slice_write_chunk() {
let mut buf = vec![0u8; 16];
let mut slice: &mut [u8] = &mut buf;
slice.write_chunk(0, &[1, 2, 3, 4]).unwrap();
slice.write_chunk(4, &[5, 6, 7, 8]).unwrap();
assert_eq!(&buf[..8], &[1, 2, 3, 4, 5, 6, 7, 8]);
}
#[test]
fn test_slice_write_out_of_bounds() {
let mut buf = vec![0u8; 4];
let mut slice: &mut [u8] = &mut buf;
assert!(slice.write_chunk(2, &[1, 2, 3]).is_err());
}
#[test]
fn test_bytesmut_write_chunk_auto_resize() {
let mut buf = BytesMut::with_capacity(4);
buf.resize(4, 0);
buf.write_chunk(0, &[1, 2]).unwrap();
buf.write_chunk(4, &[5, 6, 7, 8]).unwrap();
assert_eq!(&buf[..], &[1, 2, 0, 0, 5, 6, 7, 8]);
}
#[test]
fn test_vec_write_chunk_auto_resize() {
let mut buf = vec![0u8; 4];
buf.write_chunk(0, &[1, 2]).unwrap();
buf.write_chunk(4, &[5, 6]).unwrap();
assert_eq!(&buf, &[1, 2, 0, 0, 5, 6]);
}
}