use super::DicomValueType;
use crate::header::{HasLength, Length, Tag};
use chrono::{FixedOffset, Timelike};
use itertools::Itertools;
use num_traits::NumCast;
use safe_transmute::to_bytes::transmute_to_bytes;
use smallvec::SmallVec;
use snafu::{Backtrace, ResultExt, Snafu};
use std::borrow::Cow;
use std::fmt;
use std::str::FromStr;
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum InvalidValueReadError {
#[snafu(display("Sequence cannot be read as a primitive value"))]
NonPrimitiveType { backtrace: Backtrace },
#[snafu(display("Invalid or ambiguous combination of date with time"))]
DateTimeZone { backtrace: Backtrace },
#[snafu(display("Failed to read text as a floating point number"))]
ParseFloat {
backtrace: Backtrace,
source: std::num::ParseFloatError,
},
#[snafu(display("Failed to read text as an integer"))]
ParseInteger {
backtrace: Backtrace,
source: std::num::ParseIntError,
},
#[snafu(display("Unexpected end of element"))]
UnexpectedEndOfElement {},
#[snafu(display("Cannot convert `{}` to the target type requested", value))]
NarrowConvert { value: String, backtrace: Backtrace },
#[snafu(display("Failed to read text as a date"))]
ParseDate {
#[snafu(backtrace)]
source: crate::value::deserialize::Error,
},
#[snafu(display("Failed to read text as a time"))]
ParseTime {
#[snafu(backtrace)]
source: crate::value::deserialize::Error,
},
#[snafu(display("Failed to read text as a date-time"))]
ParseDateTime {
#[snafu(backtrace)]
source: crate::value::deserialize::Error,
},
}
#[derive(Debug, Clone, PartialEq)]
pub struct CastValueError {
pub requested: &'static str,
pub got: ValueType,
}
impl fmt::Display for CastValueError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"bad value cast: requested {} but value is {:?}",
self.requested, self.got
)
}
}
impl std::error::Error for CastValueError {}
#[derive(Debug)]
pub struct ConvertValueError {
pub requested: &'static str,
pub original: ValueType,
pub cause: Option<InvalidValueReadError>,
}
impl fmt::Display for ConvertValueError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"could not convert {:?} to a {}: ",
self.original, self.requested
)?;
if let Some(cause) = &self.cause {
write!(f, "{}", cause)?;
} else {
write!(f, "conversion not possible")?;
}
Ok(())
}
}
impl std::error::Error for ConvertValueError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.cause.as_ref().map(|x| x as _)
}
}
pub type Result<T, E = InvalidValueReadError> = std::result::Result<T, E>;
pub use chrono::{DateTime, NaiveDate, NaiveTime};
pub type C<T> = SmallVec<[T; 2]>;
#[derive(Debug, Clone)]
pub enum PrimitiveValue {
Empty,
Strs(C<String>),
Str(String),
Tags(C<Tag>),
U8(C<u8>),
I16(C<i16>),
U16(C<u16>),
I32(C<i32>),
U32(C<u32>),
I64(C<i64>),
U64(C<u64>),
F32(C<f32>),
F64(C<f64>),
Date(C<NaiveDate>),
DateTime(C<DateTime<FixedOffset>>),
Time(C<NaiveTime>),
}
macro_rules! impl_from_for_primitive {
($typ: ty, $variant: ident) => {
impl From<$typ> for PrimitiveValue {
fn from(value: $typ) -> Self {
PrimitiveValue::$variant(C::from_elem(value, 1))
}
}
};
}
impl_from_for_primitive!(u8, U8);
impl_from_for_primitive!(u16, U16);
impl_from_for_primitive!(i16, I16);
impl_from_for_primitive!(u32, U32);
impl_from_for_primitive!(i32, I32);
impl_from_for_primitive!(u64, U64);
impl_from_for_primitive!(i64, I64);
impl_from_for_primitive!(f32, F32);
impl_from_for_primitive!(f64, F64);
impl_from_for_primitive!(Tag, Tags);
impl_from_for_primitive!(NaiveDate, Date);
impl_from_for_primitive!(NaiveTime, Time);
impl_from_for_primitive!(DateTime<FixedOffset>, DateTime);
impl From<String> for PrimitiveValue {
fn from(value: String) -> Self {
PrimitiveValue::Str(value)
}
}
impl From<&str> for PrimitiveValue {
fn from(value: &str) -> Self {
PrimitiveValue::Str(value.to_owned())
}
}
impl From<Vec<u8>> for PrimitiveValue {
fn from(value: Vec<u8>) -> Self {
PrimitiveValue::U8(C::from(value))
}
}
impl From<&[u8]> for PrimitiveValue {
fn from(value: &[u8]) -> Self {
PrimitiveValue::U8(C::from(value))
}
}
macro_rules! impl_from_array_for_primitive {
($typ: ty, $variant: ident) => {
impl From<$typ> for PrimitiveValue {
fn from(value: $typ) -> Self {
PrimitiveValue::$variant(C::from_slice(&value[..]))
}
}
};
}
macro_rules! impl_from_array_for_primitive_1_to_8 {
($typ: ty, $variant: ident) => {
impl_from_array_for_primitive!([$typ; 1], $variant);
impl_from_array_for_primitive!([$typ; 2], $variant);
impl_from_array_for_primitive!([$typ; 3], $variant);
impl_from_array_for_primitive!([$typ; 4], $variant);
impl_from_array_for_primitive!([$typ; 5], $variant);
impl_from_array_for_primitive!([$typ; 6], $variant);
impl_from_array_for_primitive!([$typ; 7], $variant);
impl_from_array_for_primitive!([$typ; 8], $variant);
impl_from_array_for_primitive!(&[$typ; 1], $variant);
impl_from_array_for_primitive!(&[$typ; 2], $variant);
impl_from_array_for_primitive!(&[$typ; 3], $variant);
impl_from_array_for_primitive!(&[$typ; 4], $variant);
impl_from_array_for_primitive!(&[$typ; 5], $variant);
impl_from_array_for_primitive!(&[$typ; 6], $variant);
impl_from_array_for_primitive!(&[$typ; 7], $variant);
impl_from_array_for_primitive!(&[$typ; 8], $variant);
};
}
impl_from_array_for_primitive_1_to_8!(u8, U8);
impl_from_array_for_primitive_1_to_8!(u16, U16);
impl_from_array_for_primitive_1_to_8!(i16, I16);
impl_from_array_for_primitive_1_to_8!(u32, U32);
impl_from_array_for_primitive_1_to_8!(i32, I32);
impl_from_array_for_primitive_1_to_8!(u64, U64);
impl_from_array_for_primitive_1_to_8!(i64, I64);
impl_from_array_for_primitive_1_to_8!(f32, F32);
impl_from_array_for_primitive_1_to_8!(f64, F64);
impl_from_array_for_primitive_1_to_8!(NaiveDate, Date);
impl_from_array_for_primitive_1_to_8!(NaiveTime, Time);
impl_from_array_for_primitive_1_to_8!(DateTime<FixedOffset>, DateTime);
impl PrimitiveValue {
pub fn new_u16(value: u16) -> Self {
PrimitiveValue::U16(C::from_elem(value, 1))
}
pub fn new_u32(value: u32) -> Self {
PrimitiveValue::U32(C::from_elem(value, 1))
}
pub fn new_i32(value: u32) -> Self {
PrimitiveValue::U32(C::from_elem(value, 1))
}
pub fn multiplicity(&self) -> u32 {
use self::PrimitiveValue::*;
match self {
Empty => 0,
Str(_) => 1,
Strs(c) => c.len() as u32,
Tags(c) => c.len() as u32,
U8(c) => c.len() as u32,
I16(c) => c.len() as u32,
U16(c) => c.len() as u32,
I32(c) => c.len() as u32,
U32(c) => c.len() as u32,
I64(c) => c.len() as u32,
U64(c) => c.len() as u32,
F32(c) => c.len() as u32,
F64(c) => c.len() as u32,
Date(c) => c.len() as u32,
DateTime(c) => c.len() as u32,
Time(c) => c.len() as u32,
}
}
pub fn calculate_byte_len(&self) -> usize {
use self::PrimitiveValue::*;
match self {
Empty => 0,
U8(c) => c.len(),
I16(c) => c.len() * 2,
U16(c) => c.len() * 2,
U32(c) => c.len() * 4,
I32(c) => c.len() * 4,
U64(c) => c.len() * 8,
I64(c) => c.len() * 8,
F32(c) => c.len() * 4,
F64(c) => c.len() * 8,
Tags(c) => c.len() * 4,
Date(c) => (c.len() * 9) & !1,
Str(s) => s.as_bytes().len(),
Strs(c) => c.iter().map(|s| s.as_bytes().len() + 1).sum::<usize>() & !1,
Time(c) => {
c.iter()
.map(|t| PrimitiveValue::tm_byte_len(*t) + 1)
.sum::<usize>()
& !1
}
DateTime(c) => {
c.iter()
.map(|dt| PrimitiveValue::dt_byte_len(*dt) + 1)
.sum::<usize>()
& !1
}
}
}
fn tm_byte_len(time: NaiveTime) -> usize {
match (time.hour(), time.minute(), time.second(), time.nanosecond()) {
(_, 0, 0, 0) => 2,
(_, _, 0, 0) => 4,
(_, _, _, 0) => 6,
(_, _, _, nano) => {
let mut frac = nano / 1000;
let mut trailing_zeros = 0;
while frac % 10 == 0 {
frac /= 10;
trailing_zeros += 1;
}
7 + 6 - trailing_zeros
}
}
}
fn dt_byte_len(datetime: DateTime<FixedOffset>) -> usize {
8 + PrimitiveValue::tm_byte_len(datetime.time())
+ if datetime.offset() == &FixedOffset::east(0) {
0
} else {
5
}
}
pub fn to_str(&self) -> Cow<str> {
match self {
PrimitiveValue::Empty => Cow::from(""),
PrimitiveValue::Str(values) => Cow::from(values.as_str()),
PrimitiveValue::Strs(values) => {
if values.len() == 1 {
Cow::from(&values[0])
} else {
Cow::from(values.iter().join("\\"))
}
}
prim => Cow::from(prim.to_string()),
}
}
pub fn to_multi_str(&self) -> Cow<[String]> {
fn seq_to_str<I>(iter: I) -> Vec<String>
where
I: IntoIterator,
I::Item: std::fmt::Display,
{
iter.into_iter().map(|x| x.to_string()).collect()
}
match self {
PrimitiveValue::Empty => Cow::from(&[][..]),
PrimitiveValue::Str(values) => Cow::from(std::slice::from_ref(values)),
PrimitiveValue::Strs(values) => Cow::from(&values[..]),
PrimitiveValue::Date(values) => values
.into_iter()
.map(|date| date.format("%Y%m%d").to_string())
.collect::<Vec<_>>()
.into(),
PrimitiveValue::Time(values) => values
.into_iter()
.map(|date| date.format("%H%M%S%.6f").to_string())
.collect::<Vec<_>>()
.into(),
PrimitiveValue::DateTime(values) => values
.into_iter()
.map(|date| date.format("%Y%m%d%H%M%S%.6f%z").to_string())
.collect::<Vec<_>>()
.into(),
PrimitiveValue::U8(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::U16(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::U32(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::I16(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::I32(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::U64(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::I64(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::F32(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::F64(values) => Cow::Owned(seq_to_str(values)),
PrimitiveValue::Tags(values) => Cow::Owned(seq_to_str(values)),
}
}
pub fn to_clean_str(&self) -> Cow<str> {
match self {
PrimitiveValue::Str(values) => {
Cow::from(values.trim_end_matches(|c| c == ' ' || c == '\u{0}'))
}
PrimitiveValue::Strs(values) => {
if values.len() == 1 {
Cow::from(values[0].trim_end_matches(|c| c == ' ' || c == '\u{0}'))
} else {
Cow::Owned(
values
.iter()
.map(|s| s.trim_end_matches(|c| c == ' ' || c == '\u{0}'))
.join("\\"),
)
}
}
prim => Cow::from(prim.to_string()),
}
}
pub fn to_bytes(&self) -> Cow<[u8]> {
match self {
PrimitiveValue::Empty => Cow::from(&[][..]),
PrimitiveValue::U8(values) => Cow::from(&values[..]),
PrimitiveValue::U16(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::I16(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::U32(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::I32(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::I64(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::U64(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::F32(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::F64(values) => Cow::Borrowed(transmute_to_bytes(values)),
PrimitiveValue::Str(values) => Cow::from(values.as_bytes()),
PrimitiveValue::Strs(values) => {
if values.len() == 1 {
Cow::from(values[0].as_bytes())
} else {
Cow::from(values.iter().join("\\").into_bytes())
}
}
prim => match prim.to_str() {
Cow::Borrowed(string) => Cow::Borrowed(string.as_bytes()),
Cow::Owned(string) => Cow::Owned(string.into_bytes()),
},
}
}
pub fn to_int<T>(&self) -> Result<T, ConvertValueError>
where
T: NumCast,
T: FromStr<Err = std::num::ParseIntError>,
{
match self {
PrimitiveValue::Str(s) => {
s.trim_end()
.parse()
.context(ParseInteger)
.map_err(|err| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(err),
})
}
PrimitiveValue::Strs(s) if !s.is_empty() => s[0]
.trim_end()
.parse()
.context(ParseInteger)
.map_err(|err| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) if !bytes.is_empty() => {
T::from(bytes[0]).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: bytes[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U16(s) if !s.is_empty() => {
T::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I16(s) if !s.is_empty() => {
T::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U32(s) if !s.is_empty() => {
T::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I32(s) if !s.is_empty() => {
T::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U64(s) if !s.is_empty() => {
T::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I64(s) if !s.is_empty() => {
T::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
_ => Err(ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_int<T>(&self) -> Result<Vec<T>, ConvertValueError>
where
T: NumCast,
T: FromStr<Err = std::num::ParseIntError>,
{
match self {
PrimitiveValue::Empty => Ok(Vec::new()),
PrimitiveValue::Str(s) => {
let out = s.trim_end().parse().context(ParseInteger).map_err(|err| {
ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(err),
}
})?;
Ok(vec![out])
}
PrimitiveValue::Strs(s) => {
s.iter()
.map(|v| {
v.trim_end().parse().context(ParseInteger).map_err(|err| {
ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(err),
}
})
})
.collect::<Result<Vec<_>, _>>()
}
PrimitiveValue::U8(bytes) => bytes
.iter()
.map(|v| {
T::from(*v).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U16(s) => s
.iter()
.map(|v| {
T::from(*v).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I16(s) => s
.iter()
.map(|v| {
T::from(*v).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U32(s) => s
.iter()
.map(|v| {
T::from(*v).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I32(s) if !s.is_empty() => s
.iter()
.map(|v| {
T::from(*v).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U64(s) if !s.is_empty() => s
.iter()
.map(|v| {
T::from(*v).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I64(s) if !s.is_empty() => s
.iter()
.map(|v| {
T::from(*v).ok_or_else(|| ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
_ => Err(ConvertValueError {
requested: "integer",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_float32(&self) -> Result<f32, ConvertValueError> {
match self {
PrimitiveValue::Str(s) => {
s.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(err),
})
}
PrimitiveValue::Strs(s) if !s.is_empty() => s[0]
.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) if !bytes.is_empty() => {
NumCast::from(bytes[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: bytes[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U16(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I16(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U32(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I32(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U64(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I64(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::F32(s) if !s.is_empty() => Ok(s[0]),
PrimitiveValue::F64(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
_ => Err(ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_float32(&self) -> Result<Vec<f32>, ConvertValueError> {
match self {
PrimitiveValue::Empty => Ok(Vec::new()),
PrimitiveValue::Str(s) => {
let out =
s.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(err),
})?;
Ok(vec![out])
}
PrimitiveValue::Strs(s) => s
.iter()
.map(|v| {
v.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(err),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U8(bytes) => bytes
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U16(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I16(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U32(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I32(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U64(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I64(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::F32(s) => Ok(s[..].to_owned()),
PrimitiveValue::F64(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
_ => Err(ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_float64(&self) -> Result<f64, ConvertValueError> {
match self {
PrimitiveValue::Str(s) => {
s.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(err),
})
}
PrimitiveValue::Strs(s) if !s.is_empty() => s[0]
.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) if !bytes.is_empty() => {
NumCast::from(bytes[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: bytes[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U16(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I16(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U32(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I32(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::U64(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::I64(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::F32(s) if !s.is_empty() => {
NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: s[0].to_string(),
}
.build(),
),
})
}
PrimitiveValue::F64(s) if !s.is_empty() => Ok(s[0]),
_ => Err(ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_float64(&self) -> Result<Vec<f64>, ConvertValueError> {
match self {
PrimitiveValue::Str(s) => {
let out =
s.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(err),
})?;
Ok(vec![out])
}
PrimitiveValue::Strs(s) => s
.iter()
.map(|v| {
v.trim_end()
.parse()
.context(ParseFloat)
.map_err(|err| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(err),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U8(bytes) => bytes
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U16(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I16(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U32(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I32(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::U64(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::I64(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::F32(s) => s
.iter()
.map(|v| {
NumCast::from(*v).ok_or_else(|| ConvertValueError {
requested: "float64",
original: self.value_type(),
cause: Some(
NarrowConvert {
value: v.to_string(),
}
.build(),
),
})
})
.collect::<Result<Vec<_>, _>>(),
PrimitiveValue::F64(s) => Ok(s[..].to_owned()),
_ => Err(ConvertValueError {
requested: "float32",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_date(&self) -> Result<NaiveDate, ConvertValueError> {
match self {
PrimitiveValue::Date(v) if !v.is_empty() => Ok(v[0]),
PrimitiveValue::Str(s) => super::deserialize::parse_date(s.as_bytes())
.map(|(date, _rest)| date)
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::Strs(s) => {
super::deserialize::parse_date(s.first().map(|s| s.as_bytes()).unwrap_or(&[]))
.map(|(date, _rest)| date)
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: Some(err),
})
}
PrimitiveValue::U8(bytes) => super::deserialize::parse_date(bytes)
.map(|(date, _rest)| date)
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: Some(err),
}),
_ => Err(ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_date(&self) -> Result<Vec<NaiveDate>, ConvertValueError> {
match self {
PrimitiveValue::Date(v) if !v.is_empty() => Ok(v.to_vec()),
PrimitiveValue::Str(s) => super::deserialize::parse_date(s.trim_end().as_bytes())
.map(|(date, _rest)| vec![date])
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::Strs(s) => s
.into_iter()
.map(|s| {
super::deserialize::parse_date(s.trim_end().as_bytes())
.map(|(date, _rest)| date)
})
.collect::<Result<Vec<_>, _>>()
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
.split(|c| *c == b'\\')
.into_iter()
.map(|s| super::deserialize::parse_date(s).map(|(date, _rest)| date))
.collect::<Result<Vec<_>, _>>()
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: Some(err),
}),
_ => Err(ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_time(&self) -> Result<NaiveTime, ConvertValueError> {
match self {
PrimitiveValue::Time(v) if !v.is_empty() => Ok(v[0]),
PrimitiveValue::Str(s) => super::deserialize::parse_time(s.trim_end().as_bytes())
.map(|(date, _rest)| date)
.context(ParseTime)
.map_err(|err| ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::Strs(s) => super::deserialize::parse_time(
s.first().map(|s| s.trim_end().as_bytes()).unwrap_or(&[]),
)
.map(|(date, _rest)| date)
.context(ParseTime)
.map_err(|err| ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) => {
super::deserialize::parse_time(trim_last_whitespace(bytes))
.map(|(date, _rest)| date)
.context(ParseTime)
.map_err(|err| ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: Some(err),
})
}
_ => Err(ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_multi_time(&self) -> Result<Vec<NaiveTime>, ConvertValueError> {
match self {
PrimitiveValue::Time(v) if !v.is_empty() => Ok(v.to_vec()),
PrimitiveValue::Str(s) => super::deserialize::parse_time(s.trim_end().as_bytes())
.map(|(date, _rest)| vec![date])
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::Strs(s) => s
.into_iter()
.map(|s| {
super::deserialize::parse_time(s.trim_end().as_bytes())
.map(|(date, _rest)| date)
})
.collect::<Result<Vec<_>, _>>()
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
.split(|c| *c == b'\\')
.into_iter()
.map(|s| super::deserialize::parse_time(s).map(|(date, _rest)| date))
.collect::<Result<Vec<_>, _>>()
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: Some(err),
}),
_ => Err(ConvertValueError {
requested: "Time",
original: self.value_type(),
cause: None,
}),
}
}
pub fn to_datetime(
&self,
default_offset: FixedOffset,
) -> Result<DateTime<FixedOffset>, ConvertValueError> {
match self {
PrimitiveValue::DateTime(v) if !v.is_empty() => Ok(v[0]),
PrimitiveValue::Str(s) => {
super::deserialize::parse_datetime(s.trim_end().as_bytes(), default_offset)
.context(ParseDateTime)
.map_err(|err| ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: Some(err),
})
}
PrimitiveValue::Strs(s) => super::deserialize::parse_datetime(
s.first().map(|s| s.trim_end().as_bytes()).unwrap_or(&[]),
default_offset,
)
.context(ParseDateTime)
.map_err(|err| ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) => {
super::deserialize::parse_datetime(trim_last_whitespace(bytes), default_offset)
.context(ParseDateTime)
.map_err(|err| ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: Some(err),
})
}
_ => 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 {
PrimitiveValue::DateTime(v) if !v.is_empty() => Ok(v.to_vec()),
PrimitiveValue::Str(s) => {
super::deserialize::parse_datetime(s.trim_end().as_bytes(), default_offset)
.map(|date| vec![date])
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: Some(err),
})
}
PrimitiveValue::Strs(s) => s
.into_iter()
.map(|s| {
super::deserialize::parse_datetime(s.trim_end().as_bytes(), default_offset)
})
.collect::<Result<Vec<_>, _>>()
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: Some(err),
}),
PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
.split(|c| *c == b'\\')
.into_iter()
.map(|s| super::deserialize::parse_datetime(s, default_offset))
.collect::<Result<Vec<_>, _>>()
.context(ParseDate)
.map_err(|err| ConvertValueError {
requested: "DateTime",
original: self.value_type(),
cause: Some(err),
}),
_ => Err(ConvertValueError {
requested: "Date",
original: self.value_type(),
cause: None,
}),
}
}
}
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 {
PrimitiveValue::$variant(c) if c.is_empty() => Err(CastValueError {
requested: stringify!($name_single),
got: ValueType::Empty,
}),
PrimitiveValue::$variant(c) => Ok(c[0]),
value => Err(CastValueError {
requested: stringify!($name_single),
got: value.value_type(),
}),
}
}
pub fn $name_multi(&self) -> Result<&[$ret], CastValueError> {
match self {
PrimitiveValue::$variant(c) => Ok(&c),
value => Err(CastValueError {
requested: stringify!($name_multi),
got: value.value_type(),
}),
}
}
};
}
impl PrimitiveValue {
pub fn string(&self) -> Result<&str, CastValueError> {
use self::PrimitiveValue::*;
match self {
Strs(c) if c.is_empty() => Err(CastValueError {
requested: "Str",
got: ValueType::Empty,
}),
Strs(c) if !c.is_empty() => Ok(&c[0]),
Str(s) => Ok(s),
value => Err(CastValueError {
requested: "Str",
got: value.value_type(),
}),
}
}
pub fn strings(&self) -> Result<&[String], CastValueError> {
use self::PrimitiveValue::*;
match self {
Strs(c) => Ok(&c),
Str(s) => Ok(std::slice::from_ref(s)),
value => Err(CastValueError {
requested: "strings",
got: value.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 std::fmt::Display for PrimitiveValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
fn seq_to_str<I>(iter: I) -> String
where
I: IntoIterator,
I::Item: std::fmt::Display,
{
iter.into_iter().map(|x| x.to_string()).join("\\")
}
match self {
PrimitiveValue::Empty => Ok(()),
PrimitiveValue::Str(value) => f.write_str(value),
PrimitiveValue::Strs(values) => {
if values.len() == 1 {
f.write_str(&values[0])
} else {
f.write_str(&seq_to_str(values))
}
}
PrimitiveValue::Date(values) => f.write_str(
&values
.into_iter()
.map(|date| date.format("%Y%m%d").to_string())
.join("\\"),
),
PrimitiveValue::Time(values) => f.write_str(
&values
.into_iter()
.map(|date| date.format("%H%M%S%.6f").to_string())
.join("\\"),
),
PrimitiveValue::DateTime(values) => f.write_str(
&values
.into_iter()
.map(|date| date.format("%Y%m%d%H%M%S%.6f%z").to_string())
.join("\\"),
),
PrimitiveValue::U8(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::U16(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::U32(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::I16(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::I32(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::U64(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::I64(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::F32(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::F64(values) => f.write_str(&seq_to_str(values)),
PrimitiveValue::Tags(values) => f.write_str(&seq_to_str(values)),
}
}
}
impl HasLength for PrimitiveValue {
fn length(&self) -> Length {
Length::defined(self.calculate_byte_len() as u32)
}
}
impl PartialEq for PrimitiveValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(PrimitiveValue::Empty, PrimitiveValue::Empty) => true,
(PrimitiveValue::Strs(v1), PrimitiveValue::Str(v2)) => v1.len() == 1 && &v1[0] == v2,
(PrimitiveValue::Str(v1), PrimitiveValue::Strs(v2)) => v2.len() == 1 && v1 == &v2[0],
(PrimitiveValue::Strs(v1), PrimitiveValue::Strs(v2)) => v1 == v2,
(PrimitiveValue::Str(v1), PrimitiveValue::Str(v2)) => v1 == v2,
(PrimitiveValue::Tags(v1), PrimitiveValue::Tags(v2)) => v1 == v2,
(PrimitiveValue::U8(v1), PrimitiveValue::U8(v2)) => v1 == v2,
(PrimitiveValue::I16(v1), PrimitiveValue::I16(v2)) => v1 == v2,
(PrimitiveValue::U16(v1), PrimitiveValue::U16(v2)) => v1 == v2,
(PrimitiveValue::I32(v1), PrimitiveValue::I32(v2)) => v1 == v2,
(PrimitiveValue::U32(v1), PrimitiveValue::U32(v2)) => v1 == v2,
(PrimitiveValue::I64(v1), PrimitiveValue::I64(v2)) => v1 == v2,
(PrimitiveValue::U64(v1), PrimitiveValue::U64(v2)) => v1 == v2,
(PrimitiveValue::F32(v1), PrimitiveValue::F32(v2)) => v1 == v2,
(PrimitiveValue::F64(v1), PrimitiveValue::F64(v2)) => v1 == v2,
(PrimitiveValue::Date(v1), PrimitiveValue::Date(v2)) => v1 == v2,
(PrimitiveValue::DateTime(v1), PrimitiveValue::DateTime(v2)) => v1 == v2,
(PrimitiveValue::Time(v1), PrimitiveValue::Time(v2)) => v1 == v2,
_ => false,
}
}
}
impl PartialEq<str> for PrimitiveValue {
fn eq(&self, other: &str) -> bool {
match self {
PrimitiveValue::Strs(v) => v.len() == 1 && v[0] == other,
PrimitiveValue::Str(v) => v == other,
_ => false,
}
}
}
impl PartialEq<&str> for PrimitiveValue {
fn eq(&self, other: &&str) -> bool {
self.eq(*other)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ValueType {
Empty,
Item,
PixelSequence,
Strs,
Str,
Tags,
U8,
I16,
U16,
I32,
U32,
I64,
U64,
F32,
F64,
Date,
DateTime,
Time,
}
impl DicomValueType for PrimitiveValue {
fn value_type(&self) -> ValueType {
match *self {
PrimitiveValue::Empty => ValueType::Empty,
PrimitiveValue::Date(_) => ValueType::Date,
PrimitiveValue::DateTime(_) => ValueType::DateTime,
PrimitiveValue::F32(_) => ValueType::F32,
PrimitiveValue::F64(_) => ValueType::F64,
PrimitiveValue::I16(_) => ValueType::I16,
PrimitiveValue::I32(_) => ValueType::I32,
PrimitiveValue::I64(_) => ValueType::I64,
PrimitiveValue::Str(_) => ValueType::Str,
PrimitiveValue::Strs(_) => ValueType::Strs,
PrimitiveValue::Tags(_) => ValueType::Tags,
PrimitiveValue::Time(_) => ValueType::Time,
PrimitiveValue::U16(_) => ValueType::U16,
PrimitiveValue::U32(_) => ValueType::U32,
PrimitiveValue::U64(_) => ValueType::U64,
PrimitiveValue::U8(_) => ValueType::U8,
}
}
fn cardinality(&self) -> usize {
match self {
PrimitiveValue::Empty => 0,
PrimitiveValue::Str(_) => 1,
PrimitiveValue::Date(b) => b.len(),
PrimitiveValue::DateTime(b) => b.len(),
PrimitiveValue::F32(b) => b.len(),
PrimitiveValue::F64(b) => b.len(),
PrimitiveValue::I16(b) => b.len(),
PrimitiveValue::I32(b) => b.len(),
PrimitiveValue::I64(b) => b.len(),
PrimitiveValue::Strs(b) => b.len(),
PrimitiveValue::Tags(b) => b.len(),
PrimitiveValue::Time(b) => b.len(),
PrimitiveValue::U16(b) => b.len(),
PrimitiveValue::U32(b) => b.len(),
PrimitiveValue::U64(b) => b.len(),
PrimitiveValue::U8(b) => b.len(),
}
}
}
fn trim_last_whitespace(x: &[u8]) -> &[u8] {
match x.last() {
Some(b' ') | Some(b'\0') => &x[..x.len() - 1],
_ => x,
}
}
#[cfg(test)]
mod tests {
use super::{CastValueError, ConvertValueError, InvalidValueReadError};
use crate::dicom_value;
use crate::value::{PrimitiveValue, ValueType};
use chrono::{FixedOffset, NaiveDate, NaiveTime, TimeZone};
use smallvec::smallvec;
#[test]
fn primitive_value_to_str() {
assert_eq!(PrimitiveValue::Empty.to_str(), "");
let value = PrimitiveValue::Str("Smith^John".to_string());
let string = value.to_str();
assert_eq!(string, "Smith^John",);
match string {
std::borrow::Cow::Borrowed(_) => {}
_ => panic!("expected string to be borrowed, but was owned"),
}
assert_eq!(
PrimitiveValue::Date(smallvec![NaiveDate::from_ymd(2014, 10, 12)]).to_str(),
"20141012",
);
assert_eq!(
dicom_value!(Strs, ["DERIVED", "PRIMARY", "WHOLE BODY", "EMISSION"]).to_str(),
"DERIVED\\PRIMARY\\WHOLE BODY\\EMISSION",
);
let value = PrimitiveValue::from(vec![10, 11, 12]);
assert_eq!(value.to_str(), "10\\11\\12",);
}
#[test]
fn primitive_value_to_clean_str() {
let value = PrimitiveValue::from("1.2.345\0".to_string());
assert_eq!(&value.to_clean_str(), "1.2.345");
let value = dicom_value!(Strs, ["ONE", "TWO", "THREE", "SIX "]);
assert_eq!(&value.to_clean_str(), "ONE\\TWO\\THREE\\SIX");
let value = PrimitiveValue::from("\01.2.345\0".to_string());
assert_eq!(&value.to_clean_str(), "\01.2.345");
let value = dicom_value!(Strs, [" ONE", "TWO", "THREE", " SIX "]);
assert_eq!(&value.to_clean_str(), " ONE\\TWO\\THREE\\ SIX");
}
#[test]
fn primitive_value_to_bytes() {
assert_eq!(PrimitiveValue::Empty.to_bytes(), &[][..]);
if cfg!(target_endian = "little") {
assert_eq!(
PrimitiveValue::U16(smallvec![1, 2, 0x0601,]).to_bytes(),
&[0x01, 0x00, 0x02, 0x00, 0x01, 0x06][..],
);
} else {
assert_eq!(
PrimitiveValue::U16(smallvec![0x0001, 0x0002, 0x0601,]).to_bytes(),
&[0x00, 0x01, 0x00, 0x02, 0x06, 0x01][..],
);
}
let value = PrimitiveValue::from("Smith^John");
let bytes = value.to_bytes();
assert_eq!(bytes, &b"Smith^John"[..],);
match bytes {
std::borrow::Cow::Borrowed(_) => {}
_ => panic!("expected bytes to be borrowed, but are owned"),
}
assert_eq!(
PrimitiveValue::Date(smallvec![NaiveDate::from_ymd(2014, 10, 12)]).to_bytes(),
&b"20141012"[..],
);
assert_eq!(
dicom_value!(Strs, ["DERIVED", "PRIMARY", "WHOLE BODY", "EMISSION",]).to_bytes(),
&b"DERIVED\\PRIMARY\\WHOLE BODY\\EMISSION"[..],
);
let value = PrimitiveValue::from(vec![0x99; 16]);
let bytes = value.to_bytes();
assert_eq!(bytes, &[0x99; 16][..],);
match bytes {
std::borrow::Cow::Borrowed(_) => {}
_ => panic!("expected bytes to be borrowed, but are owned"),
}
}
#[test]
fn primitive_value_to_int() {
assert!(PrimitiveValue::Empty.to_int::<i32>().is_err());
assert_eq!(
PrimitiveValue::from(0x0601_u16).to_int().ok(),
Some(0x0601_u16),
);
assert_eq!(
PrimitiveValue::from(0x0601_u16).to_int().ok(),
Some(0x0601_u32),
);
assert_eq!(
PrimitiveValue::from(0x0601_u16).to_int().ok(),
Some(0x0601_i64),
);
assert_eq!(
PrimitiveValue::from(0x0601_u16).to_int().ok(),
Some(0x0601_u64),
);
assert_eq!(dicom_value!(I32, [1, 2, 5]).to_int().ok(), Some(1),);
assert_eq!(dicom_value!(Strs, ["-73", "2"]).to_int().ok(), Some(-73),);
assert!(PrimitiveValue::from(-1).to_int::<u32>().is_err());
assert!(matches!(
dicom_value!(Strs, ["Smith^John"]).to_int::<u8>(),
Err(ConvertValueError {
requested: _,
original: ValueType::Strs,
cause: Some(InvalidValueReadError::ParseInteger { .. }),
})
));
}
#[test]
fn primitive_value_to_multi_int() {
assert_eq!(PrimitiveValue::Empty.to_multi_int::<i32>().unwrap(), vec![]);
let test_value = dicom_value!(U16, [0x0601, 0x5353, 3, 4]);
let numbers = test_value.to_multi_int::<u16>().unwrap();
assert_eq!(numbers, vec![0x0601, 0x5353, 3, 4],);
let numbers: Vec<u32> = test_value.to_multi_int().unwrap();
assert_eq!(numbers, vec![0x0601_u32, 0x5353, 3, 4],);
let numbers: Vec<i64> = test_value.to_multi_int().unwrap();
assert_eq!(numbers, vec![0x0601_i64, 0x5353, 3, 4],);
assert_eq!(
test_value.to_multi_int::<u64>().unwrap(),
vec![0x0601_u64, 0x5353, 3, 4],
);
assert_eq!(
dicom_value!(I32, [1, 2, 5]).to_multi_int().ok(),
Some(vec![1, 2, 5]),
);
assert_eq!(
dicom_value!(Strs, ["-73", "2 "]).to_multi_int().ok(),
Some(vec![-73, 2]),
);
assert!(matches!(
dicom_value!(I32, [0, 1, -1]).to_multi_int::<u64>(),
Err(ConvertValueError {
original: ValueType::I32,
cause: Some(InvalidValueReadError::NarrowConvert {
value: x,
..
}),
..
}) if &x == "-1"
));
assert!(matches!(
dicom_value!(Strs, ["0", "1", "-1"]).to_multi_int::<u16>(),
Err(ConvertValueError {
original: ValueType::Strs,
cause: Some(InvalidValueReadError::ParseInteger { .. }),
..
})
));
assert!(matches!(
dicom_value!(Strs, ["Smith^John"]).to_int::<u8>(),
Err(ConvertValueError {
requested: _,
original: ValueType::Strs,
cause: Some(InvalidValueReadError::ParseInteger { .. }),
})
));
}
#[test]
fn primitive_value_to_multi_floats() {
assert_eq!(PrimitiveValue::Empty.to_multi_float32().ok(), Some(vec![]));
let test_value = dicom_value!(U16, [1, 2, 3, 4]);
assert_eq!(
test_value.to_multi_float32().ok(),
Some(vec![1., 2., 3., 4.]),
);
assert_eq!(
test_value.to_multi_float64().ok(),
Some(vec![1., 2., 3., 4.]),
);
assert_eq!(
dicom_value!(Strs, ["7.25", "-12.5 "])
.to_multi_float64()
.ok(),
Some(vec![7.25, -12.5]),
);
assert!(matches!(
dicom_value!(Strs, ["Smith^John"]).to_multi_float64(),
Err(ConvertValueError {
requested: _,
original: ValueType::Strs,
cause: Some(InvalidValueReadError::ParseFloat { .. }),
})
));
}
#[test]
fn primitive_value_to_date() {
assert_eq!(
PrimitiveValue::Date(smallvec![NaiveDate::from_ymd(2014, 10, 12)])
.to_date()
.unwrap(),
NaiveDate::from_ymd(2014, 10, 12),
);
assert_eq!(
dicom_value!(Str, "20141012").to_date().unwrap(),
NaiveDate::from_ymd(2014, 10, 12),
);
assert_eq!(
dicom_value!(Strs, ["20141012"]).to_date().unwrap(),
NaiveDate::from_ymd(2014, 10, 12),
);
assert_eq!(
PrimitiveValue::from(b"20141012").to_date().unwrap(),
NaiveDate::from_ymd(2014, 10, 12),
);
assert!(PrimitiveValue::Str("Smith^John".to_string())
.to_date()
.is_err());
assert!(matches!(
PrimitiveValue::Str("Smith^John".to_string()).to_date(),
Err(ConvertValueError {
requested: "Date",
original: ValueType::Str,
cause: Some(_),
})
));
}
#[test]
fn primitive_value_to_time() {
assert_eq!(
PrimitiveValue::from(NaiveTime::from_hms(11, 9, 26))
.to_time()
.unwrap(),
NaiveTime::from_hms(11, 9, 26),
);
assert_eq!(
dicom_value!(Str, "110926").to_time().unwrap(),
NaiveTime::from_hms(11, 9, 26),
);
assert_eq!(
PrimitiveValue::from(&"110926.38 "[..]).to_time().unwrap(),
NaiveTime::from_hms_milli(11, 9, 26, 380),
);
assert_eq!(
dicom_value!(Strs, ["110926"]).to_time().unwrap(),
NaiveTime::from_hms(11, 9, 26),
);
assert_eq!(
dicom_value!(Strs, ["110926.123456"]).to_time().unwrap(),
NaiveTime::from_hms_micro(11, 9, 26, 123_456),
);
assert_eq!(
PrimitiveValue::from(&b"110926.987"[..]).to_time().unwrap(),
NaiveTime::from_hms_milli(11, 9, 26, 987),
);
assert_eq!(
PrimitiveValue::from(&b"110926.38 "[..]).to_time().unwrap(),
NaiveTime::from_hms_milli(11, 9, 26, 380),
);
assert!(matches!(
PrimitiveValue::Str("Smith^John".to_string()).to_time(),
Err(ConvertValueError {
requested: "Time",
original: ValueType::Str,
..
})
));
}
#[test]
fn primitive_value_to_datetime() {
let this_datetime = FixedOffset::east(1).ymd(2012, 12, 21).and_hms(11, 9, 26);
let this_datetime_frac = FixedOffset::east(1)
.ymd(2012, 12, 21)
.and_hms_milli(11, 9, 26, 380);
assert_eq!(
PrimitiveValue::from(this_datetime)
.to_datetime(FixedOffset::east(1))
.unwrap(),
this_datetime,
);
assert_eq!(
dicom_value!(Str, "20121221110926")
.to_datetime(FixedOffset::east(1))
.unwrap(),
this_datetime,
);
assert_eq!(
PrimitiveValue::from("20121221110926.38 ")
.to_datetime(FixedOffset::east(1))
.unwrap(),
this_datetime_frac,
);
assert_eq!(
dicom_value!(Strs, ["20121221110926"])
.to_datetime(FixedOffset::east(1))
.unwrap(),
this_datetime,
);
assert_eq!(
dicom_value!(Strs, ["20121221110926.38 "])
.to_datetime(FixedOffset::east(1))
.unwrap(),
this_datetime_frac,
);
assert_eq!(
PrimitiveValue::from(&b"20121221110926.38 "[..])
.to_datetime(FixedOffset::east(1))
.unwrap(),
this_datetime_frac,
);
assert!(matches!(
PrimitiveValue::from("Smith^John").to_datetime(FixedOffset::east(1)),
Err(ConvertValueError {
requested: "DateTime",
original: ValueType::Str,
..
})
));
}
#[test]
fn calculate_byte_len() {
let val = dicom_value!("ABCD");
assert_eq!(val.calculate_byte_len(), 4);
let val = dicom_value!(Strs, ["ABCD", "EFG"]);
assert_eq!(val.calculate_byte_len(), 8);
let val = dicom_value!(Strs, ["ABCD", "EFGH"]);
assert_eq!(val.calculate_byte_len(), 10);
let val = dicom_value!(
Date,
[
NaiveDate::from_ymd(2014, 10, 12),
NaiveDate::from_ymd(2020, 9, 15),
NaiveDate::from_ymd(2018, 1, 1)
]
);
assert_eq!(val.calculate_byte_len(), 26);
let val = dicom_value!(
Date,
[
NaiveDate::from_ymd(2014, 10, 12),
NaiveDate::from_ymd(2020, 9, 15)
]
);
assert_eq!(val.calculate_byte_len(), 18);
let val = dicom_value!(NaiveTime::from_hms_micro(18, 55, 30, 475600));
assert_eq!(val.calculate_byte_len(), 12);
let val = dicom_value!(
Time,
[
NaiveTime::from_hms(18, 55, 30),
NaiveTime::from_hms(18, 55, 30)
]
);
assert_eq!(val.calculate_byte_len(), 14);
let val = PrimitiveValue::from(FixedOffset::east(1).ymd(2012, 12, 21).and_hms(9, 30, 1));
assert_eq!(val.calculate_byte_len(), 20);
}
#[test]
fn primitive_value_get() {
assert_eq!(
dicom_value!(Strs, ["Smith^John"]).string().unwrap(),
"Smith^John"
);
assert_eq!(
dicom_value!(Strs, ["Smith^John"]).strings().unwrap(),
&["Smith^John"]
);
assert_eq!(dicom_value!(I32, [1, 2, 5]).int32().unwrap(), 1,);
assert_eq!(
dicom_value!(I32, [1, 2, 5]).int32_slice().unwrap(),
&[1, 2, 5],
);
assert!(matches!(
dicom_value!(I32, [1, 2, 5]).uint32(),
Err(CastValueError {
requested: "uint32",
got: ValueType::I32,
..
})
));
assert!(matches!(
dicom_value!(I32, [1, 2, 5]).strings(),
Err(CastValueError {
requested: "strings",
got: ValueType::I32,
..
})
));
assert_eq!(
PrimitiveValue::Date(smallvec![NaiveDate::from_ymd(2014, 10, 12)])
.date()
.unwrap(),
NaiveDate::from_ymd(2014, 10, 12),
);
assert!(matches!(
PrimitiveValue::Date(smallvec![NaiveDate::from_ymd(2014, 10, 12)]).time(),
Err(CastValueError {
requested: "time",
got: ValueType::Date,
..
})
));
}
#[test]
fn eq_ignores_multi_variants() {
assert_eq!(dicom_value!(Str, "abc123"), dicom_value!(Strs, ["abc123"]),);
assert_eq!(dicom_value!(Str, "ABC123"), PrimitiveValue::from("ABC123"),);
assert_eq!(dicom_value!(Str, ""), PrimitiveValue::from(""),);
}
#[test]
fn eq_str() {
assert_eq!(PrimitiveValue::from("Doe^John"), "Doe^John");
assert_eq!(dicom_value!(Strs, ["Doe^John"]), "Doe^John");
assert_eq!(PrimitiveValue::from("Doe^John"), &*"Doe^John".to_owned());
assert_ne!(dicom_value!(Strs, ["Doe^John", "Silva^João"]), "Doe^John");
}
}