Skip to content

Commit

Permalink
Merge pull request #326 from Enet4/new/core/attribute-ops
Browse files Browse the repository at this point in the history
Add attribute operations API
  • Loading branch information
Enet4 authored Apr 30, 2023
2 parents 9f729cd + a080f13 commit 30e69bf
Show file tree
Hide file tree
Showing 8 changed files with 1,315 additions and 17 deletions.
7 changes: 7 additions & 0 deletions core/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ impl<I, P> DataElement<I, P> {
pub fn into_value(self) -> Value<I, P> {
self.value
}

/// Split the constituent parts of this element into a tuple.
/// If the value is a sequence,
/// its lifetime may still be bound to the original source.
pub fn into_parts(self) -> (DataElementHeader, Value<I, P>) {
(self.header, self.value)
}
}

impl<I, P> DataElement<I, P>
Expand Down
9 changes: 4 additions & 5 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@
//! - [`dictionary`] describes common behavior of DICOM data dictionaries,
//! which translate attribute names and/or tags to a dictionary entry
//! containing relevant information about the attribute.
//! - [`ops`] provides constructs for defining
//! operations on DICOM attributes,
//! to be applied on types resembling DICOM objects or data sets.
//! - [`value`] holds definitions for values in standard DICOM elements,
//! with the awareness of multiplicity, representation,
//! and the possible presence of sequences.
//! - [`error`] contains crate-level error and result types.
//!
//! [`dictionary`]: ./dictionary/index.html
//! [`error`]: ./error/index.html
//! [`header`]: ./header/index.html
//! [`value`]: ./value/index.html
pub mod dictionary;
pub mod header;
pub mod ops;
pub mod value;

pub use dictionary::DataDictionary;
Expand Down
137 changes: 137 additions & 0 deletions core/src/ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//! Module for the attribute operations API.
//!
//! This allows consumers to specify and implement
//! operations on DICOM objects
//! as part of a larger process,
//! such as anonymization or transcoding.
//!
//! The most important type here is [`AttributeOp`],
//! which indicates which attribute is affected,
//! and the operation to apply ([`AttributeAction`]).
//! All DICOM object types supporting this API
//! implement the [`ApplyOp`] trait.
//!
//! # Example
//!
//! Given a DICOM object
//! (opened using [`dicom_object`](https://docs.rs/dicom-object)),
//! construct an [`AttributeOp`]
//! and apply it using [`apply`](ApplyOp::apply).
//!
//! ```no_run
//! use dicom_core::ops::*;
//! # /* do not really import this
//! use dicom_object::open_file;
//! # */
//!
//! # struct DicomObj;
//! # impl ApplyOp for DicomObj {
//! # type Err = snafu::Whatever;
//! # fn apply(&mut self, _: AttributeOp) -> Result<(), Self::Err> {
//! # panic!("this is just a stub");
//! # }
//! # }
//! # fn open_file(_: &str) -> Result<DicomObj, Box<dyn std::error::Error>> { Ok(DicomObj) }
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut obj = open_file("1/2/0003.dcm")?;
//! // hide patient name
//! obj.apply(AttributeOp {
//! tag: (0x0010, 0x0010).into(),
//! action: AttributeAction::ReplaceStr("Patient^Anonymous".into()),
//! })?;
//! # Ok(())
//! # }
//! ```
use std::borrow::Cow;

use crate::{Tag, PrimitiveValue, VR};

/// Descriptor for a single operation
/// to apply over a DICOM data set.
///
/// This type is purely descriptive.
/// It outlines a non-exhaustive set of possible changes around an attribute,
/// as well as set some expectations regarding the outcome of certain actions
/// against the attribute's previous state.
///
/// The operations themselves are provided
/// alongside DICOM objec or DICOM data set implementations.
///
/// Attribute operations can only select shallow attributes,
/// but the operation may be implemented when applied against nested data sets.
#[derive(Debug, Clone, PartialEq)]
pub struct AttributeOp {
/// the tag of the attribute to apply
pub tag: Tag,
/// the effective action to apply
pub action: AttributeAction,
}

/// Descriptor for the kind of action to apply over an attribute.
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum AttributeAction {
/// Remove the attribute if it exists.
Remove,
/// If the attribute exists, clear its value to zero bytes.
Empty,
/// If the attribute exists,
/// set or provide a hint about the attribute's value representation.
///
/// The underlying value is not modified.
/// Implementations are free to ignore this request if
/// it cannot be done or it does not make sense
/// for the given implementation.
SetVr(VR),
/// Fully replace the value with the given DICOM value,
/// creating the attribute if it does not exist yet.
Replace(PrimitiveValue),
/// Fully replace a textual value with the given string,
/// creating the attribute if it does not exist yet.
ReplaceStr(Cow<'static, str>),
/// Append a string as an additional textual value,
/// creating the attribute if it does not exist yet.
///
/// New value items are recorded as separate text values,
/// meaning that they are delimited by a backslash (`\`) at encoding time,
/// regardless of the value representation.
PushStr(Cow<'static, str>),
/// Append a 32-bit signed integer as an additional numeric value,
/// creating the attribute if it does not exist yet.
PushI32(i32),
/// Append a 32-bit unsigned integer as an additional numeric value,
/// creating the attribute if it does not exist yet.
PushU32(u32),
/// Append a 16-bit signed integer as an additional numeric value,
/// creating the attribute if it does not exist yet.
PushI16(i16),
/// Append a 16-bit unsigned integer as an additional numeric value,
/// creating the attribute if it does not exist yet.
PushU16(u16),
/// Append a 32-bit floating point number as an additional numeric value,
/// creating the attribute if it does not exist yet.
PushF32(f32),
/// Append a 64-bit floating point number as an additional numeric value,
/// creating the attribute if it does not exist yet.
PushF64(f64),
}

/// Trait for applying DICOM attribute operations.
///
/// This is typically implemented by DICOM objects and other data set types
/// to serve as a common API for attribute manipulation.
pub trait ApplyOp {
/// The operation error type
type Err: std::error::Error + 'static;

/// Apply the given attribute operation on the receiving object.
///
/// Effects may slightly differ between implementations,
/// but should always be compliant with
/// the expectations defined in [`AttributeAction`] variants.
///
/// If the action to apply is unsupported,
/// or not possible for other reasons,
/// an error is returned and no changes to the receiver are made.
fn apply(&mut self, op: AttributeOp) -> Result<(), Self::Err>;
}
Loading

0 comments on commit 30e69bf

Please sign in to comment.