use bstack::BStack;
use std::io;
use std::path::Path;
struct VecStore(BStack);
impl VecStore {
fn open(path: impl AsRef<Path>) -> io::Result<Self> {
Ok(VecStore(BStack::open(path)?))
}
fn push_vec(&self, data: &[u8]) -> io::Result<u64> {
let len = data.len() as u32;
let mut record = Vec::with_capacity(5 + data.len());
record.extend_from_slice(&len.to_le_bytes());
record.extend_from_slice(data);
record.push(0x00); self.0.push(&record)
}
fn read_vec_at(&self, pos: u64) -> io::Result<(Vec<u8>, u64)> {
let mut len_buf = [0u8; 4];
self.0.get_into(pos, &mut len_buf)?;
let len = u32::from_le_bytes(len_buf) as u64;
let data = self.0.get(pos + 4, pos + 4 + len)?;
Ok((data, pos + 4 + len + 1))
}
fn get_nth_vec(&self, n: usize) -> io::Result<Vec<u8>> {
let mut pos = 0u64;
for _ in 0..n {
let mut len_buf = [0u8; 4];
self.0.get_into(pos, &mut len_buf)?;
let len = u32::from_le_bytes(len_buf) as u64;
pos += 4 + len + 1;
}
let (data, _) = self.read_vec_at(pos)?;
Ok(data)
}
fn get_vec_after(&self, pos: u64) -> io::Result<(u64, Vec<u8>)> {
let total = self.0.len()?;
let mut cur = 0u64;
while cur < total {
let mut len_buf = [0u8; 4];
self.0.get_into(cur, &mut len_buf)?;
let len = u32::from_le_bytes(len_buf) as u64;
if cur >= pos {
let data = self.0.get(cur + 4, cur + 4 + len)?;
return Ok((cur, data));
}
cur += 4 + len + 1;
}
Err(io::Error::new(
io::ErrorKind::NotFound,
"no record at or after given position",
))
}
}
fn main() -> io::Result<()> {
let store = VecStore::open("vec_store_example.bstack")?;
let offsets = [
store.push_vec(b"alpha")?,
store.push_vec(b"bb")?,
store.push_vec(b"ccc")?,
store.push_vec(b"dddd")?,
];
println!("record start offsets: {:?}", offsets);
println!("total store size: {} bytes", store.0.len()?);
println!("\nby index:");
for i in 0..4 {
let data = store.get_nth_vec(i)?;
println!(" [{}] {:?}", i, String::from_utf8_lossy(&data));
}
println!("\nsequential scan:");
let mut pos = 0u64;
let total = store.0.len()?;
while pos < total {
let (data, next) = store.read_vec_at(pos)?;
println!(" @ {:>4}: {:?}", pos, String::from_utf8_lossy(&data));
pos = next;
}
let search_from = offsets[1] + 1; let (found_at, data) = store.get_vec_after(search_from)?;
println!(
"\nfirst record at or after offset {}: {:?} (starts at {})",
search_from,
String::from_utf8_lossy(&data),
found_at,
);
Ok(())
}