Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First crack at adding dataset read adapter in DS read for deflate #438

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 21 additions & 55 deletions encoding/src/transfer_syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,57 +319,29 @@ pub enum Codec<D, R, W> {
pub type AdapterFreeTransferSyntax =
TransferSyntax<NeverAdapter, NeverPixelAdapter, NeverPixelAdapter>;

/// An adapter of byte read and write streams.
pub trait DataRWAdapter<R, W> {
/// The type of the adapted reader.
type Reader: Read;
/// The type of the adapted writer.
type Writer: Write;

/// A fully dynamic adapter of byte read and write streams.
pub trait DataRWAdapter {
/// Adapt a byte reader.
fn adapt_reader(&self, reader: R) -> Self::Reader
where
R: Read;
fn adapt_reader<'r>(&self, reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r>;

/// Adapt a byte writer.
fn adapt_writer(&self, writer: W) -> Self::Writer
where
W: Write;
fn adapt_writer<'w>(&self, writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w>;
}

/// Alias type for a dynamically dispatched data adapter.
pub type DynDataRWAdapter = Box<
dyn DataRWAdapter<
Box<dyn Read>,
Box<dyn Write>,
Reader = Box<dyn Read>,
Writer = Box<dyn Write>,
> + Send
+ Sync,
>;

impl<T, R, W> DataRWAdapter<R, W> for &'_ T
pub type DynDataRWAdapter = Box<dyn DataRWAdapter + Send + Sync>;

impl<T> DataRWAdapter for &'_ T
where
T: DataRWAdapter<R, W>,
R: Read,
W: Write,
T: DataRWAdapter,
{
type Reader = <T as DataRWAdapter<R, W>>::Reader;
type Writer = <T as DataRWAdapter<R, W>>::Writer;

/// Adapt a byte reader.
fn adapt_reader(&self, reader: R) -> Self::Reader
where
R: Read,
{
fn adapt_reader<'r>(&self, reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r> {
(**self).adapt_reader(reader)
}

/// Adapt a byte writer.
fn adapt_writer(&self, writer: W) -> Self::Writer
where
W: Write,
{
fn adapt_writer<'w>(&self, writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w> {
(**self).adapt_writer(writer)
}
}
Expand All @@ -384,21 +356,13 @@ where
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NeverAdapter {}

impl<R, W> DataRWAdapter<R, W> for NeverAdapter {
type Reader = Box<dyn Read>;
type Writer = Box<dyn Write>;
impl DataRWAdapter for NeverAdapter {

fn adapt_reader(&self, _reader: R) -> Self::Reader
where
R: Read,
{
fn adapt_reader<'r>(&self, _reader: Box<dyn Read + 'r>) -> Box<dyn Read + 'r> {
unreachable!()
}

fn adapt_writer(&self, _writer: W) -> Self::Writer
where
W: Write,
{
fn adapt_writer<'w>(&self, _writer: Box<dyn Write + 'w>) -> Box<dyn Write + 'w> {
unreachable!()
}
}
Expand Down Expand Up @@ -531,6 +495,13 @@ impl<D, R, W> TransferSyntax<D, R, W> {
matches!(self.codec, Codec::Dataset(None))
}

/// Check whether this transfer syntax expects pixel data to be encapsulated.
///
/// This does not imply that the pixel data can be decoded.
pub fn is_encapsulated_pixel_data(&self) -> bool {
matches!(self.codec, Codec::EncapsulatedPixelData(..))
}

/// Check whether reading and writing the pixel data is unsupported.
/// If this is `true`, encoding and decoding of the data set may still
/// be possible, but the pixel data will only be available in its
Expand Down Expand Up @@ -628,12 +599,7 @@ impl<D, R, W> TransferSyntax<D, R, W> {
pub fn erased(self) -> TransferSyntax
where
D: Send + Sync + 'static,
D: DataRWAdapter<
Box<dyn Read>,
Box<dyn Write>,
Reader = Box<dyn Read>,
Writer = Box<dyn Write>,
>,
D: DataRWAdapter,
R: Send + Sync + 'static,
R: PixelDataReader,
W: Send + Sync + 'static,
Expand Down
2 changes: 1 addition & 1 deletion object/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub type Result<T, E = ReadError> = std::result::Result<T, E>;
/// preamble: file meta group, followed by the rest of the data set.
pub fn from_reader<F>(file: F) -> Result<DefaultDicomObject>
where
F: Read,
F: Read + 'static,
{
OpenFileOptions::new().from_reader(file)
}
Expand Down
80 changes: 60 additions & 20 deletions object/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ pub use dicom_dictionary_std::StandardDataDictionary;
pub type DefaultDicomObject<D = StandardDataDictionary> = FileDicomObject<mem::InMemDicomObject<D>>;

use dicom_core::header::{GroupNumber, Header};
use dicom_encoding::Codec;
use dicom_encoding::adapters::{PixelDataObject, RawPixelData};
use dicom_encoding::transfer_syntax::TransferSyntaxIndex;
use dicom_parser::dataset::{DataSetWriter, IntoTokens};
Expand Down Expand Up @@ -475,21 +476,34 @@ where
.with_context(|| WriteUnsupportedTransferSyntaxSnafu {
uid: self.meta.transfer_syntax.clone(),
})?;
let mut dset_writer = DataSetWriter::with_ts(to, ts).context(CreatePrinterSnafu)?;
if let Codec::Dataset(Some(adapter))= ts.codec() {
let adapter = adapter.adapt_writer(Box::new(to));
let mut dset_writer = DataSetWriter::with_ts(adapter, ts).context(CreatePrinterSnafu)?;

// We use the default options, because only the inner object knows if something needs to change
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;
// write object
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;

Ok(())
Ok(())

} else {
let mut dset_writer = DataSetWriter::with_ts(to, ts).context(CreatePrinterSnafu)?;

// write object
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;

Ok(())
}
}

/// Write the entire object as a DICOM file
/// into the given writer.
/// Preamble, magic code, and file meta group will be included
/// before the inner object.
pub fn write_all<W: Write>(&self, to: W) -> Result<(), WriteError> {
pub fn write_all(&self, to: impl Write) -> Result<(), WriteError> {
let mut to = BufWriter::new(to);

// write preamble
Expand All @@ -507,14 +521,27 @@ where
.with_context(|| WriteUnsupportedTransferSyntaxSnafu {
uid: self.meta.transfer_syntax.clone(),
})?;
let mut dset_writer = DataSetWriter::with_ts(to, ts).context(CreatePrinterSnafu)?;
if let Codec::Dataset(Some(adapter))= ts.codec() {
let adapter = adapter.adapt_writer(Box::new(to));
let mut dset_writer = DataSetWriter::with_ts(adapter, ts).context(CreatePrinterSnafu)?;

// write object
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;

Ok(())

// We use the default options, because only the inner object knows if something needs to change
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;
} else {
let mut dset_writer = DataSetWriter::with_ts(to, ts).context(CreatePrinterSnafu)?;

Ok(())
// write object
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;

Ok(())
}
}

/// Write the file meta group set into the given writer.
Expand All @@ -528,7 +555,7 @@ where
/// without preamble, magic code, nor file meta group.
///
/// The transfer syntax is selected from the file meta table.
pub fn write_dataset<W: Write>(&self, to: W) -> Result<(), WriteError> {
pub fn write_dataset<W: Write + 'static>(&self, to: W) -> Result<(), WriteError> {
let to = BufWriter::new(to);

// prepare encoder
Expand All @@ -537,14 +564,27 @@ where
.with_context(|| WriteUnsupportedTransferSyntaxSnafu {
uid: self.meta.transfer_syntax.clone(),
})?;
let mut dset_writer = DataSetWriter::with_ts(to, ts).context(CreatePrinterSnafu)?;
if let Codec::Dataset(Some(adapter))= ts.codec() {
let adapter = adapter.adapt_writer(Box::new(to));
let mut dset_writer = DataSetWriter::with_ts(adapter, ts).context(CreatePrinterSnafu)?;

// write object
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;

// write object
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;
Ok(())

Ok(())
} else {
let mut dset_writer = DataSetWriter::with_ts(to, ts).context(CreatePrinterSnafu)?;

// write object
dset_writer
.write_sequence((&self.obj).into_tokens())
.context(PrintDataSetSnafu)?;

Ok(())
}
}
}

Expand Down
Loading
Loading