use crate::adapters::{
DynPixelDataReader, DynPixelDataWriter, NeverPixelAdapter, PixelDataReader, PixelDataWriter,
};
use crate::decode::{
basic::BasicDecoder, explicit_be::ExplicitVRBigEndianDecoder,
explicit_le::ExplicitVRLittleEndianDecoder, implicit_le::ImplicitVRLittleEndianDecoder,
DecodeFrom,
};
use crate::encode::{
explicit_be::ExplicitVRBigEndianEncoder, explicit_le::ExplicitVRLittleEndianEncoder,
implicit_le::ImplicitVRLittleEndianEncoder, EncodeTo, EncoderFor,
};
use std::io::{Read, Write};
pub use byteordered::Endianness;
pub type DynDecoder<S> = Box<dyn DecodeFrom<S>>;
pub type DynEncoder<'w, W> = Box<dyn EncodeTo<W> + 'w>;
#[derive(Debug)]
pub struct TransferSyntax<D = DynDataRWAdapter, R = DynPixelDataReader, W = DynPixelDataWriter> {
uid: &'static str,
name: &'static str,
byte_order: Endianness,
explicit_vr: bool,
codec: Codec<D, R, W>,
}
#[derive(Debug, Copy, Clone)]
pub struct TransferSyntaxFactory(pub fn() -> TransferSyntax);
#[cfg(feature = "inventory-registry")]
inventory::collect!(TransferSyntaxFactory);
pub trait TransferSyntaxIndex {
fn get(&self, uid: &str) -> Option<&TransferSyntax>;
}
impl<T: ?Sized> TransferSyntaxIndex for &T
where
T: TransferSyntaxIndex,
{
fn get(&self, uid: &str) -> Option<&TransferSyntax> {
(**self).get(uid)
}
}
#[cfg(feature = "inventory-registry")]
#[macro_export]
macro_rules! submit_transfer_syntax {
($ts: expr) => {
$crate::inventory::submit! {
$crate::transfer_syntax::TransferSyntaxFactory(|| ($ts).erased())
}
};
}
#[cfg(not(feature = "inventory-registry"))]
#[macro_export]
macro_rules! submit_transfer_syntax {
($ts: expr) => {
};
}
#[cfg(feature = "inventory-registry")]
#[macro_export]
macro_rules! submit_ele_transfer_syntax {
($uid: expr, $name: expr, $codec: expr) => {
$crate::submit_transfer_syntax! {
$crate::TransferSyntax::new_ele(
$uid,
$name,
$codec
)
}
};
}
#[cfg(not(feature = "inventory-registry"))]
#[macro_export]
macro_rules! submit_ele_transfer_syntax {
($uid: literal, $name: literal, $codec: expr) => {
};
}
#[derive(Debug, Clone, PartialEq)]
pub enum Codec<D, R, W> {
None,
EncapsulatedPixelData(Option<R>, Option<W>),
Dataset(Option<D>),
}
impl Codec<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter> {
pub fn encapsulated_pixel_data_stub() -> Self {
Codec::EncapsulatedPixelData(None, None)
}
}
impl<R> Codec<NeverAdapter, R, NeverPixelAdapter> {
pub fn encapsulated_pixel_data_reader(reader: R) -> Self {
Codec::EncapsulatedPixelData(Some(reader), None)
}
}
impl<R, W> Codec<NeverAdapter, R, W> {
pub fn encapsulated_pixel_data(reader: R, writer: W) -> Self {
Codec::EncapsulatedPixelData(Some(reader), Some(writer))
}
}
pub type AdapterFreeTransferSyntax =
TransferSyntax<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>;
pub trait DataRWAdapter {
fn adapt_reader<'r>(&self, reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r>;
fn adapt_writer<'w>(&self, writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w>;
}
pub type DynDataRWAdapter = Box<dyn DataRWAdapter + Send + Sync>;
impl<T> DataRWAdapter for &'_ T
where
T: DataRWAdapter,
{
fn adapt_reader<'r>(&self, reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r> {
(**self).adapt_reader(reader)
}
fn adapt_writer<'w>(&self, writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w> {
(**self).adapt_writer(writer)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NeverAdapter {}
impl DataRWAdapter for NeverAdapter {
fn adapt_reader<'r>(&self, _reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r> {
unreachable!()
}
fn adapt_writer<'w>(&self, _writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w> {
unreachable!()
}
}
impl<D, R, W> TransferSyntax<D, R, W> {
pub const fn new(
uid: &'static str,
name: &'static str,
byte_order: Endianness,
explicit_vr: bool,
codec: Codec<D, R, W>,
) -> Self {
TransferSyntax {
uid,
name,
byte_order,
explicit_vr,
codec,
}
}
pub const fn new_ele(uid: &'static str, name: &'static str, codec: Codec<D, R, W>) -> Self {
TransferSyntax {
uid,
name,
byte_order: Endianness::Little,
explicit_vr: true,
codec,
}
}
pub const fn uid(&self) -> &'static str {
self.uid
}
pub const fn name(&self) -> &'static str {
self.name
}
pub const fn endianness(&self) -> Endianness {
self.byte_order
}
pub fn codec(&self) -> &Codec<D, R, W> {
&self.codec
}
pub fn is_fully_supported(&self) -> bool {
matches!(
self.codec,
Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(Some(_), Some(_)),
)
}
pub fn is_codec_free(&self) -> bool {
matches!(self.codec, Codec::None)
}
pub fn is_unsupported(&self) -> bool {
matches!(self.codec, Codec::Dataset(None))
}
pub fn is_encapsulated_pixel_data(&self) -> bool {
matches!(self.codec, Codec::EncapsulatedPixelData(..))
}
pub fn is_unsupported_pixel_encapsulation(&self) -> bool {
matches!(
self.codec,
Codec::Dataset(None) | Codec::EncapsulatedPixelData(None, None)
)
}
pub fn can_decode_all(&self) -> bool {
matches!(
self.codec,
Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(Some(_), _)
)
}
pub fn can_decode_dataset(&self) -> bool {
matches!(
self.codec,
Codec::None | Codec::Dataset(Some(_)) | Codec::EncapsulatedPixelData(..)
)
}
pub fn decoder<'s>(&self) -> Option<DynDecoder<dyn Read + 's>> {
self.decoder_for()
}
pub fn decoder_for<S>(&self) -> Option<DynDecoder<S>>
where
Self: Sized,
S: ?Sized + Read,
{
match (self.byte_order, self.explicit_vr) {
(Endianness::Little, false) => Some(Box::<ImplicitVRLittleEndianDecoder<_>>::default()),
(Endianness::Little, true) => Some(Box::<ExplicitVRLittleEndianDecoder>::default()),
(Endianness::Big, true) => Some(Box::<ExplicitVRBigEndianDecoder>::default()),
_ => None,
}
}
pub fn encoder<'w>(&self) -> Option<DynEncoder<'w, dyn Write + 'w>> {
self.encoder_for()
}
pub fn encoder_for<'w, T>(&self) -> Option<DynEncoder<'w, T>>
where
Self: Sized,
T: ?Sized + Write + 'w,
{
match (self.byte_order, self.explicit_vr) {
(Endianness::Little, false) => Some(Box::new(EncoderFor::new(
ImplicitVRLittleEndianEncoder::default(),
))),
(Endianness::Little, true) => Some(Box::new(EncoderFor::new(
ExplicitVRLittleEndianEncoder::default(),
))),
(Endianness::Big, true) => Some(Box::new(EncoderFor::new(
ExplicitVRBigEndianEncoder::default(),
))),
_ => None,
}
}
pub fn basic_decoder(&self) -> BasicDecoder {
BasicDecoder::from(self.endianness())
}
pub fn pixel_data_reader(&self) -> Option<&R> {
match &self.codec {
Codec::EncapsulatedPixelData(r, _) => r.as_ref(),
_ => None,
}
}
pub fn pixel_data_writer(&self) -> Option<&W> {
match &self.codec {
Codec::EncapsulatedPixelData(_, w) => w.as_ref(),
_ => None,
}
}
pub fn erased(self) -> TransferSyntax
where
D: Send + Sync + 'static,
D: DataRWAdapter,
R: Send + Sync + 'static,
R: PixelDataReader,
W: Send + Sync + 'static,
W: PixelDataWriter,
{
let codec = match self.codec {
Codec::Dataset(d) => Codec::Dataset(d.map(|d| Box::new(d) as _)),
Codec::EncapsulatedPixelData(r, w) => Codec::EncapsulatedPixelData(
r.map(|r| Box::new(r) as _),
w.map(|w| Box::new(w) as _),
),
Codec::None => Codec::None,
};
TransferSyntax {
uid: self.uid,
name: self.name,
byte_order: self.byte_order,
explicit_vr: self.explicit_vr,
codec,
}
}
}