diff --git a/src/dicom_json.rs b/src/dicom_json.rs index 93a2561..5558d38 100644 --- a/src/dicom_json.rs +++ b/src/dicom_json.rs @@ -14,18 +14,48 @@ pub struct Alphabetic { #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(untagged)] pub enum DicomValue { - Integer(i64), - Float(f64), - String(String), - Alphabetic(Alphabetic), - SeqField(DicomJsonData), + Integer(Vec), + Float(Vec), + String(Vec), + Alphabetic([Alphabetic; 1]), + SeqField(Vec), +} + +impl DicomValue { + pub fn is_empty(&self) -> bool { + match self { + DicomValue::Integer(v) => v.is_empty(), + DicomValue::Float(v) => v.is_empty(), + DicomValue::String(v) => v.is_empty(), + DicomValue::Alphabetic(v) => v.is_empty(), + DicomValue::SeqField(v) => v.is_empty(), + } + } + + #[cfg(test)] + pub fn to_string_ref(&self) -> Option<&[String]> { + if let DicomValue::String(s) = self { + Some(s) + } else { + None + } + } + + #[cfg(test)] + pub fn to_alphabetic_ref(&self) -> Option<&[Alphabetic]> { + if let DicomValue::Alphabetic(s) = self { + Some(s) + } else { + None + } + } } #[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct DicomField { #[serde(rename = "Value")] #[serde(skip_serializing_if = "Option::is_none")] - pub value: Option>, + pub value: Option, #[serde(with = "vr_serialization")] pub vr: VR, #[serde(rename = "InlineBinary")] diff --git a/src/dimble_to_ir.rs b/src/dimble_to_ir.rs index f1f329a..6ca84bf 100644 --- a/src/dimble_to_ir.rs +++ b/src/dimble_to_ir.rs @@ -1,7 +1,7 @@ use crate::dicom_json::*; use crate::ir_to_dimble::{HeaderField, HeaderFieldMap}; use memmap2::MmapOptions; -use rmpv::{decode, Integer, Value}; +use serde::Deserialize; use std::fs; fn headerfield_and_bytes_to_dicom_fields( @@ -18,8 +18,10 @@ fn headerfield_and_bytes_to_dicom_fields( HeaderField::SQ(sqs) => { let seq_fields = sqs .iter() - .map(|sq| DicomValue::SeqField(headers_to_data(sq, dimble_buffer))) - .collect::>(); + .map(|sq| headers_to_data(sq, dimble_buffer)) + .collect(); + + let seq_fields = DicomValue::SeqField(seq_fields); DicomField { value: Some(seq_fields), @@ -50,31 +52,36 @@ fn headerfield_and_bytes_to_dicom_fields( } b"PN" => { let name = rmp_serde::decode::from_slice(field_bytes).unwrap(); - let a = DicomValue::Alphabetic(Alphabetic { alphabetic: name }); + let a = DicomValue::Alphabetic([Alphabetic { alphabetic: name }]); DicomField { - value: Some(vec![a]), + value: Some(a), vr: *vr, inline_binary: None, } } _ => { - let mut cursor = field_bytes; - let v = decode::read_value(&mut cursor).unwrap(); - let value: Vec<_> = match v { - Value::String(s) => vec![DicomValue::String(s.into_str().unwrap())], - Value::Integer(i) => vec![integer_to_dicom_value(&i)], - Value::F64(f) => vec![DicomValue::Float(f)], - Value::Array(a) => a - .into_iter() - .map(|v| match v { - Value::String(s) => DicomValue::String(s.into_str().unwrap()), - Value::Integer(i) => integer_to_dicom_value(&i), - Value::F64(f) => DicomValue::Float(f), - _ => panic!("unexpected value type: {v:?}"), - }) - .collect(), - _ => panic!("unexpected value type: {v:?}"), + #[derive(Debug, Deserialize)] + #[serde(untagged)] + enum MyValue { + String(String), + Strings(Vec), + Integer(i64), // We only support values that can be represented as i64 + Integers(Vec), + F64(f64), + F64s(Vec), + } + + let v = rmp_serde::decode::from_slice(field_bytes).unwrap(); + + let value = match v { + MyValue::String(s) => DicomValue::String(vec![s]), + MyValue::Strings(s) => DicomValue::String(s), + MyValue::Integer(i) => DicomValue::Integer(vec![i]), + MyValue::Integers(i) => DicomValue::Integer(i), + MyValue::F64(f) => DicomValue::Float(vec![f]), + MyValue::F64s(f) => DicomValue::Float(f), }; + DicomField { value: Some(value), vr: *vr, @@ -96,16 +103,6 @@ fn headers_to_data(sq: &HeaderFieldMap, dimble_buffer: &[u8]) -> DicomJsonData { .collect() } -fn integer_to_dicom_value(i: &Integer) -> DicomValue { - if let Some(v) = i.as_i64() { - DicomValue::Integer(v) - } else if let Some(v) = i.as_u64() { - DicomValue::Integer(v as i64) - } else { - panic!("Could not represent the integer as i64 or u64") - } -} - pub fn dimble_to_dicom_json(dimble_path: &str, json_path: &str) { let dimble_file = fs::File::open(dimble_path).unwrap(); let dimble_buffer = unsafe { MmapOptions::new().map(&dimble_file).expect("mmap failed") }; diff --git a/src/ir_to_dimble.rs b/src/ir_to_dimble.rs index 4c581a4..b0e71fa 100644 --- a/src/ir_to_dimble.rs +++ b/src/ir_to_dimble.rs @@ -31,49 +31,25 @@ fn get_file_bytes(safetensors_path: &str) -> Vec { fs::read(safetensors_path).unwrap() } -fn dicom_values_to_vec(tag: &str, dicom_values: &[DicomValue]) -> Option> { +fn dicom_values_to_vec(dicom_values: &DicomValue) -> Option> { let field_bytes = match dicom_values { - [DicomValue::String(s)] => to_vec(&s), - [DicomValue::Integer(u)] => to_vec(&u), - [DicomValue::Float(u)] => to_vec(&u), - [DicomValue::Alphabetic(u)] => to_vec(&u.alphabetic), - many => match many - .first() - .expect("This should definitely have a first element") - { - DicomValue::String(_) => to_vec( - &many - .iter() - .map(|v| match v { - DicomValue::String(s) => s.to_owned(), - _ => panic!("{tag} expected only strings"), - }) - .collect::>(), - ), - DicomValue::Integer(_) => to_vec( - &many - .iter() - .map(|v| match v { - DicomValue::Integer(i) => *i, - _ => panic!("{tag} expected only ints"), - }) - .collect::>(), - ), - DicomValue::Float(_) => to_vec( - &many - .iter() - .map(|v| match v { - DicomValue::Float(f) => *f, - _ => panic!("{tag} expected only floats"), - }) - .collect::>(), - ), - DicomValue::SeqField(_) => { - // TODO: handle sequences of sequences properly - return None; - } - other => panic!("{tag} unexpected value type {:?}", other), + DicomValue::String(v) => match &**v { + [s] => to_vec(&s), + o => to_vec(o), + }, + DicomValue::Integer(v) => match &**v { + [u] => to_vec(&u), + o => to_vec(o), }, + DicomValue::Float(v) => match &**v { + [u] => to_vec(&u), + o => to_vec(o), + }, + DicomValue::Alphabetic([u]) => to_vec(&u.alphabetic), + DicomValue::SeqField(_) => { + // TODO: handle sequences of sequences properly + return None; + } }; let field_bytes = field_bytes.unwrap(); Some(field_bytes) @@ -107,17 +83,27 @@ fn prepare_dimble_field( vr, inline_binary: None, } => { - match value.as_slice() { - [] if vr == b"SQ" => Ok(HeaderField::SQ(vec![])), - [] => panic!("empty value"), - [DicomValue::SeqField(seq)] => { - let sq_header_field_map = - prepare_dimble_fields(seq, data_bytes, pixel_array_safetensors_path)?; - Ok(HeaderField::SQ(vec![sq_header_field_map])) + if value.is_empty() { + if vr == b"SQ" { + return Ok(HeaderField::SQ(vec![])); + } + panic!("empty value"); + } + + match value { + DicomValue::SeqField(seqs) => { + let seqs = seqs + .iter() + .map(|seq| { + prepare_dimble_fields(seq, data_bytes, pixel_array_safetensors_path) + }) + .collect::>()?; + + Ok(HeaderField::SQ(seqs)) } dicom_values => { // call a function to handle this - match dicom_values_to_vec(tag, dicom_values) { + match dicom_values_to_vec(dicom_values) { Some(field_bytes) => { Ok(extend_and_make_field(data_bytes, &field_bytes, *vr)) } @@ -335,29 +321,23 @@ mod tests { { let field = ir.get("00080005").expect("expected 00080005 to exist"); assert_eq!(field.vr, *b"CS"); - let value: Vec<_> = field + let value = field .value - .iter() - .map(|v| match v.as_slice() { - [DicomValue::String(s)] => s, - _ => panic!("expected only strings"), - }) - .collect(); + .as_ref() + .unwrap() + .to_string_ref() + .expect("expected only strings"); assert_eq!(value, ["ISO_IR 100"]) } { let field = ir.get("00080008").expect("expected 00080008 to exist"); assert_eq!(field.vr, *b"CS"); - let value: Vec<_> = field + let value = field .value .as_ref() .unwrap() - .iter() - .map(|v| match v { - DicomValue::String(s) => s, - _ => panic!("expected only strings"), - }) - .collect(); + .to_string_ref() + .expect("expected only strings"); assert_eq!(value, ["ORIGINAL", "PRIMARY", "OTHER"]); } { @@ -368,17 +348,14 @@ mod tests { { let field = ir.get("00100010").expect("expected 00100010 to exist"); assert_eq!(field.vr, *b"PN"); - let value: Vec<_> = field + let value = field .value .as_ref() .unwrap() - .iter() - .map(|v| match v { - DicomValue::Alphabetic(a) => &a.alphabetic, - _ => panic!("expected only alphabetic"), - }) - .collect(); - assert_eq!(value, ["Doe^John"]) + .to_alphabetic_ref() + .expect("expected only alphabetic"); + let value = value.iter().map(|x| &x.alphabetic).collect::>(); + assert_eq!(value, &["Doe^John"]) } Ok(())