use ferray_core::DynArray;
use ferray_core::dtype::DType;
use ferray_core::error::FerrayResult;
use crate::npy::dtype_parse::{Endianness, dtype_to_descr, parse_dtype_str};
pub const NPY_MAGIC: &[u8] = b"\x93NUMPY";
pub const NPY_MAGIC_LEN: usize = 6;
pub const VERSION_1_0: (u8, u8) = (1, 0);
pub const VERSION_2_0: (u8, u8) = (2, 0);
pub const VERSION_3_0: (u8, u8) = (3, 0);
pub const HEADER_ALIGNMENT: usize = 64;
pub const MAX_HEADER_LEN_V1: usize = u16::MAX as usize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemmapMode {
ReadOnly,
ReadWrite,
CopyOnWrite,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HeaderData {
pub descr: String,
pub fortran_order: bool,
pub shape: Vec<usize>,
}
pub fn descr_to_dtype(descr: &str) -> FerrayResult<DType> {
let (dt, _) = parse_dtype_str(descr)?;
Ok(dt)
}
pub fn header_data_from_array_1_0(array: &DynArray) -> FerrayResult<HeaderData> {
let descr = dtype_to_descr(array.dtype(), Endianness::Little)?;
Ok(HeaderData {
descr,
fortran_order: false,
shape: array.shape().to_vec(),
})
}
pub fn read_array<R: std::io::Read>(reader: &mut R) -> FerrayResult<DynArray> {
crate::npy::load_dynamic_from_reader(reader)
}
pub fn write_array<W: std::io::Write>(writer: &mut W, array: &DynArray) -> FerrayResult<()> {
crate::npy::save_dynamic_to_writer(writer, array)
}
#[cfg(test)]
mod tests {
use super::*;
use ferray_core::{Array, IxDyn};
#[test]
fn magic_bytes() {
assert_eq!(NPY_MAGIC.len(), NPY_MAGIC_LEN);
assert_eq!(NPY_MAGIC[0], 0x93);
assert_eq!(&NPY_MAGIC[1..], b"NUMPY");
}
#[test]
fn memmap_mode_variants() {
let modes = [
MemmapMode::ReadOnly,
MemmapMode::ReadWrite,
MemmapMode::CopyOnWrite,
];
assert_eq!(modes.len(), 3);
assert_ne!(MemmapMode::ReadOnly, MemmapMode::ReadWrite);
}
#[test]
fn descr_to_dtype_basic() {
assert_eq!(descr_to_dtype("<f8").unwrap(), DType::F64);
assert_eq!(descr_to_dtype("<f4").unwrap(), DType::F32);
assert_eq!(descr_to_dtype("<i4").unwrap(), DType::I32);
assert_eq!(descr_to_dtype("|b1").unwrap(), DType::Bool);
}
#[test]
fn descr_to_dtype_invalid_errs() {
assert!(descr_to_dtype("<garbage").is_err());
}
#[test]
fn header_data_from_array_basic() {
let arr: Array<f64, IxDyn> = Array::from_vec(IxDyn::new(&[2, 3]), vec![1.0; 6]).unwrap();
let dyn_arr: DynArray = arr.into();
let h = header_data_from_array_1_0(&dyn_arr).unwrap();
assert_eq!(h.descr, "<f8");
assert!(!h.fortran_order);
assert_eq!(h.shape, vec![2, 3]);
}
#[test]
fn read_array_write_array_roundtrip() {
let arr: Array<i32, IxDyn> = Array::from_vec(IxDyn::new(&[3]), vec![10, 20, 30]).unwrap();
let dyn_arr: DynArray = arr.into();
let mut buf = Vec::<u8>::new();
write_array(&mut buf, &dyn_arr).unwrap();
let mut cursor = std::io::Cursor::new(buf);
let restored = read_array(&mut cursor).unwrap();
assert_eq!(restored.shape(), &[3]);
assert_eq!(restored.dtype(), DType::I32);
}
}