pub mod stub;
use crate::header::{Tag, VR};
use snafu::{ensure, Backtrace, OptionExt, ResultExt, Snafu};
use std::fmt::Debug;
use std::str::FromStr;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum TagRange {
Single(Tag),
Group100(Tag),
Element100(Tag),
}
impl TagRange {
pub fn inner(self) -> Tag {
match self {
TagRange::Single(tag) => tag,
TagRange::Group100(tag) => tag,
TagRange::Element100(tag) => tag,
}
}
}
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum TagRangeParseError {
#[snafu(display("Not enough tag components, expected tag (group, element)"))]
MissingTag { backtrace: Backtrace },
#[snafu(display("Not enough tag components, expected tag element"))]
MissingTagElement { backtrace: Backtrace },
#[snafu(display(
"tag component `group` has an invalid length: got {} but must be 4",
got
))]
InvalidGroupLength { got: usize, backtrace: Backtrace },
#[snafu(display(
"tag component `element` has an invalid length: got {} but must be 4",
got
))]
InvalidElementLength { got: usize, backtrace: Backtrace },
#[snafu(display("unsupported tag range"))]
UnsupportedTagRange { backtrace: Backtrace },
#[snafu(display("invalid tag component `group`"))]
InvalidTagGroup {
backtrace: Backtrace,
source: std::num::ParseIntError,
},
#[snafu(display("invalid tag component `element`"))]
InvalidTagElement {
backtrace: Backtrace,
source: std::num::ParseIntError,
},
}
impl FromStr for TagRange {
type Err = TagRangeParseError;
fn from_str(mut s: &str) -> Result<Self, Self::Err> {
if s.starts_with('(') && s.ends_with(')') {
s = &s[1..s.len() - 1];
}
let mut parts = s.split(',');
let group = parts.next().context(MissingTag)?;
let elem = parts.next().context(MissingTagElement)?;
ensure!(group.len() == 4, InvalidGroupLength { got: group.len() });
ensure!(elem.len() == 4, InvalidElementLength { got: elem.len() });
match (&group.as_bytes()[2..], &elem.as_bytes()[2..]) {
(b"xx", b"xx") => UnsupportedTagRange.fail(),
(b"xx", _) => {
let group = u16::from_str_radix(&group[..2], 16).context(InvalidTagGroup)? << 8;
let elem = u16::from_str_radix(elem, 16).context(InvalidTagElement)?;
Ok(TagRange::Group100(Tag(group, elem)))
}
(_, b"xx") => {
let group = u16::from_str_radix(group, 16).context(InvalidTagGroup)?;
let elem = u16::from_str_radix(&elem[..2], 16).context(InvalidTagElement)? << 8;
Ok(TagRange::Element100(Tag(group, elem)))
}
(_, _) => {
let group = u16::from_str_radix(group, 16).context(InvalidTagGroup)?;
let elem = u16::from_str_radix(elem, 16).context(InvalidTagElement)?;
Ok(TagRange::Single(Tag(group, elem)))
}
}
}
}
pub trait DataDictionary: Debug {
type Entry: DictionaryEntry;
fn by_name(&self, name: &str) -> Option<&Self::Entry>;
fn by_tag(&self, tag: Tag) -> Option<&Self::Entry>;
}
pub trait DictionaryEntry {
fn tag_range(&self) -> TagRange;
fn tag(&self) -> Tag {
match self.tag_range() {
TagRange::Single(tag) => tag,
TagRange::Group100(tag) => tag,
TagRange::Element100(tag) => tag,
}
}
fn alias(&self) -> &str;
fn vr(&self) -> VR;
}
#[derive(Debug, PartialEq, Clone)]
pub struct DictionaryEntryBuf {
pub tag: TagRange,
pub alias: String,
pub vr: VR,
}
impl DictionaryEntry for DictionaryEntryBuf {
fn tag_range(&self) -> TagRange {
self.tag
}
fn alias(&self) -> &str {
self.alias.as_str()
}
fn vr(&self) -> VR {
self.vr
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct DictionaryEntryRef<'a> {
pub tag: TagRange,
pub alias: &'a str,
pub vr: VR,
}
impl<'a> DictionaryEntry for DictionaryEntryRef<'a> {
fn tag_range(&self) -> TagRange {
self.tag
}
fn alias(&self) -> &str {
self.alias
}
fn vr(&self) -> VR {
self.vr
}
}
#[derive(Debug, Clone)]
pub struct TagByName<N, D> {
dict: D,
name: N,
}
impl<N, D> TagByName<N, D>
where
N: AsRef<str>,
D: DataDictionary,
{
pub fn new(dictionary: D, name: N) -> TagByName<N, D> {
TagByName {
dict: dictionary,
name,
}
}
}
impl<N, D> From<TagByName<N, D>> for Option<Tag>
where
N: AsRef<str>,
D: DataDictionary,
{
fn from(tag: TagByName<N, D>) -> Option<Tag> {
tag.dict.by_name(tag.name.as_ref()).map(|e| e.tag())
}
}
#[cfg(test)]
mod tests {
use super::TagRange;
use crate::header::Tag;
#[test]
fn test_parse_tag_range() {
let tag: TagRange = "(1234,5678)".parse().unwrap();
assert_eq!(tag, TagRange::Single(Tag(0x1234, 0x5678)));
let tag: TagRange = "1234,5678".parse().unwrap();
assert_eq!(tag, TagRange::Single(Tag(0x1234, 0x5678)));
let tag: TagRange = "12xx,5678".parse().unwrap();
assert_eq!(tag, TagRange::Group100(Tag(0x1200, 0x5678)));
let tag: TagRange = "1234,56xx".parse().unwrap();
assert_eq!(tag, TagRange::Element100(Tag(0x1234, 0x5600)));
}
}