use bincode::{
Decode, Encode, config, decode_from_slice, decode_from_std_read, encode_into_std_write,
encode_to_vec,
};
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
use std::path::Path;
use crate::prelude::*;
const MC_SPARSE_MAGIC: [u8; 8] = *b"BIXVMCSP";
#[derive(Encode, Decode)]
struct McSparseHeader {
magic: [u8; 8],
version: u32,
cs_type: u8,
has_data2: u8,
nrow: u64,
ncol: u64,
nnz: u64,
_reserved: [u8; 26],
}
impl<T, U> CompressedSparseData2<T, U>
where
T: BixverseNumeric,
U: BixverseNumeric,
{
pub fn write_to_disk<P: AsRef<Path>>(&self, path: P) -> Result<(), BixverseErrors>
where
T: Encode,
U: Encode,
{
let header_cfg = config::standard().with_fixed_int_encoding();
let body_cfg = config::standard();
let header = McSparseHeader {
magic: MC_SPARSE_MAGIC,
version: MC_SPARSE_VERSION,
cs_type: match self.cs_type {
CompressedSparseFormat::Csc => 0,
CompressedSparseFormat::Csr => 1,
},
has_data2: self.data_2.is_some() as u8,
nrow: self.shape.0 as u64,
ncol: self.shape.1 as u64,
nnz: self.indices.len() as u64,
_reserved: [0; 26],
};
let mut writer = BufWriter::new(File::create(path)?);
let mut header_bytes =
encode_to_vec(&header, header_cfg).map_err(|_| BixverseErrors::HeaderEncodeFailed)?;
header_bytes.resize(64, 0); writer.write_all(&header_bytes)?;
encode_into_std_write(&self.indptr, &mut writer, body_cfg)
.map_err(|_| BixverseErrors::SerialisationFailed)?;
encode_into_std_write(&self.indices, &mut writer, body_cfg)
.map_err(|_| BixverseErrors::SerialisationFailed)?;
encode_into_std_write(&self.data, &mut writer, body_cfg)
.map_err(|_| BixverseErrors::SerialisationFailed)?;
encode_into_std_write(&self.data_2, &mut writer, body_cfg)
.map_err(|_| BixverseErrors::SerialisationFailed)?;
writer.flush()?;
Ok(())
}
pub fn read_from_disk<P: AsRef<Path>>(path: P) -> Result<Self, BixverseErrors>
where
T: Decode<()>,
U: Decode<()>,
{
let header_cfg = config::standard().with_fixed_int_encoding();
let body_cfg = config::standard();
let mut reader = BufReader::new(File::open(path)?);
let mut header_buf = [0u8; 64];
reader.read_exact(&mut header_buf)?;
let (header, _) = decode_from_slice::<McSparseHeader, _>(&header_buf, header_cfg)
.map_err(|_| BixverseErrors::HeaderDecodeFailed)?;
if header.magic != MC_SPARSE_MAGIC {
return Err(BixverseErrors::HeaderDecodeFailed);
}
if header.version != MC_SPARSE_VERSION {
return Err(BixverseErrors::FileVersionMismatch {
expected: MC_SPARSE_VERSION,
found: header.version,
});
}
let cs_type = match header.cs_type {
0 => CompressedSparseFormat::Csc,
1 => CompressedSparseFormat::Csr,
_ => return Err(BixverseErrors::HeaderDecodeFailed),
};
let indptr: Vec<u32> = decode_from_std_read(&mut reader, body_cfg)
.map_err(|_| BixverseErrors::DeserialisationFailed)?;
let indices: Vec<u32> = decode_from_std_read(&mut reader, body_cfg)
.map_err(|_| BixverseErrors::DeserialisationFailed)?;
let data: Vec<T> = decode_from_std_read(&mut reader, body_cfg)
.map_err(|_| BixverseErrors::DeserialisationFailed)?;
let data_2: Option<Vec<U>> = decode_from_std_read(&mut reader, body_cfg)
.map_err(|_| BixverseErrors::DeserialisationFailed)?;
let out = Self {
data,
indices,
indptr,
cs_type,
data_2,
shape: (header.nrow as usize, header.ncol as usize),
};
out.assert_invariants();
Ok(out)
}
}