<commit_before>//! Module holding an in-memory implementation of a NIfTI volume.

use byteordered::{Endianness};
use crate::error::{NiftiError, Result};
use crate::header::NiftiHeader;
use crate::typedef::NiftiType;
use crate::util::{nb_bytes_for_data, nb_bytes_for_dim_datatype};
use crate::volume::element::DataElement;
use crate::volume::{FromSource, FromSourceOptions, NiftiVolume, RandomAccessNiftiVolume};
use super::shape::Dim;
use super::util::coords_to_index;
use flate2::bufread::GzDecoder;
use num_traits::Num;
use std::fs::File;
use std::io::{BufReader, Read};
use std::ops::{Add, Mul};
use std::path::Path;

#[cfg(feature = "ndarray_volumes")]
use ndarray::{Array, Ix, IxDyn, ShapeBuilder};
#[cfg(feature = "ndarray_volumes")]
use super::ndarray::IntoNdArray;

/// The maximum size in bytes to reserve before the volume voxel data is read.
const PREALLOC_MAX_SIZE: usize = 1 << 28; // 256M

macro_rules! fn_convert_and_cast {
    ($fname: ident, $typ: ty, $converter: expr) => {
        #[cfg(feature = "ndarray_volumes")]
        fn $fname <O> (self) -> Result<Array<O, IxDyn>>
        where
            O: DataElement,
        {
            use crate::volume::element::LinearTransform;

            let dim: Vec<_> = self.dim().iter().map(|d| *d as Ix).collect();
    
            let data: Vec<_> = <$typ as DataElement>::from_raw_vec(self.raw_data, self.endianness)?;
            let mut data: Vec<O> = data.into_iter()
                .map($converter)
                .collect();
            <O as DataElement>::Transform::linear_transform_many_inline(
                &mut data,
                self.scl_slope,
                self.scl_inter,
            );
    
            Ok(Array::from_shape_vec(IxDyn(&dim).f(), data).expect("Inconsistent raw data size"))
        }
    };
}

/// A data type for a NIFTI-1 volume contained in memory. Objects of this type
/// contain raw image data, which is converted automatically when using reading
/// methods or [converting it to an `ndarray`] (only with the `ndarray_volumes`
/// feature).
///
/// Since NIfTI volumes are stored in disk in column major order (also called
/// Fortran order), this data type will also retain this memory order.
///
/// [converting it to an `ndarray`]: ../ndarray/index.html
///
#[derive(Debug, PartialEq, Clone)]
pub struct InMemNiftiVolume {
    dim: Dim,
    datatype: NiftiType,
    scl_slope: f32,
    scl_inter: f32,
    raw_data: Vec<u8>,
    endianness: Endianness,
}<commit_msg>Add comments to fn_convert_and_cast macro<commit_after>//! Module holding an in-memory implementation of a NIfTI volume.

use byteordered::{Endianness};
use crate::error::{NiftiError, Result};
use crate::header::NiftiHeader;
use crate::typedef::NiftiType;
use crate::util::{nb_bytes_for_data, nb_bytes_for_dim_datatype};
use crate::volume::element::DataElement;
use crate::volume::{FromSource, FromSourceOptions, NiftiVolume, RandomAccessNiftiVolume};
use super::shape::Dim;
use super::util::coords_to_index;
use flate2::bufread::GzDecoder;
use num_traits::Num;
use std::fs::File;
use std::io::{BufReader, Read};
use std::ops::{Add, Mul};
use std::path::Path;

#[cfg(feature = "ndarray_volumes")]
use ndarray::{Array, Ix, IxDyn, ShapeBuilder};
#[cfg(feature = "ndarray_volumes")]
use super::ndarray::IntoNdArray;

/// The maximum size in bytes to reserve before the volume voxel data is read.
const PREALLOC_MAX_SIZE: usize = 1 << 28; // 256M

macro_rules! fn_convert_and_cast {
    ($fname: ident, $typ: ty, $converter: expr) => {
        #[cfg(feature = "ndarray_volumes")]
        fn $fname <O> (self) -> Result<Array<O, IxDyn>>
        where
            O: DataElement,
        {
            use crate::volume::element::LinearTransform;

            let dim: Vec<_> = self.dim().iter().map(|d| *d as Ix).collect();

            // cast raw data from file) to the corresponding DataElement
            let data: Vec<_> = <$typ as DataElement>::from_raw_vec(self.raw_data, self.endianness)?;
            // cast elements to the requested output type
            let mut data: Vec<O> = data.into_iter().map($converter).collect();
            // apply slope and inter before creating the final ndarray
            <O as DataElement>::Transform::linear_transform_many_inline(
                &mut data,
                self.scl_slope,
                self.scl_inter,
            );
    
            Ok(Array::from_shape_vec(IxDyn(&dim).f(), data).expect("Inconsistent raw data size"))
        }
    };
}

/// A data type for a NIFTI-1 volume contained in memory. Objects of this type
/// contain raw image data, which is converted automatically when using reading
/// methods or [converting it to an `ndarray`] (only with the `ndarray_volumes`
/// feature).
///
/// Since NIfTI volumes are stored in disk in column major order (also called
/// Fortran order), this data type will also retain this memory order.
///
/// [converting it to an `ndarray`]: ../ndarray/index.html
///
#[derive(Debug, PartialEq, Clone)]
pub struct InMemNiftiVolume {
    dim: Dim,
    datatype: NiftiType,
    scl_slope: f32,
    scl_inter: f32,
    raw_data: Vec<u8>,
    endianness: Endianness,
}
{'fraction_non_alphanumeric': 0.1379511059371362, 'fraction_numerical': 0.005044625533566162, 'mean_word_length': 3.350210970464135, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '876564', 'n_tokens_mistral': 1667, 'n_tokens_neox': 1634, 'n_words': 461}