structured_cms/
counter.rs1use crate::signer::SignerInfo;
4use crate::{Error, ErrorCode, Result};
5use structured_asn1::Reader;
6use structured_asn1::memory::Work;
7
8mod walk;
9pub use walk::{Visit, WalkError, walk};
10
11const FIELD: &str = "signerInfo.unsignedAttrs.countersignature";
12
13pub struct Countersignatures<'s, 'a> {
20 signer: &'s SignerInfo<'a>,
21 parent: &'s Reader<'a>,
22 cursor: Cursor,
23}
24
25#[derive(Default)]
27struct Cursor {
28 attribute: usize,
29 active: Option<usize>,
30 value: usize,
31 stopped: bool,
32}
33
34impl<'s, 'a> Countersignatures<'s, 'a> {
35 pub(crate) fn new(signer: &'s SignerInfo<'a>, parent: &'s Reader<'a>) -> Self {
36 Self {
37 signer,
38 parent,
39 cursor: Cursor::default(),
40 }
41 }
42}
43
44impl Cursor {
45 fn next<'a>(
46 &mut self,
47 signer: &SignerInfo<'a>,
48 parent: &Reader<'a>,
49 ) -> Option<Result<(SignerInfo<'a>, Reader<'a>)>> {
50 if self.stopped {
51 return None;
52 }
53 if let Err(error) = signer.require_session(parent, FIELD) {
54 self.stopped = true;
55 return Some(Err(error));
56 }
57 let Some(attributes) = signer.unsigned_attributes() else {
58 self.stopped = true;
59 return None;
60 };
61 loop {
62 let at = self.active.map_or(signer.span().start, |index| {
63 attributes.items()[index].span().start
64 });
65 if let Err(reason) = parent.execution().charge_work(1) {
66 self.stopped = true;
67 return Some(Err(Error::resource(reason, FIELD, at)));
68 }
69 if let Some(index) = self.active {
70 let attribute = &attributes.items()[index];
71 if self.value < attribute.values().len() {
72 let index = self.value;
73 self.value += 1;
74 let value = (|| {
75 let Some(mut reader) = attribute.value_reader_in(index, parent, FIELD)?
76 else {
77 return Err(Error::schema(ErrorCode::MissingField, FIELD, at));
78 };
79 let element = crate::signer::required(&mut reader, FIELD)?;
80 let signer = SignerInfo::read(&reader, &element)?;
81 Ok((signer, reader))
82 })();
83 if value.as_ref().is_err_and(Error::is_terminal) {
84 self.stopped = true;
85 }
86 return Some(value);
87 }
88 self.active = None;
89 }
90 let attribute = match attributes.next_matching(
91 crate::oid::COUNTERSIGNATURE,
92 &parent.execution(),
93 &mut self.attribute,
94 &mut self.stopped,
95 ) {
96 Some(Ok(attribute)) => attribute,
97 Some(Err(error)) => return Some(Err(error)),
98 None => return None,
99 };
100 if attribute.values().is_empty() {
101 return Some(Err(Error::schema(
102 ErrorCode::AttributeCardinality,
103 FIELD,
104 attribute.span().start,
105 )));
106 }
107 self.active = Some(self.attribute - 1);
108 self.value = 0;
109 }
110 }
111}
112
113impl<'a> Iterator for Countersignatures<'_, 'a> {
114 type Item = Result<SignerInfo<'a>>;
115 fn next(&mut self) -> Option<Self::Item> {
116 self.cursor
117 .next(self.signer, self.parent)
118 .map(|reading| reading.map(|(signer, _reader)| signer))
119 }
120}
121impl core::iter::FusedIterator for Countersignatures<'_, '_> {}