//! 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, /// Path to generated thumbnail pub thumbnail_path: Option, /// Path to pre-generated tile pyramid pub pyramid_path: Option, /// Unix timestamp when slide was imported pub created_at: i64, /// Unix timestamp when processing completed pub processed_at: Option, } /// 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 { 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); } }