This commit is contained in:
Ed Guloien
2026-05-28 16:10:26 -04:00
parent b21662247d
commit 11da9ba05d
+44 -30
View File
@@ -1,4 +1,3 @@
#[derive(PartialEq, Debug, Clone, Copy)] #[derive(PartialEq, Debug, Clone, Copy)]
struct Range { struct Range {
// todo: consider just using a map instead // todo: consider just using a map instead
@@ -12,7 +11,7 @@ enum RangeLocation {
LeftEnd, LeftEnd,
RightEnd, RightEnd,
Middle, Middle,
No No,
} }
impl Range { impl Range {
@@ -25,7 +24,7 @@ impl Range {
return RangeLocation::LeftEnd; return RangeLocation::LeftEnd;
} }
if index >= self.end { if index >= self.end {
return RangeLocation::No return RangeLocation::No;
} }
if index == self.end - 1 { if index == self.end - 1 {
return RangeLocation::RightEnd; return RangeLocation::RightEnd;
@@ -36,7 +35,7 @@ impl Range {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.start >= self.end self.start >= self.end
} }
} }
pub struct Blob { pub struct Blob {
bytes: Vec<u8>, bytes: Vec<u8>,
@@ -44,14 +43,24 @@ pub struct Blob {
} }
impl Blob { impl Blob {
pub fn new() -> Self { Self {bytes: Vec::new(), valid_ranges: Vec::new()} } pub fn new() -> Self {
Self {
bytes: Vec::new(),
valid_ranges: Vec::new(),
}
}
pub fn append(&mut self, input: &[u8]) { pub fn append(&mut self, input: &[u8]) {
let new_range = Range {start: self.bytes.len(), end: self.bytes.len() + input.len()}; let new_range = Range {
start: self.bytes.len(),
end: self.bytes.len() + input.len(),
};
// we are appending so only have to check the last range // we are appending so only have to check the last range
match self.valid_ranges.last_mut() { match self.valid_ranges.last_mut() {
Some(range) if range.where_in_range(new_range.start) != RangeLocation::No => range.end = new_range.end, Some(range) if range.where_in_range(new_range.start) != RangeLocation::No => {
range.end = new_range.end
}
_ => self.valid_ranges.push(new_range), _ => self.valid_ranges.push(new_range),
} }
self.bytes.extend_from_slice(input); self.bytes.extend_from_slice(input);
@@ -60,36 +69,41 @@ impl Blob {
// todo: better way to do the return type? // todo: better way to do the return type?
pub fn read(&mut self, start: usize, len: usize, output: &mut [u8]) { pub fn read(&mut self, start: usize, len: usize, output: &mut [u8]) {
assert!(len == output.len()); // todo: add error handling assert!(len == output.len()); // todo: add error handling
let slice = &mut self.bytes[start..start+len]; let slice = &mut self.bytes[start..start + len];
slice.swap_with_slice(output); slice.swap_with_slice(output);
// we copy existing entries into a new list to avoid iterator invalidation // we copy existing entries into a new list to avoid iterator invalidation
// of inserting while iterating // of inserting while iterating
// todo: might be a better way // todo: might be a better way
let clear_range = Range{ start, end: start + len }; let clear_range = Range {
start,
end: start + len,
};
let mut new_ranges = Vec::new(); let mut new_ranges = Vec::new();
let mut i = 0; let mut i = 0;
while i < self.valid_ranges.len() { while i < self.valid_ranges.len() {
let mut extra_range : Option<Range> = None; let mut extra_range: Option<Range> = None;
let mut range = self.valid_ranges[i]; let mut range = self.valid_ranges[i];
if range.where_in_range(clear_range.start) == RangeLocation::LeftEnd { if range.where_in_range(clear_range.start) == RangeLocation::LeftEnd {
range.start = clear_range.end; range.start = clear_range.end;
} else if range.where_in_range(clear_range.end-1) == RangeLocation::RightEnd { } else if range.where_in_range(clear_range.end - 1) == RangeLocation::RightEnd {
range.end = clear_range.end range.end = clear_range.end
} else if range.where_in_range(clear_range.start) == RangeLocation::Middle { } else if range.where_in_range(clear_range.start) == RangeLocation::Middle {
let end = range.end; let end = range.end;
range.end = clear_range.start; range.end = clear_range.start;
extra_range = Some(Range::new(clear_range.end, end)); extra_range = Some(Range::new(clear_range.end, end));
} }
if !range.is_empty() { if !range.is_empty() {
new_ranges.push(range); new_ranges.push(range);
} }
if let Some(er) = extra_range && !er.is_empty() { if let Some(er) = extra_range
&& !er.is_empty()
{
new_ranges.push(er); new_ranges.push(er);
} }
i+=1; i += 1;
} }
self.valid_ranges = new_ranges; self.valid_ranges = new_ranges;
} }
@@ -105,10 +119,10 @@ mod tests {
#[test] #[test]
fn test_range() { fn test_range() {
let range = Range{start:0, end:3}; let range = Range { start: 0, end: 3 };
assert_eq!(range, range); // identity assert_eq!(range, range); // identity
let range2 = Range{start:0, end:3}; let range2 = Range { start: 0, end: 3 };
assert_eq!(range, range2); // similar assert_eq!(range, range2); // similar
assert_eq!(range.where_in_range(0), RangeLocation::LeftEnd); assert_eq!(range.where_in_range(0), RangeLocation::LeftEnd);
@@ -121,25 +135,25 @@ mod tests {
fn test_blob() { fn test_blob() {
let mut b = Blob::new(); let mut b = Blob::new();
b.append(&[b'a', b'b', b'c']); b.append(&[b'a', b'b', b'c']);
assert_eq!(b.valid_ranges, &[Range{start:0, end:3}]); assert_eq!(b.valid_ranges, &[Range { start: 0, end: 3 }]);
let mut read = vec![0; 1]; let mut read = vec![0; 1];
b.read(0,1, &mut read); // left read b.read(0, 1, &mut read); // left read
assert_eq!(b.valid_ranges, &[Range{start:1, end:3}]); assert_eq!(b.valid_ranges, &[Range { start: 1, end: 3 }]);
let mut read = vec![0; 1]; let mut read = vec![0; 1];
b.read(0,1, &mut read); // dupe read // todo: should error or fail b.read(0, 1, &mut read); // dupe read // todo: should error or fail
assert_eq!(b.valid_ranges, &[Range{start:1, end:3}]); assert_eq!(b.valid_ranges, &[Range { start: 1, end: 3 }]);
let mut read = vec![0; 2]; let mut read = vec![0; 2];
b.read(1,2, &mut read); // right read b.read(1, 2, &mut read); // right read
assert_eq!(b.valid_ranges, &[]); assert_eq!(b.valid_ranges, &[]);
b.append(&[b'a', b'b', b'c']); b.append(&[b'a', b'b', b'c']);
assert_eq!(b.valid_ranges, &[Range{start:3, end:6}]); assert_eq!(b.valid_ranges, &[Range { start: 3, end: 6 }]);
let mut read = vec![0; 1]; let mut read = vec![0; 1];
b.read(4,1, &mut read); // middle read b.read(4, 1, &mut read); // middle read
assert_eq!(b.valid_ranges, &[Range::new(3,4), Range::new(5,6)]); assert_eq!(b.valid_ranges, &[Range::new(3, 4), Range::new(5, 6)]);
println!("blob: {:?}", b.bytes); println!("blob: {:?}", b.bytes);
} }
} }