use crate::error::{Error, Result};
use crate::value::{DicomValueType, PrimitiveValue, Value};
use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt;
use std::str::{from_utf8, FromStr};
#[allow(clippy::len_without_is_empty)]
pub trait Header {
fn tag(&self) -> Tag;
fn len(&self) -> Length;
fn is_item(&self) -> bool {
self.tag() == Tag(0xFFFE, 0xE000)
}
fn is_item_delimiter(&self) -> bool {
self.tag() == Tag(0xFFFE, 0xE00D)
}
fn is_sequence_delimiter(&self) -> bool {
self.tag() == Tag(0xFFFE, 0xE0DD)
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct DataElement<I> {
header: DataElementHeader,
value: Value<I>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct PrimitiveDataElement {
header: DataElementHeader,
value: PrimitiveValue,
}
impl PrimitiveDataElement {
pub fn new(header: DataElementHeader, value: PrimitiveValue) -> Self {
PrimitiveDataElement { header, value }
}
}
impl<I> From<PrimitiveDataElement> for DataElement<I> {
fn from(o: PrimitiveDataElement) -> Self {
DataElement {
header: o.header,
value: o.value.into(),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct DataElementRef<'v, I: 'v> {
header: DataElementHeader,
value: &'v Value<I>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct PrimitiveDataElementRef<'v> {
header: DataElementHeader,
value: &'v PrimitiveValue,
}
impl<'a> PrimitiveDataElementRef<'a> {
pub fn new(header: DataElementHeader, value: &'a PrimitiveValue) -> Self {
PrimitiveDataElementRef { header, value }
}
}
impl<I> Header for DataElement<I> {
#[inline]
fn tag(&self) -> Tag {
self.header.tag()
}
#[inline]
fn len(&self) -> Length {
self.header.len()
}
}
impl<'a, I> Header for &'a DataElement<I> {
#[inline]
fn tag(&self) -> Tag {
(**self).tag()
}
#[inline]
fn len(&self) -> Length {
(**self).len()
}
}
impl<'v, I> Header for DataElementRef<'v, I> {
#[inline]
fn tag(&self) -> Tag {
self.header.tag()
}
#[inline]
fn len(&self) -> Length {
self.header.len()
}
}
impl<I> DataElement<I>
where
I: DicomValueType,
{
pub fn empty(tag: Tag, vr: VR) -> Self {
DataElement {
header: DataElementHeader {
tag,
vr,
len: Length(0),
},
value: PrimitiveValue::Empty.into(),
}
}
pub fn new(tag: Tag, vr: VR, value: Value<I>) -> Self {
DataElement {
header: DataElementHeader {
tag,
vr,
len: value.size(),
},
value,
}
}
pub fn header(&self) -> &DataElementHeader {
&self.header
}
pub fn value(&self) -> &Value<I> {
&self.value
}
pub fn vr(&self) -> VR {
self.header.vr()
}
pub fn to_str(&self) -> Result<Cow<str>> {
self.value.to_str().map_err(From::from)
}
}
impl<'v, I> DataElementRef<'v, I>
where
I: DicomValueType,
{
pub fn new(tag: Tag, vr: VR, value: &'v Value<I>) -> Self {
DataElementRef {
header: DataElementHeader {
tag,
vr,
len: value.size(),
},
value,
}
}
pub fn vr(&self) -> VR {
self.header.vr()
}
pub fn value(&self) -> &Value<I> {
&self.value
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct DataElementHeader {
pub tag: Tag,
pub vr: VR,
pub len: Length,
}
impl Header for DataElementHeader {
fn tag(&self) -> Tag {
self.tag
}
fn len(&self) -> Length {
self.len
}
}
impl DataElementHeader {
pub fn new<T: Into<Tag>>(tag: T, vr: VR, len: Length) -> DataElementHeader {
DataElementHeader {
tag: tag.into(),
vr,
len,
}
}
pub fn vr(&self) -> VR {
self.vr
}
}
impl From<SequenceItemHeader> for DataElementHeader {
fn from(value: SequenceItemHeader) -> DataElementHeader {
DataElementHeader {
tag: value.tag(),
vr: VR::UN,
len: value.len(),
}
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SequenceItemHeader {
Item {
len: Length,
},
ItemDelimiter,
SequenceDelimiter,
}
impl SequenceItemHeader {
pub fn new<T: Into<Tag>>(tag: T, len: Length) -> Result<SequenceItemHeader> {
match tag.into() {
Tag(0xFFFE, 0xE000) => {
Ok(SequenceItemHeader::Item { len })
}
Tag(0xFFFE, 0xE00D) => {
if len != Length(0) {
Err(Error::UnexpectedDataValueLength)
} else {
Ok(SequenceItemHeader::ItemDelimiter)
}
}
Tag(0xFFFE, 0xE0DD) => {
Ok(SequenceItemHeader::SequenceDelimiter)
}
_ => Err(Error::UnexpectedElement),
}
}
}
impl Header for SequenceItemHeader {
fn tag(&self) -> Tag {
match *self {
SequenceItemHeader::Item { .. } => Tag(0xFFFE, 0xE000),
SequenceItemHeader::ItemDelimiter => Tag(0xFFFE, 0xE00D),
SequenceItemHeader::SequenceDelimiter => Tag(0xFFFE, 0xE0DD),
}
}
fn len(&self) -> Length {
match *self {
SequenceItemHeader::Item { len } => len,
SequenceItemHeader::ItemDelimiter | SequenceItemHeader::SequenceDelimiter => Length(0),
}
}
}
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, Ord, PartialOrd)]
pub enum VR {
AE,
AS,
AT,
CS,
DA,
DS,
DT,
FL,
FD,
IS,
LO,
LT,
OB,
OD,
OF,
OL,
OV,
OW,
PN,
SH,
SL,
SQ,
SS,
ST,
SV,
TM,
UC,
UI,
UL,
UN,
UR,
US,
UT,
UV,
}
impl VR {
pub fn from_binary(chars: [u8; 2]) -> Option<Self> {
from_utf8(chars.as_ref())
.ok()
.and_then(|s| VR::from_str(s).ok())
}
pub fn to_string(self) -> &'static str {
use VR::*;
match self {
AE => "AE",
AS => "AS",
AT => "AT",
CS => "CS",
DA => "DA",
DS => "DS",
DT => "DT",
FL => "FL",
FD => "FD",
IS => "IS",
LO => "LO",
LT => "LT",
OB => "OB",
OD => "OD",
OF => "OF",
OL => "OL",
OV => "OV",
OW => "OW",
PN => "PN",
SH => "SH",
SL => "SL",
SQ => "SQ",
SS => "SS",
ST => "ST",
SV => "SV",
TM => "TM",
UC => "UC",
UI => "UI",
UL => "UL",
UN => "UN",
UR => "UR",
US => "US",
UT => "UT",
UV => "UV",
}
}
pub fn to_bytes(self) -> [u8; 2] {
let bytes = self.to_string().as_bytes();
[bytes[0], bytes[1]]
}
}
impl FromStr for VR {
type Err = &'static str;
fn from_str(string: &str) -> std::result::Result<Self, Self::Err> {
use VR::*;
match string {
"AE" => Ok(AE),
"AS" => Ok(AS),
"AT" => Ok(AT),
"CS" => Ok(CS),
"DA" => Ok(DA),
"DS" => Ok(DS),
"DT" => Ok(DT),
"FL" => Ok(FL),
"FD" => Ok(FD),
"IS" => Ok(IS),
"LO" => Ok(LO),
"LT" => Ok(LT),
"OB" => Ok(OB),
"OD" => Ok(OD),
"OF" => Ok(OF),
"OL" => Ok(OL),
"OV" => Ok(OV),
"OW" => Ok(OW),
"PN" => Ok(PN),
"SH" => Ok(SH),
"SL" => Ok(SL),
"SQ" => Ok(SQ),
"SS" => Ok(SS),
"ST" => Ok(ST),
"SV" => Ok(SV),
"TM" => Ok(TM),
"UC" => Ok(UC),
"UI" => Ok(UI),
"UL" => Ok(UL),
"UN" => Ok(UN),
"UR" => Ok(UR),
"US" => Ok(US),
"UT" => Ok(UT),
"UV" => Ok(UV),
_ => Err("no such value representation"),
}
}
}
impl fmt::Display for VR {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(VR::to_string(*self))
}
}
pub type GroupNumber = u16;
pub type ElementNumber = u16;
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
pub struct Tag(pub GroupNumber, pub ElementNumber);
impl Tag {
#[inline]
pub fn group(self) -> GroupNumber {
self.0
}
#[inline]
pub fn element(self) -> ElementNumber {
self.1
}
}
impl fmt::Debug for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Tag({:#06X?}, {:#06X?})", self.0, self.1)
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:04X},{:04X})", self.0, self.1)
}
}
impl PartialEq<(u16, u16)> for Tag {
fn eq(&self, other: &(u16, u16)) -> bool {
self.0 == other.0 && self.1 == other.1
}
}
impl PartialEq<[u16; 2]> for Tag {
fn eq(&self, other: &[u16; 2]) -> bool {
self.0 == other[0] && self.1 == other[1]
}
}
impl From<(u16, u16)> for Tag {
#[inline]
fn from(value: (u16, u16)) -> Tag {
Tag(value.0, value.1)
}
}
impl From<[u16; 2]> for Tag {
#[inline]
fn from(value: [u16; 2]) -> Tag {
Tag(value[0], value[1])
}
}
#[derive(Clone, Copy)]
pub struct Length(pub u32);
const UNDEFINED_LEN: u32 = 0xFFFF_FFFF;
impl Length {
pub const UNDEFINED: Self = Length(UNDEFINED_LEN);
pub fn new(len: u32) -> Self {
Length(len)
}
pub fn defined(len: u32) -> Self {
assert_ne!(len, UNDEFINED_LEN);
Length(len)
}
}
impl From<u32> for Length {
fn from(o: u32) -> Self {
Length(o)
}
}
impl PartialEq<Length> for Length {
fn eq(&self, rhs: &Length) -> bool {
match (self.0, rhs.0) {
(UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => false,
(l1, l2) => l1 == l2,
}
}
}
impl PartialOrd<Length> for Length {
fn partial_cmp(&self, rhs: &Length) -> Option<Ordering> {
match (self.0, rhs.0) {
(UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => None,
(l1, l2) => Some(l1.cmp(&l2)),
}
}
}
impl ::std::ops::Add<Length> for Length {
type Output = Self;
fn add(self, rhs: Length) -> Self::Output {
match (self.0, rhs.0) {
(UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => Length::UNDEFINED,
(l1, l2) => {
let o = l1 + l2;
debug_assert!(
o != UNDEFINED_LEN,
"integer overflow (0xFFFF_FFFF reserved for undefined length)"
);
Length(o)
}
}
}
}
impl ::std::ops::Add<i32> for Length {
type Output = Self;
fn add(self, rhs: i32) -> Self::Output {
match self.0 {
UNDEFINED_LEN => Length::UNDEFINED,
len => {
let o = (len as i32 + rhs) as u32;
debug_assert!(
o != UNDEFINED_LEN,
"integer overflow (0xFFFF_FFFF reserved for undefined length)"
);
Length(o)
}
}
}
}
impl ::std::ops::Sub<Length> for Length {
type Output = Self;
fn sub(self, rhs: Length) -> Self::Output {
match (self.0, rhs.0) {
(UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => Length::UNDEFINED,
(l1, l2) => {
let o = l1 - l2;
debug_assert!(
o != UNDEFINED_LEN,
"integer overflow (0xFFFF_FFFF reserved for undefined length)"
);
Length(o)
}
}
}
}
impl ::std::ops::Sub<i32> for Length {
type Output = Self;
fn sub(self, rhs: i32) -> Self::Output {
match self.0 {
UNDEFINED_LEN => Length::UNDEFINED,
len => {
let o = (len as i32 - rhs) as u32;
debug_assert!(
o != UNDEFINED_LEN,
"integer overflow (0xFFFF_FFFF reserved for undefined length)"
);
Length(o)
}
}
}
}
impl Length {
#[inline]
pub fn is_undefined(self) -> bool {
self.0 == UNDEFINED_LEN
}
#[inline]
pub fn is_defined(self) -> bool {
!self.is_undefined()
}
#[inline]
pub fn get(self) -> Option<u32> {
match self.0 {
UNDEFINED_LEN => None,
v => Some(v),
}
}
}
impl fmt::Debug for Length {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
UNDEFINED_LEN => f.write_str("Length(Undefined)"),
l => f.debug_tuple("Length").field(&l).finish(),
}
}
}
impl fmt::Display for Length {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
UNDEFINED_LEN => f.write_str("U/L"),
l => write!(f, "{}", &l),
}
}
}
#[cfg(test)]
mod tests {
use super::Tag;
#[test]
fn tag_from_u16_pair() {
let t = Tag::from((0x0010u16, 0x0020u16));
assert_eq!(0x0010u16, t.group());
assert_eq!(0x0020u16, t.element());
}
#[test]
fn tag_from_u16_array() {
let t = Tag::from([0x0010u16, 0x0020u16]);
assert_eq!(0x0010u16, t.group());
assert_eq!(0x0020u16, t.element());
}
}