use std::str::FromStr;
use snafu::{ensure, Backtrace, OptionExt, ResultExt, Snafu};
use crate::{
ops::{AttributeSelector, AttributeSelectorStep},
Tag, VR,
};
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum TagRange {
Single(Tag),
Group100(Tag),
Element100(Tag),
GroupLength,
PrivateCreator,
}
impl TagRange {
pub fn inner(self) -> Tag {
match self {
TagRange::Single(tag) => tag,
TagRange::Group100(tag) => tag,
TagRange::Element100(tag) => tag,
TagRange::GroupLength => Tag(0x0000, 0x0000),
TagRange::PrivateCreator => Tag(0x0009, 0x0010),
}
}
}
#[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(MissingTagSnafu)?;
let elem = parts.next().context(MissingTagElementSnafu)?;
ensure!(
group.len() == 4,
InvalidGroupLengthSnafu { got: group.len() }
);
ensure!(
elem.len() == 4,
InvalidElementLengthSnafu { got: elem.len() }
);
match (&group.as_bytes()[2..], &elem.as_bytes()[2..]) {
(b"xx", b"xx") => UnsupportedTagRangeSnafu.fail(),
(b"xx", _) => {
let group =
u16::from_str_radix(&group[..2], 16).context(InvalidTagGroupSnafu)? << 8;
let elem = u16::from_str_radix(elem, 16).context(InvalidTagElementSnafu)?;
Ok(TagRange::Group100(Tag(group, elem)))
}
(_, b"xx") => {
let group = u16::from_str_radix(group, 16).context(InvalidTagGroupSnafu)?;
let elem =
u16::from_str_radix(&elem[..2], 16).context(InvalidTagElementSnafu)? << 8;
Ok(TagRange::Element100(Tag(group, elem)))
}
(_, _) => {
let group = u16::from_str_radix(group, 16).context(InvalidTagGroupSnafu)?;
let elem = u16::from_str_radix(elem, 16).context(InvalidTagElementSnafu)?;
Ok(TagRange::Single(Tag(group, elem)))
}
}
}
}
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum VirtualVr {
Exact(VR),
Xs,
Ox,
Px,
Lt,
}
impl From<VR> for VirtualVr {
fn from(value: VR) -> Self {
VirtualVr::Exact(value)
}
}
impl VirtualVr {
pub fn exact(self) -> Option<VR> {
match self {
VirtualVr::Exact(vr) => Some(vr),
_ => None,
}
}
pub fn relaxed(self) -> VR {
match self {
VirtualVr::Exact(vr) => vr,
VirtualVr::Xs => VR::US,
VirtualVr::Ox => VR::OW,
VirtualVr::Px => VR::OW,
VirtualVr::Lt => VR::OW,
}
}
}
#[derive(Debug, Snafu)]
pub struct ParseSelectorError(ParseSelectorErrorInner);
#[derive(Debug, Snafu)]
enum ParseSelectorErrorInner {
MissingItemDelimiter,
ParseKey,
ParseItemIndex,
ParseLeaf,
}
pub trait DataDictionary {
type Entry: DataDictionaryEntry;
fn by_tag(&self, tag: Tag) -> Option<&Self::Entry>;
fn by_name(&self, name: &str) -> Option<&Self::Entry>;
fn by_expr(&self, tag: &str) -> Option<&Self::Entry> {
match tag.parse() {
Ok(tag) => self.by_tag(tag),
Err(_) => self.by_name(tag),
}
}
fn parse_tag(&self, tag: &str) -> Option<Tag> {
tag.parse().ok().or_else(|| {
self.by_name(tag).map(|e| e.tag())
})
}
fn parse_selector(&self, selector_text: &str) -> Result<AttributeSelector, ParseSelectorError> {
let mut steps = crate::value::C::new();
for part in selector_text.split('.') {
if part.ends_with(']') {
let split_i = part.find('[').context(MissingItemDelimiterSnafu)?;
let tag_part = &part[0..split_i];
let item_index_part = &part[split_i + 1..part.len() - 1];
let tag: Tag = self.parse_tag(tag_part).context(ParseKeySnafu)?;
let item: u32 = item_index_part.parse().ok().context(ParseItemIndexSnafu)?;
steps.push(AttributeSelectorStep::Nested { tag, item });
} else {
let tag: Tag = self.parse_tag(part).context(ParseKeySnafu)?;
steps.push(AttributeSelectorStep::Tag(tag));
}
}
Ok(AttributeSelector::new(steps).context(ParseLeafSnafu)?)
}
}
pub trait DataDictionaryEntry {
fn tag_range(&self) -> TagRange;
fn tag(&self) -> Tag {
self.tag_range().inner()
}
fn alias(&self) -> &str;
fn vr(&self) -> VirtualVr;
}
#[derive(Debug, PartialEq, Clone)]
pub struct DataDictionaryEntryBuf {
pub tag: TagRange,
pub alias: String,
pub vr: VirtualVr,
}
impl DataDictionaryEntry for DataDictionaryEntryBuf {
fn tag_range(&self) -> TagRange {
self.tag
}
fn alias(&self) -> &str {
self.alias.as_str()
}
fn vr(&self) -> VirtualVr {
self.vr
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct DataDictionaryEntryRef<'a> {
pub tag: TagRange,
pub alias: &'a str,
pub vr: VirtualVr,
}
impl DataDictionaryEntry for DataDictionaryEntryRef<'_> {
fn tag_range(&self) -> TagRange {
self.tag
}
fn alias(&self) -> &str {
self.alias
}
fn vr(&self) -> VirtualVr {
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)));
}
}