use std::collections::HashMap;
use std::io::Cursor;
use std::path::Path;
use std::{cmp, fmt, io, ops};
use byteorder::{ByteOrder, ReadBytesExt};
use crate::bruker::BrukerFrame;
use crate::cbf::CbfFrame;
use crate::edf::EdfFrame;
use crate::mar::MarFrame;
#[derive(PartialEq, Debug)]
pub enum HeaderEntry {
Empty,
Number(i64),
Float(f64),
String(String),
Pixels([f64; 2]),
}
pub type Header = HashMap<String, HeaderEntry>;
pub struct Array {
dim1: usize,
dim2: usize,
data: Vec<f64>,
}
impl ops::Index<usize> for Array {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
self.data.index(index)
}
}
impl ops::IndexMut<usize> for Array {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.data.index_mut(index)
}
}
impl cmp::PartialEq for Array {
fn eq(&self, other: &Self) -> bool {
self.dim2 == other.dim2 && self.dim1 == other.dim1 && self.data.len() == other.data.len()
}
}
impl cmp::PartialEq for dyn Frame {
fn eq(&self, other: &Self) -> bool {
self.array() == other.array()
}
}
impl ops::SubAssign<&Array> for &mut Array {
fn sub_assign(&mut self, rhs: &Array) {
for (s, r) in self.data.iter_mut().zip(rhs.data.iter()) {
*s -= *r;
}
}
}
impl ops::SubAssign<f64> for &mut Array {
fn sub_assign(&mut self, rhs: f64) {
for s in &mut self.data {
*s -= rhs;
}
}
}
impl ops::AddAssign<&Array> for &mut Array {
fn add_assign(&mut self, rhs: &Array) {
for (s, r) in self.data.iter_mut().zip(rhs.data.iter()) {
*s += *r;
}
}
}
impl ops::DivAssign<&Array> for &mut Array {
fn div_assign(&mut self, rhs: &Array) {
for (s, r) in self.data.iter_mut().zip(rhs.data.iter()) {
*s /= *r;
}
}
}
impl ops::DivAssign<f64> for &mut Array {
fn div_assign(&mut self, rhs: f64) {
for s in &mut self.data {
*s /= rhs;
}
}
}
impl ops::MulAssign<f64> for &mut Array {
fn mul_assign(&mut self, rhs: f64) {
for s in &mut self.data {
*s *= rhs;
}
}
}
impl Array {
pub fn new() -> Array {
Array {
dim1: 0,
dim2: 0,
data: vec![],
}
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn clear(&mut self) {
self.dim1 = 0;
self.dim2 = 0;
self.data.clear();
self.data.shrink_to_fit();
}
pub fn consume(self) -> Vec<f64> {
self.data
}
pub fn with_dims(dim1: usize, dim2: usize) -> Array {
Array {
dim1,
dim2,
data: Vec::with_capacity(dim1 * dim2),
}
}
pub fn with_data(dim1: usize, dim2: usize, data: Vec<f64>) -> Array {
Array { dim1, dim2, data }
}
pub fn from_slice_u8(dim1: usize, dim2: usize, data: &[u8]) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_u8()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_i8(dim1: usize, dim2: usize, data: &[u8]) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_i8()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_u16<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_u16::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_i16<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_i16::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_u32<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_u32::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_i32<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_i32::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_u64<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_u64::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_i64<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_i64::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_f32<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_f32::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn from_slice_f64<F: ByteOrder>(
dim1: usize,
dim2: usize,
data: &[u8],
) -> io::Result<(Array)> {
let (mut reader, mut vec, size) = get_reader_vector(dim1, dim2, data);
for i in 0..size {
vec[i] = reader.read_f64::<F>()? as f64;
}
Ok(Array::with_data(dim1, dim2, vec))
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn data(&self) -> &Vec<f64> {
&self.data
}
pub fn data_mut(&mut self) -> &mut Vec<f64> {
&mut self.data
}
pub fn dim1(&self) -> usize {
self.dim1
}
pub fn dim2(&self) -> usize {
self.dim2
}
pub fn dims(&self) -> (usize, usize) {
(self.dim1, self.dim2)
}
pub fn capacity(&self) -> usize {
self.data.capacity()
}
pub fn push(&mut self, value: f64) {
self.data.push(value);
}
pub fn cell(&self, i: usize, j: usize) -> f64 {
self.data[i * self.dim2 + j]
}
pub fn set_cell(&mut self, i: usize, j: usize, value: f64) {
self.data[i * self.dim2 + j] = value;
}
pub fn sum(&self) -> f64 {
let mut sum = 0.;
for value in &self.data {
sum += *value;
}
sum
}
pub fn min(&self) -> f64 {
let mut min = std::f64::MAX;
for value in &self.data {
if min > *value {
min = *value;
}
}
min
}
pub fn max(&self) -> f64 {
let mut max = std::f64::MIN;
for value in &self.data {
if max < *value {
max = *value;
}
}
max
}
}
pub trait Frame: Sync + Send {
fn array(&self) -> &Array;
fn header(&self) -> &Header;
fn header_mut(&mut self) -> &mut Header;
fn array_mut(&mut self) -> &mut Array;
fn set_array(&mut self, array: Array);
fn sum(&self) -> f64 {
self.array().sum()
}
fn min(&self) -> f64 {
self.array().min()
}
fn max(&self) -> f64 {
self.array().max()
}
fn dim1(&self) -> usize {
self.array().dim1
}
fn dim2(&self) -> usize {
self.array().dim2
}
fn get_header_i64(&self, key: &str) -> io::Result<(i64)> {
match self.header().get(key) {
Some(val) => match val {
HeaderEntry::Number(val) => return Ok(*val),
HeaderEntry::Float(val) => return Ok(*val as i64),
HeaderEntry::String(_) => return self.get_header_str_as_i64(key),
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("bad header entry for {}", key),
));
}
},
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("could not find {}", key),
));
}
};
}
fn get_header_str_or_empty(&self, key: &str) -> &str {
match self.header().get(key) {
Some(entry) => match entry {
HeaderEntry::String(value) => value,
_ => "",
},
None => "",
}
}
fn get_header_float(&self, key: &str) -> f64 {
match self.header().get(key) {
Some(entry) => match entry {
HeaderEntry::Float(value) => *value,
HeaderEntry::Empty => 0.,
HeaderEntry::Number(value) => *value as f64,
HeaderEntry::Pixels(_) => 0.,
HeaderEntry::String(value) => match value.parse::<f64>() {
Ok(value) => value,
Err(_) => 0.,
},
},
None => 0.,
}
}
fn get_header_str(&self, key: &str) -> io::Result<&str> {
match self.header().get(key) {
Some(entry) => match entry {
HeaderEntry::String(value) => return Ok(value),
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("bad header entry for '{}'", key),
));
}
},
None => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("could not find '{}' header entry", key),
)),
}
}
fn get_header_float_as_string_or_empty(&self, key: &str, exp: bool) -> String {
match self.header().get(key) {
Some(entry) => match entry {
HeaderEntry::Float(value) => {
if exp {
format!("{:e}", value)
} else {
format!("{}", value)
}
}
_ => "".to_string(),
},
None => "".to_string(),
}
}
fn get_header_int_as_string_or_empty(&self, key: &str) -> String {
match self.header().get(key) {
Some(entry) => match entry {
HeaderEntry::Number(value) => format!("{}", value),
_ => "".to_string(),
},
None => "".to_string(),
}
}
fn get_header_str_as_i64(&self, key: &str) -> io::Result<i64> {
let value = self.get_header_str(key)?;
match value.parse::<i64>() {
Ok(v) => return Ok(v),
Err(_) => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("could not parse key '{}' in the header", key),
));
}
}
}
fn insert(&mut self, key: String, value: HeaderEntry) {
self.header_mut().insert(key, value);
}
}
impl fmt::Display for HeaderEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
HeaderEntry::Number(v) => write!(f, "{}", v),
HeaderEntry::Float(v) => write!(f, "{}", v),
HeaderEntry::String(v) => write!(f, "{}", v),
HeaderEntry::Empty => write!(f, "empty"),
HeaderEntry::Pixels(v) => write!(f, "[{}, {}]", v[0], v[1]),
}
}
}
fn get_reader_vector(dim1: usize, dim2: usize, data: &[u8]) -> (Cursor<&[u8]>, Vec<f64>, usize) {
let reader = io::Cursor::new(data);
let size = dim1 * dim2;
let mut vec = Vec::with_capacity(size);
unsafe { vec.set_len(size) };
(reader, vec, size)
}
pub fn open<P: AsRef<Path> + fmt::Debug>(path: P) -> io::Result<Box<dyn Frame>> {
if let Some(ext) = path.as_ref().to_path_buf().extension() {
if ext == "cbf" {
return Ok(Box::new(CbfFrame::read_file(path)?));
} else if ext == "edf" {
return Ok(Box::new(EdfFrame::read_file(path)?));
} else if ext == "gfrm" {
return Ok(Box::new(BrukerFrame::read_file(path)?));
} else if ext == "mar2300" || ext == "mar3450" || ext == "mar2560" {
return Ok(Box::new(MarFrame::read_file(path)?));
}
}
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("failed to read {:?} as frame", path),
));
}
impl ops::Index<usize> for dyn Frame {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
self.array().index(index)
}
}
impl ops::IndexMut<usize> for dyn Frame {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.array_mut().index_mut(index)
}
}