use byteordered::{ByteOrdered, Endian};
use crate::NiftiType;
use crate::error::Result;
use crate::util::convert_bytes_to;
use num_traits::cast::AsPrimitive;
use safe_transmute::transmute_vec;
use std::io::Read;
use std::mem::align_of;
use std::ops::{Add, Mul};
pub trait LinearTransform<T: 'static + Copy> {
fn linear_transform(value: T, slope: f32, intercept: f32) -> T;
fn linear_transform_many(value: &[T], slope: f32, intercept: f32) -> Vec<T> {
value
.iter()
.map(|x| Self::linear_transform(*x, slope, intercept))
.collect()
}
fn linear_transform_many_inline(value: &mut [T], slope: f32, intercept: f32) {
for v in value.iter_mut() {
*v = Self::linear_transform(*v, slope, intercept);
}
}
}
#[derive(Debug)]
pub struct LinearTransformViaF32;
impl<T> LinearTransform<T> for LinearTransformViaF32
where
T: AsPrimitive<f32>,
f32: AsPrimitive<T>,
{
fn linear_transform(value: T, slope: f32, intercept: f32) -> T {
if slope == 0. {
return value;
}
(value.as_() * slope + intercept).as_()
}
}
#[derive(Debug)]
pub struct LinearTransformViaF64;
impl<T> LinearTransform<T> for LinearTransformViaF64
where
T: 'static + Copy + AsPrimitive<f64>,
f64: AsPrimitive<T>,
{
fn linear_transform(value: T, slope: f32, intercept: f32) -> T {
if slope == 0. {
return value;
}
let slope: f64 = slope.as_();
let intercept: f64 = intercept.as_();
(value.as_() * slope + intercept).as_()
}
}
#[derive(Debug)]
pub struct LinearTransformViaOriginal;
impl<T> LinearTransform<T> for LinearTransformViaOriginal
where
T: 'static + DataElement + Mul<Output = T> + Add<Output = T> + Copy,
f32: AsPrimitive<T>,
{
fn linear_transform(value: T, slope: f32, intercept: f32) -> T {
if slope == 0. {
return value;
}
let slope: T = slope.as_();
let intercept: T = intercept.as_();
value * slope + intercept
}
}
pub trait DataElement:
'static + Sized + Copy + AsPrimitive<u8> + AsPrimitive<f32> + AsPrimitive<f64>
{
const DATA_TYPE: NiftiType;
type Transform: LinearTransform<Self>;
fn from_raw<R: Read, E>(src: R, endianness: E) -> Result<Self>
where
R: Read,
E: Endian;
fn from_raw_vec<E>(vec: Vec<u8>, endianness: E) -> Result<Vec<Self>>
where
E: Endian,
E: Clone,
{
let mut cursor: &[u8] = &vec;
let n = align_of::<Self>();
(0..n)
.map(|_| Self::from_raw(&mut cursor, endianness.clone()))
.collect()
}
}
impl DataElement for u8 {
const DATA_TYPE: NiftiType = NiftiType::Uint8;
type Transform = LinearTransformViaF32;
fn from_raw_vec<E>(vec: Vec<u8>, _: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(vec)
}
fn from_raw<R, E>(src: R, _: E) -> Result<Self>
where
R: Read,
E: Endian,
{
ByteOrdered::native(src).read_u8().map_err(From::from)
}
}
impl DataElement for i8 {
const DATA_TYPE: NiftiType = NiftiType::Int8;
type Transform = LinearTransformViaF32;
fn from_raw_vec<E>(vec: Vec<u8>, _: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(transmute_vec(vec).unwrap())
}
fn from_raw<R, E>(src: R, _: E) -> Result<Self>
where
R: Read,
E: Endian,
{
ByteOrdered::native(src).read_i8().map_err(From::from)
}
}
impl DataElement for u16 {
const DATA_TYPE: NiftiType = NiftiType::Uint16;
type Transform = LinearTransformViaF32;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_u16(src).map_err(From::from)
}
}
impl DataElement for i16 {
const DATA_TYPE: NiftiType = NiftiType::Int16;
type Transform = LinearTransformViaF32;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_i16(src).map_err(From::from)
}
}
impl DataElement for u32 {
const DATA_TYPE: NiftiType = NiftiType::Uint32;
type Transform = LinearTransformViaF32;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_u32(src).map_err(From::from)
}
}
impl DataElement for i32 {
const DATA_TYPE: NiftiType = NiftiType::Int32;
type Transform = LinearTransformViaF32;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_i32(src).map_err(From::from)
}
}
impl DataElement for u64 {
const DATA_TYPE: NiftiType = NiftiType::Uint64;
type Transform = LinearTransformViaF64;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_u64(src).map_err(From::from)
}
}
impl DataElement for i64 {
const DATA_TYPE: NiftiType = NiftiType::Int64;
type Transform = LinearTransformViaF64;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_i64(src).map_err(From::from)
}
}
impl DataElement for f32 {
const DATA_TYPE: NiftiType = NiftiType::Float32;
type Transform = LinearTransformViaOriginal;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_f32(src).map_err(From::from)
}
}
impl DataElement for f64 {
const DATA_TYPE: NiftiType = NiftiType::Float64;
type Transform = LinearTransformViaOriginal;
fn from_raw_vec<E>(vec: Vec<u8>, e: E) -> Result<Vec<Self>>
where
E: Endian,
{
Ok(convert_bytes_to(vec, e))
}
fn from_raw<R, E>(src: R, e: E) -> Result<Self>
where
R: Read,
E: Endian,
{
e.read_f64(src).map_err(From::from)
}
}