pub mod stub;
use crate::header::{Tag, VR};
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, Default, Copy, Clone, Eq, PartialEq)]
pub struct TagRangeParseError(&'static str);
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().ok_or(TagRangeParseError(
"not enough tag components, expected `group,element`",
))?;
let elem = parts.next().ok_or(TagRangeParseError(
"not enough tag components, expected `element`",
))?;
if group.len() != 4 {
return Err(TagRangeParseError(
"tag component `group` has an invalid length, must be 4",
));
}
if elem.len() != 4 {
return Err(TagRangeParseError(
"tag component `element` has an invalid length, must be 4",
));
}
match (&group.as_bytes()[2..], &elem.as_bytes()[2..]) {
(b"xx", b"xx") => Err(TagRangeParseError("unsupported tag range")),
(b"xx", _) => {
let group = u16::from_str_radix(&group[..2], 16)
.map_err(|_e| TagRangeParseError("Invalid component `group`"))?
<< 8;
let elem = u16::from_str_radix(elem, 16)
.map_err(|_e| TagRangeParseError("Invalid component `element`"))?;
Ok(TagRange::Group100(Tag(group, elem)))
}
(_, b"xx") => {
let group = u16::from_str_radix(group, 16)
.map_err(|_e| TagRangeParseError("Invalid component `group`"))?;
let elem = u16::from_str_radix(&elem[..2], 16)
.map_err(|_e| TagRangeParseError("Invalid component `element`"))?
<< 8;
Ok(TagRange::Element100(Tag(group, elem)))
}
(_, _) => {
let group = u16::from_str_radix(group, 16)
.map_err(|_e| TagRangeParseError("Invalid component `group`"))?;
let elem = u16::from_str_radix(elem, 16)
.map_err(|_e| TagRangeParseError("Invalid component `element`"))?;
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)));
}
}