init blob storage: added basic Blob and Range, testing wip

This commit is contained in:
Ed Guloien
2026-05-28 10:11:07 -04:00
commit e2c0acf1a7
4 changed files with 109 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
#[derive(PartialEq, Debug)]
struct Range {
start: usize,
end: usize, // exclusive
}
impl Range {
pub fn contains(&self, index: usize) -> bool {
index >= self.start && index < self.end
}
}
pub struct Blob {
bytes: Vec<u8>,
valid_ranges: Vec<Range>,
}
impl Blob {
pub fn new() -> Self { Self {bytes: Vec::new(), valid_ranges: Vec::new()} }
pub fn append(&mut self, input: &[u8]) {
self.bytes.extend_from_slice(input);
// we are appending so only have to check the last range
let new_range = Range {start: self.bytes.len(), end: self.bytes.len() + input.len()};
match self.valid_ranges.last_mut() {
Some(range) if range.contains(new_range.start) => range.end = new_range.end,
_ => self.valid_ranges.push(new_range),
}
}
// todo: better way to do the return type?
pub fn read(&mut self, start: usize, len: usize, output: &mut [u8]) {
assert!(len == output.len()); // todo: add error handling
let slice = &mut self.bytes[start..start+len];
slice.swap_with_slice(output);
// update the valid array
let clear_range = Range{ start: start, end: start + len };
for range in self.valid_ranges.iter_mut() {
if range.contains(clear_range.start) {
range.end = clear_range.start;
}
if range.contains(clear_range.end) {
range.start = clear_range.end;
}
}
}
}
fn main() {
println!("run cargo test instead")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_range() {
let range = Range{start:0, end:3};
assert_eq!(range, range); // identity
let range2 = Range{start:0, end:3};
assert_eq!(range, range2); // similar
// basic contains
assert!(range.contains(0));
assert!(range.contains(1));
assert!(range.contains(2));
assert!(!range.contains(3));
assert!(!range.contains(4));
}
#[test]
fn test_blob() {
let mut b = Blob::new();
b.append(&[b'a', b'b', b'c']);
let mut read = vec![0; 1];
b.read(0,1, &mut read);
// todo make some asserts
//assert!(&read, Vec<u8>::new([b'a']));
println!("blob (0,1): {}", str::from_utf8(&read).unwrap());
let mut read = vec![0; 1];
b.read(0,1, &mut read);
println!("blob (0,1) again: {}", str::from_utf8(&read).unwrap());
let mut read = vec![0; 2];
b.read(1,2, &mut read);
println!("blob (1,2) again: {}", str::from_utf8(&read).unwrap());
}
}