Rust Implementation of DICOM Medical Imaging Systems: Type-Safe Database Design
This project demonstrates how to build a robust, type-safe database access layer in Rust, specifically designed for healthcare applications requiring strict data validation. Through abstract interfaces and concrete implementation separation, the system can easily scale to support more database types while ensuring code maintainability and testability.
Core Design Concepts
1. Type-Safe Data Structures
Several key type-safe wrappers are defined in the project:
- BoundedString: Length-limited string type
- FixedLengthString: Fixed-length string type
- DicomDateString: Specialized string type for DICOM date format
// Example: BoundedString definition
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct BoundedString<const N: usize> {
value: String,
}
- Unified Database Access Interface The database operations interface is abstracted through the DbProvider trait:
#[async_trait]
pub trait DbProvider: Send + Sync {
async fn save_state_info(&self, state_meta: &DicomStateMeta) -> Result<(), DbError>;
async fn save_state_list(&self, state_meta: &[DicomStateMeta]) -> Result<(), DbError>;
async fn save_json_list(&self, state_meta: &[DicomJsonMeta]) -> Result<(), DbError>;
// ... other methods
}
- Database Type Adapters
MySQL
MySqlDbProvider struct implements operations for MySQL database::
pub struct MySqlDbProvider {
db_connection_string: String,
}
#[async_trait]
impl DbProvider for MySqlDbProvider {
// Implementation of various database operation methods
}
PostgreSQL
PgDbProvider struct provides support for PostgreSQL database:
pub struct PgDbProvider {
db_connection_string: String,
}
#[async_trait]
impl DbProvider for PgDbProvider {
// Implementation of various database operation methods
}
- Key Data Models DICOM State Metadata DicomStateMeta struct contains patient, study, and series-level metadata information:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DicomStateMeta {
pub tenant_id: BoundedString<64>,
pub patient_id: BoundedString<64>,
pub study_uid: BoundedString<64>,
pub series_uid: BoundedString<64>,
// ...
}
DICOM Image Metadata
DicomImageMeta struct stores instance-level image-related information:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DicomImageMeta {
pub tenant_id: BoundedString<64>,
pub patient_id: BoundedString<64>,
pub study_uid: BoundedString<64>,
pub series_uid: BoundedString<64>,
pub sop_uid: BoundedString<64>,
// ...
}
Technical Highlights
-
Compile-Time Type Safety Through Rust’s generics and type system, many potential data errors can be caught at compile time:
-
Asynchronous Database Operations All database operations are implemented asynchronously to improve system concurrency performance:
-
Unified Error Handling Using thiserror and snafu libraries to handle various error scenarios uniformly:
Project Structure
database/ ├── src/ │ ├── dicom_dbprovider.rs # Database provider trait definition │ ├── dicom_dbtype.rs # Custom database types │ ├── dicom_meta.rs # DICOM metadata structure definition │ ├── dicom_mysql.rs # MySQL implementation │ ├── dicom_mysql_types.rs # MySQL type adaptation │ ├── dicom_pg.rs # PostgreSQL implementation │ ├── dicom_pg_types.rs # PostgreSQL type adaptation │ └── lib.rs # Library entry file └── Cargo.toml # Project configuration file
The Cargo.toml configuration is as follows:
[package]
name = "database"
version = "0.1.0"
edition = "2024"
[dependencies]
md5 = { workspace = true }
const-crc32 = { workspace = true }
snafu = { workspace = true }
uuid = { workspace = true, features = ["v4", "v7", "fast-rng"] }
serde_json = "1.0.145"
serde = { workspace = true, features = ["derive"] }
config = { workspace = true } # Configuration file parsing
dotenv = { workspace = true }
clap = { workspace = true, features = ["derive"] }
dicom-core = { workspace = true }
dicom-ul = { workspace = true, features = ["async"] }
dicom-object = { workspace = true }
dicom-encoding = { workspace = true }
dicom-pixeldata = { workspace = true,
features = ["native", "jpeg", "rle", "image", "jpegxl", "openjp2", "rayon", "deflate"] }
dicom-dictionary-std = { workspace = true }
dicom-transfer-syntax-registry = { workspace = true }
seahash = { workspace = true }
async-trait = { workspace = true }
tracing = { workspace = true }
tokio = { workspace = true, features = ["full"] }
urlencoding = { workspace = true }
url = { workspace = true }
slog = { workspace = true }
slog-term = { workspace = true }
slog-async = { workspace = true }
slog-stdlog = { workspace = true }
slog-scope = { workspace = true }
rdkafka = { workspace = true }
futures = { workspace = true }
futures-util = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
rayon = { workspace = true }
thiserror = { workspace = true }
encoding_rs = { workspace = true }
gdcm_conv = { workspace = true }
rstest = { workspace = true }
openssl = { workspace = true, features = ["v102", "vendored"] }
x509-parser = { workspace = true }
der = { workspace = true }
pem = { workspace = true }
hex = { workspace = true }
regex = { workspace = true }
lazy_static = { workspace = true }
tempfile = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
aes-gcm = { workspace = true }
rand = { workspace = true }
base64 = { workspace = true }
cipher = "0.4.4"
salsa20 = "0.10.2"
generic-array = "0.14.7"
chrono-tz = "0.10.4"
tokio-postgres = {
version = "0.7.15",
features = ["default", "with-time-0_3", "with-uuid-1", "with-chrono-0_4"]
}
postgres-types = "0.2.11"
mysql = {
version = "26.0.1",
default-features = false,
features = ["minimal-rust", "rustls-tls","chrono","time"]
}
ctor = "0.6.1"
The next section will detail database type definitions and implementations.
DICOM Cloud Part ONE Database Type Defines
This comprehensive guide demonstrates how to implement type-safe database access in Rust for medical imaging applications, providing a solid foundation for building reliable healthcare technology solutions.