feat: add a function to read a "bloc / field size" in SSV memory

This commit is contained in:
Florian Briand 2024-07-30 15:15:24 +02:00 committed by theo
parent 3a263f92e1
commit cde7f3aab4
Signed by: theo
SSH Key Fingerprint: SHA256:IbehMhSwpXrGUj7vj9iVvfdwe3g09IL9KLUz0zFzcXU
2 changed files with 120 additions and 0 deletions

View File

@ -1,5 +1,6 @@
mod ssvlib_demo;
mod libssv;
mod ssv_memory;
fn main() {
ssvlib_demo::demo();

View File

@ -0,0 +1,119 @@
/**
* Provide functions to manipulate raw memory from SSV library.
*/
// TODO : Est-ce qu'on pourrait/devrait définir un type custom pour représenter les tableaux de bytes ?
#[derive(PartialEq, Debug)]
pub struct ElementSize {
pub size: usize,
pub pad: usize,
}
#[derive(PartialEq, Debug)]
pub enum MemoryParsingError<'a> {
MemoryIsEmpty(&'a str),
MemoryIsNotValid(&'a str),
}
pub fn read_element_size(bytes: &[u8]) -> Result<ElementSize, MemoryParsingError> {
/* Longueur:
* - si le bit de poids fort du premier octet est à 0, la longueur est codée sur un octet
* - si le bit de poids fort du premier octet est à 1, les 7 bits de poids faible codent le nombre d'octets utilisés pour coder la longueur
*/
if bytes.len() == 0 {
return Err(MemoryParsingError::MemoryIsEmpty("Empty bytes input"));
}
let mut element_size = ElementSize { size: 0, pad: 1 };
if bytes[0] & 0b1000_0000 == 0 {
// Size coded on 1 byte
element_size.size = bytes[0] as usize;
} else {
// Size coded on N bytes
// N are the 7 lower bits of the first byte
let size_bytes_len = (bytes[0] & 0b0111_1111) as usize;
if size_bytes_len > bytes.len() - 1 {
return Err(MemoryParsingError::MemoryIsNotValid(
"Invalid memory: not enough bytes to read the size",
));
} else if size_bytes_len > 4 {
return Err(MemoryParsingError::MemoryIsNotValid(
"Invalid memory: size is too big",
));
}
let size_bytes = &bytes[1..1 + size_bytes_len];
// u32::from_be_bytes() requires a 4 bytes array
let mut padded_bytes = [0u8; 4];
padded_bytes[size_bytes_len..].copy_from_slice(&size_bytes);
element_size.size = u32::from_be_bytes(padded_bytes) as usize;
element_size.pad += size_bytes_len;
}
Ok(element_size)
}
#[cfg(test)]
mod test_read_element_size {
use super::*;
#[test]
fn short_size() {
let bytes = [0b_0000_0001_u8];
let element_size = read_element_size(&bytes).unwrap();
assert_eq!(element_size.size, 1);
assert_eq!(element_size.pad, 1);
let bytes = [0b_0100_0000_u8];
let element_size = read_element_size(&bytes).unwrap();
assert_eq!(element_size.size, 64);
assert_eq!(element_size.pad, 1);
}
#[test]
fn long_size() {
let bytes = [0b_1000_0010_u8, 0b_0000_0001_u8, 0b_0100_0000_u8];
let element_size = read_element_size(&bytes).unwrap();
assert_eq!(element_size.size, 320);
assert_eq!(element_size.pad, 3);
}
#[test]
fn null_size() {
let bytes = [];
let toto = "toto";
// Expect an error
assert_eq!(
read_element_size(&bytes),
Err(MemoryParsingError::MemoryIsEmpty("Empty bytes input")),
);
}
#[test]
fn invalid_memory() {
let bytes = [0b_1000_0001_u8];
assert_eq!(
read_element_size(&bytes),
Err(MemoryParsingError::MemoryIsNotValid(
"Invalid memory: not enough bytes to read the size"
)),
);
let bytes = [0b_1000_0010_u8, 1];
assert_eq!(
read_element_size(&bytes),
Err(MemoryParsingError::MemoryIsNotValid(
"Invalid memory: not enough bytes to read the size"
)),
);
let bytes = [0b_1000_0101_u8, 1, 1, 1, 1, 1];
assert_eq!(
read_element_size(&bytes),
Err(MemoryParsingError::MemoryIsNotValid(
"Invalid memory: size is too big"
)),
);
}
}