use crate::header::{EmptyObject, HasLength, Length, Tag};
use num_traits::NumCast;
use smallvec::SmallVec;
use std::{borrow::Cow, str::FromStr};
pub mod deserialize;
mod primitive;
pub mod serialize;
pub use self::deserialize::Error as DeserializeError;
pub use self::primitive::{
CastValueError, ConvertValueError, InvalidValueReadError, PrimitiveValue, ValueType,
};
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveTime};
pub type C<T> = SmallVec<[T; 2]>;
pub trait DicomValueType: HasLength {
fn value_type(&self) -> ValueType;
fn cardinality(&self) -> usize;
}
#[derive(Debug, Clone, PartialEq)]
pub enum Value<I = EmptyObject, P = [u8; 0]> {
Primitive(PrimitiveValue),
Sequence {
items: C<I>,
size: Length,
},
PixelSequence {
offset_table: C<u8>,
fragments: C<P>,
},
}
impl<P> Value<EmptyObject, P> {
pub fn new_pixel_sequence<T>(offset_table: C<u8>, fragments: T) -> Self
where
T: Into<C<P>>,
{
Value::PixelSequence {
offset_table,
fragments: fragments.into(),
}
}
}
impl<I> Value<I, [u8; 0]> {
#[inline]
pub fn new_sequence<T>(items: T, length: Length) -> Self
where
T: Into<C<I>>,
{
Value::Sequence {
items: items.into(),
size: length,
}
}
}
impl Value<EmptyObject, [u8; 0]> {
#[inline]
pub fn new(value: PrimitiveValue) -> Self {
Self::from(value)
}
}
impl<I, P> Value<I, P> {
pub fn multiplicity(&self) -> u32 {
match *self {
Value::Primitive(ref v) => v.multiplicity(),
Value::Sequence { ref items, .. } => items.len() as u32,
Value::PixelSequence { .. } => 1,
}
}
pub fn primitive(&self) -> Option<&PrimitiveValue> {
match *self {
Value::Primitive(ref v) => Some(v),
_ => None,
}
}
pub fn items(&self) -> Option<&[I]> {
match *self {
Value::Sequence { ref items, .. } => Some(items),
_ => None,
}
}
pub fn into_primitive(self) -> Option<PrimitiveValue> {
match self {
Value::Primitive(v) => Some(v),
_ => None,
}
}
pub fn into_items(self) -> Option<C<I>> {
match self {
Value::Sequence { items, .. } => Some(items),
_ => None,
}
}
pub fn offset_table(&self) -> Option<&[u8]> {
match self {
Value::PixelSequence { offset_table, .. } => Some(&offset_table),
_ => None,
}
}
}
impl<I, P> HasLength for Value<I, P> {
fn length(&self) -> Length {
match self {
Value::Primitive(v) => v.length(),
Value::Sequence { size, .. } => *size,
Value::PixelSequence { .. } => Length::UNDEFINED,
}
}
}
impl<I, P> DicomValueType for Value<I, P> {
fn value_type(&self) -> ValueType {
match self {
Value::Primitive(v) => v.value_type(),
Value::Sequence { .. } => ValueType::Item,
Value::PixelSequence { .. } => ValueType::PixelSequence,
}
}
fn cardinality(&self) -> usize {
match self {
Value::Primitive(v) => v.cardinality(),
Value::Sequence { items, .. } => items.len(),
Value::PixelSequence { .. } => 1,
}
}
}
impl<I, P> Value<I, P>
where
I: HasLength,
{
pub fn to_str(&self) -> Result<Cow<str>, CastValueError> {
match self {
Value::Primitive(prim) => Ok(prim.to_str()),
_ => Err(CastValueError {
requested: "string",
got: self.value_type(),
}),
}
}
pub fn to_clean_str(&self) -> Result<Cow<str>, CastValueError> {
match self {
Value::Primitive(prim) => Ok(prim.to_clean_str()),
_ => Err(CastValueError {
requested: "string",
got: self.value_type(),
}),
}
}
pub fn to_multi_str(&self) -> Result<Cow<[String]>, CastValueError> {
match self {
Value::Primitive(prim) => Ok(prim.to_multi_str()),
_ => Err(CastValueError {
requested: "string",
got: self.value_type(),
}),
}
}
pub fn to_bytes(&self) -> Result<Cow<[u8]>, CastValueError> {
match self {
Value::Primitive(prim) => Ok(prim.to_bytes()),
_ => Err(CastValueError {
requested: "bytes",
got: self.value_type(),
}),
}
}
#[deprecated(note = "use `uint8_slice` instead")]
pub fn as_u8(&self) -> Result<&[u8], CastValueError> {
self.uint8_slice()
}
#[deprecated(note = "use `int32_slice` instead")]
pub fn as_i32(&self) -> Result<&[i32], CastValueError> {
self.int32_slice()
}
pub fn to_int<T>(&self) -> Result<T, ConvertValueError>
where
T: Clone,
T: NumCast,
T: FromStr<Err = std::num::ParseIntError>,
{
match self {
Value::Primitive(v) => v.to_int::<T>(),
_ => Err(ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_int<T>(&self) -> Result<Vec<T>, ConvertValueError>
where
T: Clone,
T: NumCast,
T: FromStr<Err = std::num::ParseIntError>,
{
match self {
Value::Primitive(v) => v.to_multi_int::<T>(),
_ => Err(ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_float32(&self) -> Result<f32, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_float32(),
_ => Err(ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_float32(&self) -> Result<Vec<f32>, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_multi_float32(),
_ => Err(ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_float64(&self) -> Result<f64, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_float64(),
_ => Err(ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_float64(&self) -> Result<Vec<f64>, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_multi_float64(),
_ => Err(ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_date(&self) -> Result<NaiveDate, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_date(),
_ => Err(ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_date(&self) -> Result<Vec<NaiveDate>, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_multi_date(),
_ => Err(ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_time(&self) -> Result<NaiveTime, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_time(),
_ => Err(ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_time(&self) -> Result<Vec<NaiveTime>, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_multi_time(),
_ => Err(ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_datetime(
&self,
default_offset: FixedOffset,
) -> Result<DateTime<FixedOffset>, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_datetime(default_offset),
_ => Err(ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_datetime(
&self,
default_offset: FixedOffset,
) -> Result<Vec<DateTime<FixedOffset>>, ConvertValueError> {
match self {
Value::Primitive(v) => v.to_multi_datetime(default_offset),
_ => Err(ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_tag(&self) -> Result<Tag, CastValueError> {
match self {
Value::Primitive(PrimitiveValue::Tags(v)) => Ok(v[0]),
_ => Err(CastValueError {
requested: "tag",
got: self.value_type(),
}),
}
}
#[deprecated(note = "use `tags` instead")]
pub fn as_tags(&self) -> Result<&[Tag], CastValueError> {
self.tags()
}
}
macro_rules! impl_primitive_getters {
($name_single: ident, $name_multi: ident, $variant: ident, $ret: ty) => {
pub fn $name_single(&self) -> Result<$ret, CastValueError> {
match self {
Value::Primitive(v) => v.$name_single(),
value => Err(CastValueError {
requested: stringify!($name_single),
got: value.value_type(),
}),
}
}
pub fn $name_multi(&self) -> Result<&[$ret], CastValueError> {
match self {
Value::Primitive(v) => v.$name_multi(),
value => Err(CastValueError {
requested: stringify!($name_multi),
got: value.value_type(),
}),
}
}
};
}
impl<I, P> Value<I, P> {
pub fn string(&self) -> Result<&str, CastValueError> {
match self {
Value::Primitive(v) => v.string(),
_ => Err(CastValueError {
requested: "string",
got: self.value_type(),
}),
}
}
pub fn strings(&self) -> Result<&[String], CastValueError> {
match self {
Value::Primitive(v) => v.strings(),
_ => Err(CastValueError {
requested: "strings",
got: self.value_type(),
}),
}
}
impl_primitive_getters!(tag, tags, Tags, Tag);
impl_primitive_getters!(date, dates, Date, NaiveDate);
impl_primitive_getters!(time, times, Time, NaiveTime);
impl_primitive_getters!(datetime, datetimes, DateTime, DateTime<FixedOffset>);
impl_primitive_getters!(uint8, uint8_slice, U8, u8);
impl_primitive_getters!(uint16, uint16_slice, U16, u16);
impl_primitive_getters!(int16, int16_slice, I16, i16);
impl_primitive_getters!(uint32, uint32_slice, U32, u32);
impl_primitive_getters!(int32, int32_slice, I32, i32);
impl_primitive_getters!(int64, int64_slice, I64, i64);
impl_primitive_getters!(uint64, uint64_slice, U64, u64);
impl_primitive_getters!(float32, float32_slice, F32, f32);
impl_primitive_getters!(float64, float64_slice, F64, f64);
}
impl<I, P> From<PrimitiveValue> for Value<I, P> {
fn from(v: PrimitiveValue) -> Self {
Value::Primitive(v)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dicom_value;
use crate::header::EmptyObject;
use smallvec::smallvec;
#[test]
fn to_int() {
let value = Value::new(dicom_value!(I32, [1, 2, 5]));
assert_eq!(value.to_int::<u32>().unwrap(), 1);
assert_eq!(value.to_int::<i32>().unwrap(), 1);
assert_eq!(value.to_int::<u16>().unwrap(), 1);
assert_eq!(value.to_int::<i16>().unwrap(), 1);
assert_eq!(value.to_int::<u64>().unwrap(), 1);
assert_eq!(value.to_int::<i64>().unwrap(), 1);
assert_eq!(value.to_multi_int::<i32>().unwrap(), vec![1, 2, 5]);
assert_eq!(value.to_multi_int::<u32>().unwrap(), vec![1, 2, 5]);
let value = Value::<EmptyObject, _>::new_sequence(smallvec![], Length::UNDEFINED);
assert!(matches!(
value.to_int::<u32>(),
Err(ConvertValueError {
requested: "integer",
original: ValueType::Item,
..
})
));
}
#[test]
fn to_float() {
let value = Value::new(dicom_value!(F64, [1., 2., 5.]));
assert_eq!(value.to_float32().unwrap(), 1.);
assert_eq!(value.to_float64().unwrap(), 1.);
assert_eq!(value.to_multi_float32().unwrap(), vec![1., 2., 5.]);
assert_eq!(value.to_multi_float64().unwrap(), vec![1., 2., 5.]);
let value = Value::<EmptyObject, _>::new_sequence(smallvec![], Length::UNDEFINED);
assert!(matches!(
value.to_float32(),
Err(ConvertValueError {
requested: "float32",
original: ValueType::Item,
..
})
));
}
#[test]
fn getters() {
assert_eq!(
Value::new(dicom_value!(Strs, ["Smith^John"]))
.string()
.unwrap(),
"Smith^John"
);
assert_eq!(
Value::new(dicom_value!(Strs, ["Smith^John"]))
.strings()
.unwrap(),
&["Smith^John"]
);
assert_eq!(Value::new(dicom_value!(I32, [1, 2, 5])).int32().unwrap(), 1,);
assert_eq!(
Value::new(dicom_value!(I32, [1, 2, 5]))
.int32_slice()
.unwrap(),
&[1, 2, 5],
);
assert!(matches!(
Value::new(dicom_value!(I32, [1, 2, 5])).uint32(),
Err(CastValueError {
requested: "uint32",
got: ValueType::I32,
..
})
));
assert!(matches!(
Value::new(dicom_value!(I32, [1, 2, 5])).strings(),
Err(CastValueError {
requested: "strings",
got: ValueType::I32,
..
})
));
assert_eq!(
Value::new(PrimitiveValue::Date(smallvec![NaiveDate::from_ymd(
2014, 10, 12
)]))
.date()
.unwrap(),
NaiveDate::from_ymd(2014, 10, 12),
);
assert_eq!(
Value::new(PrimitiveValue::Date(
smallvec![NaiveDate::from_ymd(2014, 10, 12); 5]
))
.dates()
.unwrap(),
&[NaiveDate::from_ymd(2014, 10, 12); 5]
);
assert!(matches!(
Value::new(PrimitiveValue::Date(smallvec![NaiveDate::from_ymd(
2014, 10, 12
)]))
.time(),
Err(CastValueError {
requested: "time",
got: ValueType::Date,
..
})
));
}
}