Skip to content

Commit

Permalink
Merge pull request #342 from Enet4/imp/parser/extend-reader
Browse files Browse the repository at this point in the history
Extend data set readers
  • Loading branch information
Enet4 authored May 2, 2023
2 parents 30e69bf + 6a3b798 commit ce90d9f
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 17 deletions.
32 changes: 18 additions & 14 deletions parser/src/dataset/lazy_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,17 @@ where
})
}

/** Advance and retrieve the next DICOM data token.
*
* **Note:** For the data set to be successfully parsed,
* the resulting data tokens needs to be consumed
* if they are of a value type.
*/
pub fn next(&mut self) -> Option<Result<LazyDataToken<&mut S>>> {
/// Retrieve the inner stateful decoder from this data set reader.
pub fn into_decoder(self) -> S {
self.parser
}

/// Advance and retrieve the next DICOM data token.
///
/// **Note:** For the data set to be successfully parsed,
/// the resulting data tokens needs to be consumed
/// if they are of a value type.
pub fn advance(&mut self) -> Option<Result<LazyDataToken<&mut S>>> {
if self.hard_break {
return None;
}
Expand Down Expand Up @@ -478,7 +482,7 @@ mod tests {
let mut dset_reader = LazyDataSetReader::new(parser);

let mut gt_iter = ground_truth.into_iter();
while let Some(res) = dset_reader.next() {
while let Some(res) = dset_reader.advance() {
let gt_token = gt_iter.next().expect("ground truth is shorter");
let token = res.expect("should parse without an error");
let token = token.into_owned().unwrap();
Expand Down Expand Up @@ -1025,7 +1029,7 @@ mod tests {
let mut dset_reader = LazyDataSetReader::new(parser);

let mut gt_iter = ground_truth.into_iter();
while let Some(res) = dset_reader.next() {
while let Some(res) = dset_reader.advance() {
let token = res.expect("should parse without an error");
let gt_token = gt_iter.next().expect("ground truth is shorter");
match token {
Expand Down Expand Up @@ -1078,7 +1082,7 @@ mod tests {
let mut dset_reader = LazyDataSetReader::new(parser);

let token = dset_reader
.next()
.advance()
.expect("Expected token 1")
.expect("Failed to read token 1");

Expand All @@ -1090,7 +1094,7 @@ mod tests {
};

let token = dset_reader
.next()
.advance()
.expect("Expected token 2")
.expect("Failed to read token 2");

Expand All @@ -1110,7 +1114,7 @@ mod tests {
);

let token = dset_reader
.next()
.advance()
.expect("Expected token 3")
.expect("Failed to read token 3");

Expand All @@ -1122,7 +1126,7 @@ mod tests {
};

let token = dset_reader
.next()
.advance()
.expect("Expected token 4")
.expect("Failed to read token 4");

Expand All @@ -1142,7 +1146,7 @@ mod tests {
);

assert!(
dset_reader.next().is_none(),
dset_reader.advance().is_none(),
"unexpected number of tokens remaining"
);
}
Expand Down
6 changes: 3 additions & 3 deletions parser/src/dataset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,14 @@ impl<D> LazyDataToken<D>
where
D: decode::StatefulDecode,
{
pub fn skip(self) -> Result<()> {
pub fn skip(self) -> crate::stateful::decode::Result<()> {
match self {
LazyDataToken::LazyValue {
header,
mut decoder,
} => decoder.skip_bytes(header.len.0).context(SkipValueSnafu),
} => decoder.skip_bytes(header.len.0),
LazyDataToken::LazyItemValue { len, mut decoder } => {
decoder.skip_bytes(len).context(SkipValueSnafu)
decoder.skip_bytes(len)
}
_ => Ok(()), // do nothing
}
Expand Down
105 changes: 105 additions & 0 deletions parser/src/dataset/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ pub struct DataSetReader<S> {
hard_break: bool,
/// last decoded header
last_header: Option<DataElementHeader>,
/// if a peek was taken, this holds the token peeked
peek: Option<DataToken>,
}

impl<R> DataSetReader<DynStatefulDecoder<R>> {
Expand Down Expand Up @@ -217,6 +219,7 @@ impl<R> DataSetReader<DynStatefulDecoder<R>> {
in_sequence: false,
hard_break: false,
last_header: None,
peek: None,
})
}
}
Expand All @@ -233,6 +236,7 @@ impl<S> DataSetReader<S> {
in_sequence: false,
hard_break: false,
last_header: None,
peek: None,
}
}
}
Expand All @@ -247,6 +251,10 @@ where
if self.hard_break {
return None;
}
// if there was a peek, consume peeked token
if let Some(token) = self.peek.take() {
return Some(Ok(token));
}

// item or sequence delimitation logic for explicit lengths
if self.delimiter_check_pending {
Expand Down Expand Up @@ -488,6 +496,25 @@ impl<S> DataSetReader<S>
where
S: StatefulDecode,
{
/// Peek the next token from the source by
/// reading a new token in the first call.
/// Subsequent calls to `peek` will return the same token
/// until another consumer method (such as `Iterator::next`)
/// is called.
pub fn peek(&mut self) -> Result<Option<&DataToken>> {
if self.peek.is_none() {
// try to read the next token
match self.next() {
None => return Ok(None),
Some(Err(e)) => return Err(e),
Some(Ok(token)) => {
self.peek = Some(token);
}
}
}
Ok(self.peek.as_ref())
}

fn update_seq_delimiters(&mut self) -> Result<Option<DataToken>> {
if let Some(sd) = self.seq_delimiters.last() {
if let Some(len) = sd.len.get() {
Expand Down Expand Up @@ -1119,4 +1146,82 @@ mod tests {

validate_dataset_reader_implicit_vr(DATA, ground_truth);
}

#[test]
fn peek_data_elements_implicit() {
#[rustfmt::skip]
static DATA: &[u8] = &[
0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
b'S', b'Q', // VR
0x00, 0x00, // reserved
0xff, 0xff, 0xff, 0xff, // length: undefined
// -- 12 --
0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
// -- 82 --
0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
b'T', b'E', b'S', b'T', // value = "TEST"
];

let ground_truth = vec![
DataToken::SequenceStart {
tag: Tag(0x0018, 0x6011),
len: Length::UNDEFINED,
},
DataToken::SequenceEnd,
DataToken::ElementHeader(DataElementHeader {
tag: Tag(0x0020, 0x4000),
vr: VR::LT,
len: Length(4),
}),
DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
];

let mut cursor = DATA;
let parser = StatefulDecoder::new(
&mut cursor,
ExplicitVRLittleEndianDecoder::default(),
LittleEndianBasicDecoder::default(),
SpecificCharacterSet::Default,
);
let mut dset_reader = DataSetReader::new(parser, Default::default());

let iter = (&mut dset_reader).into_iter();

// peek at first token
let token = iter.peek().expect("should peek first token OK");
assert_eq!(token, Some(&ground_truth[0]));

// peeking multiple times gives the same result
let token = iter.peek().expect("should peek first token again OK");
assert_eq!(token, Some(&ground_truth[0]));

// Using `next` give us the same token
let token = iter
.next()
.expect("expected token")
.expect("should read token peeked OK");
assert_eq!(&token, &ground_truth[0]);

// read some more tokens

// sequence end
let token = iter.next().unwrap().unwrap();
assert_eq!(&token, &ground_truth[1]);
// data element header
let token = iter.next().unwrap().unwrap();
assert_eq!(&token, &ground_truth[2]);

// peek string value
let token = iter.peek().unwrap();
assert_eq!(token, Some(&ground_truth[3]));
// peek it again
let token = iter.peek().unwrap();
assert_eq!(token, Some(&ground_truth[3]));
// then read it
let token = iter.next().unwrap().unwrap();
assert_eq!(&token, &ground_truth[3]);

// finished reading, peek should return None
assert!(iter.peek().unwrap().is_none());
}
}

0 comments on commit ce90d9f

Please sign in to comment.