165 lines
4.6 KiB
Rust
165 lines
4.6 KiB
Rust
//! # rtx-medical-core
|
|
//!
|
|
//! Unified medical imaging super-crate consolidating I/O formats and volume handling.
|
|
//!
|
|
//! This crate provides a comprehensive foundation for medical imaging applications,
|
|
//! supporting various formats (NIfTI, DICOM) and volume processing operations.
|
|
//!
|
|
//! ## Features
|
|
//!
|
|
//! - `volume`: Core volume data structure (enabled by default)
|
|
//! - `nifti`: NIfTI file format support (enabled by default)
|
|
//! - `dicom`: DICOM file format support
|
|
//! - `gpu`: GPU acceleration support via rtx-tensor
|
|
//! - `full`: All features enabled
|
|
//!
|
|
//! ## Example
|
|
//!
|
|
//! ```rust
|
|
//! use rtx_medical_core::{
|
|
//! Volume,
|
|
//! MedicalMetadata,
|
|
//! VoxelSpacing,
|
|
//! };
|
|
//!
|
|
//! // Create voxel spacing
|
|
//! let spacing = VoxelSpacing::isotropic(1.0);
|
|
//!
|
|
//! // Create a volume filled with zeros
|
|
//! let volume = Volume::zeros([256, 256, 128]);
|
|
//!
|
|
//! // Access volume properties
|
|
//! println!("Volume shape: {:?}", volume.shape());
|
|
//! println!("Number of voxels: {}", volume.num_voxels());
|
|
//! ```
|
|
|
|
#![deny(missing_docs)]
|
|
// Note: unsafe_code is allowed in specific modules (volume) for performance-critical operations
|
|
|
|
// Core modules (always available)
|
|
mod error;
|
|
mod metadata;
|
|
|
|
// Re-export core types
|
|
pub use error::{MedicalError, MedicalResult};
|
|
pub use metadata::{MedicalMetadata, Orientation, VoxelSpacing};
|
|
|
|
// Feature-gated modules
|
|
#[cfg(feature = "volume")]
|
|
#[allow(unsafe_code)]
|
|
mod volume;
|
|
|
|
#[cfg(feature = "volume")]
|
|
pub use volume::Volume;
|
|
|
|
#[cfg(feature = "nifti")]
|
|
/// NIfTI file format support
|
|
pub mod nifti;
|
|
|
|
#[cfg(feature = "nifti")]
|
|
pub use nifti::{NiftiDataType, NiftiHeader, NiftiVolume, read_nifti, write_nifti};
|
|
|
|
#[cfg(feature = "dicom")]
|
|
/// DICOM file format support
|
|
pub mod dicom;
|
|
|
|
#[cfg(feature = "dicom")]
|
|
pub use dicom::{DicomMetadata, Modality, TransferSyntax};
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_core_exports_available() {
|
|
let spacing = VoxelSpacing::isotropic(1.0);
|
|
let metadata = MedicalMetadata::new((10, 10, 10), spacing);
|
|
assert_eq!(metadata.dimensions, (10, 10, 10));
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_export_available() {
|
|
let err = MedicalError::Volume("test".to_string());
|
|
assert!(err.to_string().contains("test"));
|
|
}
|
|
|
|
#[cfg(feature = "volume")]
|
|
#[test]
|
|
fn test_volume_export_available() {
|
|
let volume = Volume::zeros([10, 10, 10]);
|
|
assert_eq!(volume.shape(), [10, 10, 10]);
|
|
assert_eq!(volume.num_voxels(), 1000);
|
|
}
|
|
|
|
#[cfg(feature = "nifti")]
|
|
#[test]
|
|
fn test_nifti_exports_available() {
|
|
// Test NiftiDataType is accessible and works
|
|
let datatype = NiftiDataType::Int16;
|
|
assert_eq!(datatype.bytes_per_voxel(), 2);
|
|
|
|
// Test NiftiDataType conversion
|
|
let float_type = NiftiDataType::Float32;
|
|
assert_eq!(float_type.bytes_per_voxel(), 4);
|
|
|
|
// Test Affine4 type is accessible
|
|
let affine = nifti::identity();
|
|
assert_eq!(affine[0][0], 1.0);
|
|
}
|
|
|
|
#[cfg(feature = "dicom")]
|
|
#[test]
|
|
fn test_dicom_exports_available() {
|
|
let modality = Modality::CT;
|
|
assert_eq!(modality.code(), "CT");
|
|
|
|
let transfer_syntax = TransferSyntax::ExplicitVRLittleEndian;
|
|
assert_eq!(transfer_syntax.uid(), "1.2.840.10008.1.2.1");
|
|
|
|
let metadata = DicomMetadata::new(modality, transfer_syntax);
|
|
assert_eq!(metadata.modality, Modality::CT);
|
|
}
|
|
|
|
#[test]
|
|
fn test_medical_result_propagation() {
|
|
fn test_function() -> MedicalResult<i32> {
|
|
Err(MedicalError::Volume("test error".to_string()))
|
|
}
|
|
|
|
let result = test_function();
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_medical_result_ok_propagation() {
|
|
fn test_function() -> MedicalResult<i32> {
|
|
Ok(42)
|
|
}
|
|
|
|
let result = test_function();
|
|
assert_eq!(result.unwrap(), 42);
|
|
}
|
|
|
|
#[cfg(feature = "volume")]
|
|
#[test]
|
|
fn test_integration_volume_with_metadata() {
|
|
let volume = Volume::filled([64, 64, 32], 100.0);
|
|
assert_eq!(volume.shape(), [64, 64, 32]);
|
|
assert_eq!(volume.num_voxels(), 64 * 64 * 32);
|
|
assert_eq!(volume.spacing(), [1.0, 1.0, 1.0]);
|
|
}
|
|
|
|
#[cfg(all(feature = "volume", feature = "nifti"))]
|
|
#[test]
|
|
fn test_integration_volume_with_nifti() {
|
|
// Test that volume and nifti types work together
|
|
let volume = Volume::zeros([128, 128, 64]);
|
|
assert_eq!(volume.num_voxels(), 128 * 128 * 64);
|
|
assert_eq!(volume.shape(), [128, 128, 64]);
|
|
|
|
// NiftiDataType is accessible
|
|
let dtype = NiftiDataType::Float64;
|
|
assert_eq!(dtype.bytes_per_voxel(), 8);
|
|
}
|
|
}
|