dicom_object/
tokens.rs

1//! Conversion of DICOM objects into tokens.
2use crate::mem::InMemDicomObject;
3use dicom_core::DataElement;
4use dicom_parser::dataset::{DataToken, IntoTokens, IntoTokensOptions};
5use std::collections::VecDeque;
6
7/// A stream of tokens from a DICOM object.
8pub struct InMemObjectTokens<E> {
9    /// iterators of tokens in order of priority.
10    tokens_pending: VecDeque<DataToken>,
11    /// the iterator of data elements in order.
12    elem_iter: E,
13    /// whether the tokens are done
14    fused: bool,
15    /// Options to take into account when generating tokens
16    token_options: IntoTokensOptions,
17}
18
19impl<E> InMemObjectTokens<E>
20where
21    E: Iterator,
22{
23    pub fn new<T>(obj: T) -> Self
24    where
25        T: IntoIterator<IntoIter = E, Item = E::Item>,
26    {
27        InMemObjectTokens {
28            tokens_pending: Default::default(),
29            elem_iter: obj.into_iter(),
30            fused: false,
31            token_options: Default::default(),
32        }
33    }
34
35    pub fn new_with_options<T>(obj: T, token_options: IntoTokensOptions) -> Self
36    where
37        T: IntoIterator<IntoIter = E, Item = E::Item>,
38    {
39        InMemObjectTokens {
40            tokens_pending: Default::default(),
41            elem_iter: obj.into_iter(),
42            fused: false,
43            token_options,
44        }
45    }
46}
47
48impl<P, I, E> Iterator for InMemObjectTokens<E>
49where
50    E: Iterator<Item = DataElement<I, P>>,
51    E::Item: IntoTokens,
52{
53    type Item = DataToken;
54
55    fn next(&mut self) -> Option<Self::Item> {
56        if self.fused {
57            return None;
58        }
59
60        // otherwise, consume pending tokens
61        if let Some(token) = self.tokens_pending.pop_front() {
62            return Some(token);
63        }
64
65        // otherwise, expand next element, recurse
66        if let Some(elem) = self.elem_iter.next() {
67            self.tokens_pending = if self.token_options == Default::default() {
68                elem.into_tokens()
69            } else {
70                elem.into_tokens_with_options(self.token_options)
71            }
72            .collect();
73
74            self.next()
75        } else {
76            // no more elements
77            None
78        }
79    }
80
81    fn size_hint(&self) -> (usize, Option<usize>) {
82        // make a slightly better estimation for the minimum
83        // number of tokens that follow: 2 tokens per element left
84        (self.elem_iter.size_hint().0 * 2, None)
85    }
86}
87
88impl<D> IntoTokens for InMemDicomObject<D> {
89    type Iter = InMemObjectTokens<<InMemDicomObject<D> as IntoIterator>::IntoIter>;
90
91    fn into_tokens(self) -> Self::Iter {
92        InMemObjectTokens::new(self)
93    }
94
95    fn into_tokens_with_options(self, mut options: IntoTokensOptions) -> Self::Iter {
96        //This is required for recursing with the correct option
97        options.force_invalidate_sq_length |= self.charset_changed;
98        InMemObjectTokens::new_with_options(self, options)
99    }
100}
101
102impl<'a, D> IntoTokens for &'a InMemDicomObject<D>
103where
104    D: Clone,
105{
106    type Iter =
107        InMemObjectTokens<std::iter::Cloned<<&'a InMemDicomObject<D> as IntoIterator>::IntoIter>>;
108
109    fn into_tokens(self) -> Self::Iter {
110        self.into_tokens_with_options(Default::default())
111    }
112
113    fn into_tokens_with_options(self, mut options: IntoTokensOptions) -> Self::Iter {
114        options.force_invalidate_sq_length |= self.charset_changed;
115
116        InMemObjectTokens::new_with_options(self.into_iter().cloned(), options)
117    }
118}