use core::fmt;
use serde::de::{self, MapAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub(crate) const MATRIX_SENTINEL: &str = "__hdf5_pure_mat_Matrix__";
#[derive(Debug, Clone, PartialEq)]
pub struct Matrix<T> {
rows: usize,
cols: usize,
data: Vec<T>,
}
impl<T> Matrix<T> {
pub fn from_row_major(rows: usize, cols: usize, data: Vec<T>) -> Self {
assert_eq!(
data.len(),
rows * cols,
"Matrix::from_row_major: data length {} does not match {}×{} = {}",
data.len(),
rows,
cols,
rows * cols
);
Self { rows, cols, data }
}
pub fn rows(&self) -> usize {
self.rows
}
pub fn cols(&self) -> usize {
self.cols
}
pub fn data(&self) -> &[T] {
&self.data
}
pub fn into_data(self) -> Vec<T> {
self.data
}
}
impl<T: Clone + Default> Matrix<T> {
pub fn zeros(rows: usize, cols: usize) -> Self {
Self {
rows,
cols,
data: vec![T::default(); rows * cols],
}
}
}
impl<T: Serialize> Serialize for Matrix<T> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut s = serializer.serialize_struct(MATRIX_SENTINEL, 3)?;
s.serialize_field("rows", &self.rows)?;
s.serialize_field("cols", &self.cols)?;
s.serialize_field("data", &self.data)?;
s.end()
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Matrix<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct MatrixVisitor<T>(core::marker::PhantomData<T>);
impl<'de, T: Deserialize<'de>> Visitor<'de> for MatrixVisitor<T> {
type Value = Matrix<T>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a Matrix<T> struct with fields rows, cols, data")
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Matrix<T>, A::Error> {
let mut rows: Option<usize> = None;
let mut cols: Option<usize> = None;
let mut data: Option<Vec<T>> = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"rows" => rows = Some(map.next_value()?),
"cols" => cols = Some(map.next_value()?),
"data" => data = Some(map.next_value()?),
_ => {
let _: serde::de::IgnoredAny = map.next_value()?;
}
}
}
let rows = rows.ok_or_else(|| de::Error::missing_field("rows"))?;
let cols = cols.ok_or_else(|| de::Error::missing_field("cols"))?;
let data = data.ok_or_else(|| de::Error::missing_field("data"))?;
if data.len() != rows * cols {
return Err(de::Error::custom(format!(
"Matrix data length {} does not match {}×{} = {}",
data.len(),
rows,
cols,
rows * cols
)));
}
Ok(Matrix { rows, cols, data })
}
}
deserializer.deserialize_struct(
MATRIX_SENTINEL,
&["rows", "cols", "data"],
MatrixVisitor(core::marker::PhantomData),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn from_row_major_length_mismatch_panics() {
let _ = Matrix::from_row_major(2, 3, vec![1.0_f64]);
}
}