Consistent formatting pass: line wrapping, import sorting, trailing whitespace removal, let-chain indentation, merged derive attributes, and unsafe block reformatting. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
148 lines
4.1 KiB
Rust
148 lines
4.1 KiB
Rust
//! Slide metadata types for SlideScope demo
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Slide metadata containing all information about a pathology slide
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct SlideMetadata {
|
|
/// Unique slide identifier
|
|
pub id: String,
|
|
/// Display name of the slide
|
|
pub name: String,
|
|
/// Original file path
|
|
pub path: String,
|
|
/// Image width in pixels
|
|
pub width: u32,
|
|
/// Image height in pixels
|
|
pub height: u32,
|
|
/// Current processing status
|
|
pub status: SlideStatus,
|
|
/// Detected or configured stain type
|
|
pub stain_type: Option<StainType>,
|
|
/// Path to generated thumbnail
|
|
pub thumbnail_path: Option<String>,
|
|
/// Path to pre-generated tile pyramid
|
|
pub pyramid_path: Option<String>,
|
|
/// Unix timestamp when slide was imported
|
|
pub created_at: i64,
|
|
/// Unix timestamp when processing completed
|
|
pub processed_at: Option<i64>,
|
|
}
|
|
|
|
/// Processing status of a slide
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "lowercase")]
|
|
#[derive(Default)]
|
|
pub enum SlideStatus {
|
|
/// Slide imported and pyramid generated, ready for processing
|
|
#[default]
|
|
Imported,
|
|
/// NMF processing in progress
|
|
Processing,
|
|
/// Processing completed successfully
|
|
Processed,
|
|
/// Processing failed
|
|
Failed,
|
|
}
|
|
|
|
impl std::fmt::Display for SlideStatus {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Imported => write!(f, "imported"),
|
|
Self::Processing => write!(f, "processing"),
|
|
Self::Processed => write!(f, "processed"),
|
|
Self::Failed => write!(f, "failed"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Stain type for pathology slides
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
pub enum StainType {
|
|
/// Hematoxylin and Eosin (most common)
|
|
#[serde(rename = "H&E")]
|
|
#[default]
|
|
HE,
|
|
/// Immunohistochemistry with DAB chromogen
|
|
#[serde(rename = "IHC-DAB")]
|
|
IhcDab,
|
|
/// Custom or unknown stain configuration
|
|
Custom,
|
|
}
|
|
|
|
impl std::fmt::Display for StainType {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::HE => write!(f, "H&E"),
|
|
Self::IhcDab => write!(f, "IHC-DAB"),
|
|
Self::Custom => write!(f, "Custom"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Supported image formats for import
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum ImageFormat {
|
|
/// Standard TIFF
|
|
Tiff,
|
|
/// BigTIFF for large images
|
|
BigTiff,
|
|
/// Aperio SVS format
|
|
Svs,
|
|
/// Hamamatsu NDPI format
|
|
Ndpi,
|
|
/// PNG format
|
|
Png,
|
|
/// JPEG format
|
|
Jpeg,
|
|
}
|
|
|
|
impl ImageFormat {
|
|
/// Detect format from file extension
|
|
pub fn from_extension(ext: &str) -> Option<Self> {
|
|
match ext.to_lowercase().as_str() {
|
|
"tif" | "tiff" => Some(Self::Tiff),
|
|
"svs" => Some(Self::Svs),
|
|
"ndpi" => Some(Self::Ndpi),
|
|
"png" => Some(Self::Png),
|
|
"jpg" | "jpeg" => Some(Self::Jpeg),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
/// Check if format requires OpenSlide
|
|
pub fn requires_openslide(&self) -> bool {
|
|
matches!(self, Self::Svs | Self::Ndpi)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_slide_status_serialization() {
|
|
let status = SlideStatus::Processing;
|
|
let json = serde_json::to_string(&status).unwrap();
|
|
assert_eq!(json, "\"processing\"");
|
|
|
|
let deserialized: SlideStatus = serde_json::from_str(&json).unwrap();
|
|
assert_eq!(deserialized, SlideStatus::Processing);
|
|
}
|
|
|
|
#[test]
|
|
fn test_stain_type_serialization() {
|
|
let stain = StainType::HE;
|
|
let json = serde_json::to_string(&stain).unwrap();
|
|
assert_eq!(json, "\"H&E\"");
|
|
}
|
|
|
|
#[test]
|
|
fn test_image_format_detection() {
|
|
assert_eq!(ImageFormat::from_extension("tif"), Some(ImageFormat::Tiff));
|
|
assert_eq!(ImageFormat::from_extension("SVS"), Some(ImageFormat::Svs));
|
|
assert_eq!(ImageFormat::from_extension("unknown"), None);
|
|
}
|
|
}
|