use crate::error::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataspaceType {
Scalar,
Simple,
Null,
}
#[derive(Debug, Clone)]
pub struct DataspaceMessage {
pub version: u8,
pub space_type: DataspaceType,
pub ndims: u8,
pub dims: Vec<u64>,
pub max_dims: Option<Vec<u64>>,
}
impl DataspaceMessage {
pub fn decode(data: &[u8]) -> Result<Self> {
if data.len() < 4 {
return Err(Error::InvalidFormat("dataspace message too short".into()));
}
let version = data[0];
let ndims = data[1];
match version {
1 => Self::decode_v1(data, ndims),
2 => Self::decode_v2(data, ndims),
_ => {
if data.len() <= 4 {
Ok(Self {
version,
space_type: DataspaceType::Scalar,
ndims: 0,
dims: vec![],
max_dims: None,
})
} else {
Self::decode_v1(data, ndims)
}
}
}
}
fn decode_v1(data: &[u8], ndims: u8) -> Result<Self> {
let flags = data[2];
let has_max = flags & 0x01 != 0;
let mut pos = 8;
let dims = read_dims(data, &mut pos, ndims as usize);
let max_dims = if has_max {
Some(read_dims(data, &mut pos, ndims as usize))
} else {
None
};
let space_type = if ndims == 0 {
DataspaceType::Scalar
} else {
DataspaceType::Simple
};
Ok(Self {
version: 1,
space_type,
ndims,
dims,
max_dims,
})
}
fn decode_v2(data: &[u8], ndims: u8) -> Result<Self> {
let flags = data[2];
let space_type_val = data[3];
let space_type = match space_type_val {
0 => DataspaceType::Scalar,
1 => DataspaceType::Simple,
2 => DataspaceType::Null,
_ => {
return Err(Error::InvalidFormat(format!(
"unknown dataspace type {space_type_val}"
)))
}
};
let has_max = flags & 0x01 != 0;
let mut pos = 4;
let dims = read_dims(data, &mut pos, ndims as usize);
let max_dims = if has_max {
Some(read_dims(data, &mut pos, ndims as usize))
} else {
None
};
Ok(Self {
version: 2,
space_type,
ndims,
dims,
max_dims,
})
}
}
fn read_dims(data: &[u8], pos: &mut usize, count: usize) -> Vec<u64> {
let mut dims = Vec::with_capacity(count);
for _ in 0..count {
if *pos + 8 > data.len() {
break;
}
let val = read_le_u64(&data[*pos..], 8);
*pos += 8;
dims.push(val);
}
dims
}
fn read_le_u64(data: &[u8], size: usize) -> u64 {
let mut val = 0u64;
for i in 0..size.min(data.len()).min(8) {
val |= (data[i] as u64) << (i * 8);
}
val
}