use crate::error::CastValueError;
use crate::header::{Length, Tag};
use chrono::{DateTime, Datelike, FixedOffset, NaiveDate, NaiveTime, Timelike};
use itertools::Itertools;
use smallvec::SmallVec;
use std::borrow::Cow;
pub type C<T> = SmallVec<[T; 2]>;
#[derive(Debug, Clone, PartialEq)]
pub enum Value<I> {
Primitive(PrimitiveValue),
Sequence {
items: C<I>,
size: Length,
},
}
impl<I> Value<I>
where
I: DicomValueType,
{
pub fn multiplicity(&self) -> u32 {
match *self {
Value::Primitive(ref v) => v.multiplicity(),
Value::Sequence { ref items, .. } => items.len() as u32,
}
}
pub fn primitive(&self) -> Option<&PrimitiveValue> {
match *self {
Value::Primitive(ref v) => Some(v),
_ => None,
}
}
pub fn item(&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_item(self) -> Option<C<I>> {
match self {
Value::Sequence { items, .. } => Some(items),
_ => None,
}
}
pub fn to_str(&self) -> Result<Cow<str>, CastValueError> {
match self {
Value::Primitive(PrimitiveValue::Str(v)) => Ok(Cow::from(v.as_str())),
Value::Primitive(PrimitiveValue::Strs(v)) => Ok(Cow::from(v.into_iter().join("\\"))),
_ => Err(CastValueError {
requested: "string",
got: self.value_type(),
}),
}
}
pub fn as_u8(&self) -> Result<&[u8], CastValueError> {
match self {
Value::Primitive(PrimitiveValue::U8(v)) => Ok(&v),
_ => Err(CastValueError {
requested: "u8",
got: self.value_type(),
}),
}
}
pub fn as_i32(&self) -> Result<&[i32], CastValueError> {
match self {
Value::Primitive(PrimitiveValue::I32(v)) => Ok(&v),
_ => Err(CastValueError {
requested: "i32",
got: self.value_type(),
}),
}
}
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(),
}),
}
}
pub fn as_tags(&self) -> Result<&[Tag], CastValueError> {
match self {
Value::Primitive(PrimitiveValue::Tags(v)) => Ok(&v),
_ => Err(CastValueError {
requested: "tag",
got: self.value_type(),
}),
}
}
}
impl<I> From<PrimitiveValue> for Value<I> {
fn from(v: PrimitiveValue) -> Self {
Value::Primitive(v)
}
}
#[derive(Debug, PartialEq, 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>),
}
impl PrimitiveValue {
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 string(&self) -> Option<&str> {
use self::PrimitiveValue::*;
match self {
Strs(c) => c.first().map(String::as_str),
Str(s) => Some(s),
_ => None,
}
}
pub fn strings(&self) -> Option<Vec<&str>> {
use self::PrimitiveValue::*;
match self {
Strs(c) => Some(c.iter().map(String::as_str).collect()),
Str(s) => Some(vec![&s]),
_ => None,
}
}
pub fn tag(&self) -> Option<Tag> {
use self::PrimitiveValue::*;
match self {
Tags(c) => c.first().map(Clone::clone),
_ => None,
}
}
pub fn tags(&self) -> Option<&[Tag]> {
use self::PrimitiveValue::*;
match self {
Tags(c) => Some(&c),
_ => None,
}
}
pub fn int64(&self) -> Option<i64> {
use self::PrimitiveValue::*;
match self {
I64(c) => c.first().cloned(),
_ => None,
}
}
pub fn uint64(&self) -> Option<u64> {
use self::PrimitiveValue::*;
match self {
U64(c) => c.first().cloned(),
_ => None,
}
}
pub fn int32(&self) -> Option<i32> {
use self::PrimitiveValue::*;
match self {
I32(c) => c.first().cloned(),
_ => None,
}
}
pub fn uint32(&self) -> Option<u32> {
use self::PrimitiveValue::*;
match self {
U32(ref c) => c.first().cloned(),
_ => None,
}
}
pub fn int16(&self) -> Option<i16> {
use self::PrimitiveValue::*;
match self {
I16(ref c) => c.first().cloned(),
_ => None,
}
}
pub fn uint16(&self) -> Option<u16> {
use self::PrimitiveValue::*;
match self {
U16(c) => c.first().cloned(),
_ => None,
}
}
pub fn uint8(&self) -> Option<u8> {
use self::PrimitiveValue::*;
match self {
U8(c) => c.first().cloned(),
_ => None,
}
}
pub fn float32(&self) -> Option<f32> {
use self::PrimitiveValue::*;
match self {
F32(c) => c.first().cloned(),
_ => None,
}
}
pub fn float64(&self) -> Option<f64> {
use self::PrimitiveValue::*;
match self {
F64(c) => c.first().cloned(),
_ => None,
}
}
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() * 8,
Str(s) => s.as_bytes().len(),
Strs(c) if c.is_empty() => 0,
Strs(c) => {
c.iter()
.map(|s| ((s.as_bytes().len() + 1) & !1) + 1)
.sum::<usize>()
- 1
}
Time(c) if c.is_empty() => 0,
Time(c) => {
c.iter()
.map(|t| ((PrimitiveValue::tm_byte_len(*t) + 1) & !1) + 1)
.sum::<usize>()
- 1
}
DateTime(c) if c.is_empty() => 0,
DateTime(c) => {
c.iter()
.map(|dt| ((PrimitiveValue::dt_byte_len(*dt) + 1) & !1) + 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 {
(match (datetime.month(), datetime.day()) {
(1, 1) => 0,
(_, 1) => 2,
_ => 4,
}) + 8
+ PrimitiveValue::tm_byte_len(datetime.time())
+ if datetime.offset() == &FixedOffset::east(0) {
0
} else {
5
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ValueType {
Empty,
Item,
Strs,
Str,
Tags,
U8,
I16,
U16,
I32,
U32,
I64,
U64,
F32,
F64,
Date,
DateTime,
Time,
}
pub trait DicomValueType {
fn value_type(&self) -> ValueType;
fn size(&self) -> Length;
fn is_empty(&self) -> bool {
self.size() == Length(0)
}
}
impl DicomValueType for PrimitiveValue {
fn value_type(&self) -> ValueType {
use self::PrimitiveValue::*;
match *self {
Empty => ValueType::Empty,
Date(_) => ValueType::Date,
DateTime(_) => ValueType::DateTime,
F32(_) => ValueType::F32,
F64(_) => ValueType::F64,
I16(_) => ValueType::I16,
I32(_) => ValueType::I32,
I64(_) => ValueType::I64,
Str(_) => ValueType::Str,
Strs(_) => ValueType::Strs,
Tags(_) => ValueType::Tags,
Time(_) => ValueType::Time,
U16(_) => ValueType::U16,
U32(_) => ValueType::U32,
U64(_) => ValueType::U64,
U8(_) => ValueType::U8,
}
}
fn size(&self) -> Length {
use self::PrimitiveValue::*;
Length::defined(match self {
Empty => 0,
Str(_) => 1,
Date(b) => b.len() as u32,
DateTime(b) => b.len() as u32,
F32(b) => b.len() as u32,
F64(b) => b.len() as u32,
I16(b) => b.len() as u32,
I32(b) => b.len() as u32,
I64(b) => b.len() as u32,
Strs(b) => b.len() as u32,
Tags(b) => b.len() as u32,
Time(b) => b.len() as u32,
U16(b) => b.len() as u32,
U32(b) => b.len() as u32,
U64(b) => b.len() as u32,
U8(b) => b.len() as u32,
})
}
}
impl<I> DicomValueType for Value<I>
where
I: DicomValueType,
{
fn value_type(&self) -> ValueType {
match *self {
Value::Primitive(ref v) => v.value_type(),
Value::Sequence { .. } => ValueType::Item,
}
}
fn size(&self) -> Length {
match *self {
Value::Primitive(ref v) => v.size(),
Value::Sequence { size, .. } => size,
}
}
}