add better panic messages on oob index

This commit is contained in:
Vinzenz Schroeter 2024-05-17 23:48:30 +02:00
parent 312fff95b3
commit 6a2ee5fcfa
5 changed files with 35 additions and 7 deletions

View file

@ -1,6 +1,7 @@
/// A vector of bits /// A vector of bits
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct BitVec { pub struct BitVec {
size: usize,
data: Vec<u8>, data: Vec<u8>,
} }
@ -15,6 +16,7 @@ impl BitVec {
pub fn new(size: usize) -> BitVec { pub fn new(size: usize) -> BitVec {
assert_eq!(size % 8, 0); assert_eq!(size % 8, 0);
Self { Self {
size,
data: vec![0; size / 8], data: vec![0; size / 8],
} }
} }
@ -73,7 +75,7 @@ impl BitVec {
/// Gets the length in bits /// Gets the length in bits
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.data.len() * 8 self.size
} }
/// returns true if length is 0. /// returns true if length is 0.
@ -87,9 +89,13 @@ impl BitVec {
} }
/// Calculates the byte index and bitmask for a specific bit in the vector /// Calculates the byte index and bitmask for a specific bit in the vector
fn get_indexes(&self, index: usize) -> (usize, u8) { fn get_indexes(&self, bit_index: usize) -> (usize, u8) {
let byte_index = index / 8; if bit_index >= self.size {
let bit_in_byte_index = 7 - index % 8; panic!("bit index {bit_index} is outside of range 0..<{}", self.size)
}
let byte_index = bit_index / 8;
let bit_in_byte_index = 7 - bit_index % 8;
let bit_mask: u8 = 1 << bit_in_byte_index; let bit_mask: u8 = 1 << bit_in_byte_index;
(byte_index, bit_mask) (byte_index, bit_mask)
} }
@ -106,6 +112,7 @@ impl From<&[u8]> for BitVec {
/// Interpret the data as a series of bits and load then into a new `BitVec` instance. /// Interpret the data as a series of bits and load then into a new `BitVec` instance.
fn from(value: &[u8]) -> Self { fn from(value: &[u8]) -> Self {
Self { Self {
size: value.len() * 8,
data: Vec::from(value), data: Vec::from(value),
} }
} }

View file

@ -38,11 +38,13 @@ impl ByteGrid {
/// ///
/// returns: current byte value /// returns: current byte value
pub fn get(&self, x: usize, y: usize) -> u8 { pub fn get(&self, x: usize, y: usize) -> u8 {
self.check_indexes(x, y);
self.data[x + y * self.width] self.data[x + y * self.width]
} }
/// Sets the byte value at the specified position /// Sets the byte value at the specified position
pub fn set(&mut self, x: usize, y: usize, value: u8) { pub fn set(&mut self, x: usize, y: usize, value: u8) {
self.check_indexes(x, y);
self.data[x + y * self.width] = value; self.data[x + y * self.width] = value;
} }
@ -65,6 +67,15 @@ impl ByteGrid {
pub fn height(&self) -> usize { pub fn height(&self) -> usize {
self.height self.height
} }
fn check_indexes(&self, x: usize, y: usize) {
if x >= self.width {
panic!("cannot access byte {x}-{y} because x is outside of bounds 0..{}", self.width)
}
if y >= self.height {
panic!("cannot access byte {x}-{y} because y is outside of bounds 0..{}", self.height)
}
}
} }
impl From<ByteGrid> for Vec<u8> { impl From<ByteGrid> for Vec<u8> {

View file

@ -706,7 +706,7 @@ mod tests {
fn error_reserved_used() { fn error_reserved_used() {
let Packet(header, payload) let Packet(header, payload)
= Command::BitmapLinear(0, BitVec::new(8), CompressionCode::Uncompressed).into(); = Command::BitmapLinear(0, BitVec::new(8), CompressionCode::Uncompressed).into();
let Header(command, offset, length, sub, reserved) = header; let Header(command, offset, length, sub, _reserved) = header;
let p = Packet(Header(command, offset, length, sub, 69), payload); let p = Packet(Header(command, offset, length, sub, 69), payload);
assert_eq!( assert_eq!(
Command::try_from(p), Command::try_from(p),
@ -717,7 +717,7 @@ mod tests {
fn error_invalid_compression() { fn error_invalid_compression() {
let Packet(header, payload) let Packet(header, payload)
= Command::BitmapLinear(0, BitVec::new(8), CompressionCode::Uncompressed).into(); = Command::BitmapLinear(0, BitVec::new(8), CompressionCode::Uncompressed).into();
let Header(command, offset, length, sub, reserved) = header; let Header(command, offset, length, _sub, reserved) = header;
let p = Packet(Header(command, offset, length, 42, reserved), payload); let p = Packet(Header(command, offset, length, 42, reserved), payload);
assert_eq!( assert_eq!(
Command::try_from(p), Command::try_from(p),

View file

@ -51,7 +51,7 @@ impl Connection {
/// pixels.fill(true); /// pixels.fill(true);
/// ///
/// // send pixels to display /// // send pixels to display
/// connection.send(servicepoint2::Command::BitmapLinearWin(servicepoint2::Origin::top_left(), pixels, CompressionCode::Lzma).into()) /// connection.send(servicepoint2::Command::BitmapLinearWin(servicepoint2::Origin(0, 0), pixels, CompressionCode::Lzma).into())
/// .expect("send failed"); /// .expect("send failed");
/// ``` /// ```
pub fn send(&self, packet: Packet) -> Result<(), std::io::Error> { pub fn send(&self, packet: Packet) -> Result<(), std::io::Error> {

View file

@ -60,6 +60,7 @@ impl PixelGrid {
/// Sets the byte value at the specified position /// Sets the byte value at the specified position
pub fn set(&mut self, x: usize, y: usize, value: bool) -> bool { pub fn set(&mut self, x: usize, y: usize, value: bool) -> bool {
self.check_indexes(x, y);
self.bit_vec.set(x + y * self.width, value) self.bit_vec.set(x + y * self.width, value)
} }
@ -88,6 +89,15 @@ impl PixelGrid {
pub fn height(&self) -> usize { pub fn height(&self) -> usize {
self.height self.height
} }
fn check_indexes(&self, x: usize, y: usize) {
if x >= self.width {
panic!("cannot access pixel {x}-{y} because x is outside of bounds 0..{}", self.width)
}
if y >= self.height {
panic!("cannot access pixel {x}-{y} because y is outside of bounds 0..{}", self.height)
}
}
} }
impl From<PixelGrid> for Vec<u8> { impl From<PixelGrid> for Vec<u8> {