1use crate::Error;
4use crate::provider::{Finalized, Finished, Prehash};
5use crate::stream::{self, Sink, Source, StreamError};
6use core::cmp::Ordering;
7use structured_asn1::digest::{Digest, Resolution};
8use structured_asn1::memory::{OwnedVec, SortError, Work};
9
10pub type PassError<SE, PE> = StreamError<SE, DigestError<PE>>;
12pub type DigestOutput<'a, P> =
14 Finalized<'a, P, <P as Digest<'a>>::Identity, <P as Digest<'a>>::Output>;
15pub type DigestResult<T, E> = Result<T, DigestError<E>>;
17pub type PassResult<T, SE, PE> = Result<T, PassError<SE, PE>>;
19
20#[derive(Debug)]
22pub enum DigestError<E> {
23 Processing(Error),
25 Callback(E),
27 OutputWidth {
30 expected: usize,
32 actual: usize,
34 },
35 Unstreamable,
39}
40
41fn started<S, E>(start: Result<Resolution<S>, E>) -> Result<S, DigestError<E>> {
42 match start.map_err(DigestError::Callback)? {
43 Resolution::Supported(state) => Ok(state),
44 Resolution::Unsupported | Resolution::Malformed => Err(DigestError::Unstreamable),
45 }
46}
47
48struct Pending<I, S> {
49 ordinal: usize,
50 identity: I,
51 state: S,
52}
53
54struct Request<I> {
55 ordinal: usize,
56 identity: I,
57}
58
59pub struct DigestBatch<'a, P: Digest<'a>> {
61 provider: &'a P,
62 pending: OwnedVec<Pending<P::Identity, P::State>>,
63 mapping: OwnedVec<usize>,
64 field: &'static str,
65 at: u64,
66}
67
68impl<'a, P: Digest<'a>> DigestBatch<'a, P> {
69 pub fn prepare<W: Work>(
76 provider: &'a P,
77 identities: OwnedVec<P::Identity>,
78 execution: &W,
79 field: &'static str,
80 at: u64,
81 ) -> Result<Self, DigestError<P::Error>> {
82 crate::provider::require_instance(provider, field, at).map_err(DigestError::Processing)?;
83 let refusal = |reason| DigestError::Processing(Error::resource(reason, field, at));
84 execution.charge_work(1).map_err(refusal)?;
85 let count = identities.len();
86 let mut ordered = execution.vector();
87 ordered
88 .try_reserve_exact(identities.len())
89 .map_err(refusal)?;
90 execution
91 .charge_work(core::mem::size_of_val(&*identities) as u64)
92 .map_err(refusal)?;
93 for (ordinal, identity) in identities.into_iter().enumerate() {
94 ordered
95 .try_push(Request { ordinal, identity })
96 .map_err(refusal)?;
97 }
98 ordered
99 .try_sort_unstable_by(|left, right| {
100 let order = provider.compare(&left.identity, &right.identity, execution)?;
101 if order == Ordering::Equal {
105 Ok(left.ordinal.cmp(&right.ordinal))
106 } else {
107 Ok(order)
108 }
109 })
110 .map_err(|error| match error {
111 SortError::Resource(reason) => refusal(reason),
112 SortError::Comparison(error) => DigestError::Callback(error),
113 })?;
114 let mut pending: OwnedVec<Pending<P::Identity, P::State>, _> = execution.vector();
115 let mut mapping = execution.vector();
116 mapping.try_reserve_exact(count).map_err(refusal)?;
117 for _ in 0..count {
120 mapping.try_push(0).map_err(refusal)?;
121 }
122 execution
123 .charge_work(core::mem::size_of_val(&*ordered) as u64)
124 .map_err(refusal)?;
125 for Request { ordinal, identity } in ordered.into_owned() {
126 execution.charge_work(1).map_err(refusal)?;
127 if let Some(previous) = pending.last()
128 && provider
129 .compare(&previous.identity, &identity, execution)
130 .map_err(DigestError::Callback)?
131 == Ordering::Equal
132 {
133 mapping[ordinal] = pending.len() - 1;
134 continue;
135 }
136 pending.try_reserve(1).map_err(refusal)?;
137 let state = started(provider.start(&identity, execution))?;
138 pending
139 .try_push(Pending {
140 ordinal,
141 identity,
142 state,
143 })
144 .map_err(refusal)?;
145 mapping[ordinal] = pending.len() - 1;
146 }
147 Ok(Self {
148 provider,
149 pending: pending.into_owned(),
150 mapping: mapping.into_owned(),
151 field,
152 at,
153 })
154 }
155
156 #[must_use]
158 pub fn len(&self) -> usize {
159 self.pending.len()
160 }
161 #[must_use]
163 pub fn is_empty(&self) -> bool {
164 self.pending.is_empty()
165 }
166
167 pub fn run<S: Source, W: Work>(
173 mut self,
174 source: &mut S,
175 execution: &W,
176 ) -> Result<DigestMemo<'a, P>, PassError<S::Error, P::Error>> {
177 let field = self.field;
178 let at = self.at;
179 let mut outputs = execution.vector();
180 outputs
181 .try_reserve_exact(self.pending.len())
182 .map_err(|reason| StreamError::Processing(Error::resource(reason, field, at)))?;
183 stream::run(source, &mut BatchSink(&mut self), execution, field, at)?;
184 self.finish(outputs, execution)
185 .map_err(StreamError::Callback)
186 }
187
188 pub fn run_requests<S: RequestSource<'a, P>, W: Work>(
198 mut self,
199 source: &mut S,
200 execution: &W,
201 ) -> PassResult<DigestMemo<'a, P>, S::Error, P::Error> {
202 let mut outputs = execution.vector();
203 outputs
204 .try_reserve_exact(self.pending.len())
205 .map_err(|cause| {
206 StreamError::Processing(Error::resource(cause, self.field, self.at))
207 })?;
208 for pending in &mut self.pending {
209 execution.charge_work(1).map_err(|cause| {
210 StreamError::Processing(Error::resource(cause, self.field, self.at))
211 })?;
212 let mut selected = SelectedSource {
213 source,
214 ordinal: pending.ordinal,
215 provider: self.provider,
216 identity: &pending.identity,
217 };
218 stream::run(
219 &mut selected,
220 &mut RelatedSink {
221 provider: self.provider,
222 state: &mut pending.state,
223 },
224 execution,
225 self.field,
226 self.at,
227 )?;
228 }
229 self.finish(outputs, execution)
230 .map_err(StreamError::Callback)
231 }
232
233 pub(crate) fn feed<W: Work>(
234 &mut self,
235 bytes: &[u8],
236 execution: &W,
237 ) -> Result<(), DigestError<P::Error>> {
238 for pending in &mut self.pending {
239 execution.charge_work(1).map_err(|reason| {
240 DigestError::Processing(Error::resource(reason, self.field, self.at))
241 })?;
242 self.provider
243 .update(&mut pending.state, bytes, execution)
244 .map_err(DigestError::Callback)?;
245 }
246 Ok(())
247 }
248
249 pub(crate) fn finish<W: Work>(
250 self,
251 mut outputs: OwnedVec<DigestOutput<'a, P>, W>,
252 execution: &W,
253 ) -> Result<DigestMemo<'a, P>, DigestError<P::Error>> {
254 let refusal =
255 |reason| DigestError::Processing(Error::resource(reason, self.field, self.at));
256 execution
257 .charge_work(core::mem::size_of_val(&*self.pending) as u64)
258 .map_err(refusal)?;
259 for pending in self.pending {
260 execution.charge_work(1).map_err(refusal)?;
261 let output = self
262 .provider
263 .finish(pending.state, execution)
264 .map_err(DigestError::Callback)?;
265 if let Some(expected) = self.provider.width(&pending.identity) {
266 let actual = output.as_ref().len();
267 if actual != expected {
268 return Err(DigestError::OutputWidth { expected, actual });
269 }
270 }
271 outputs
272 .try_push(Finalized::new(self.provider, pending.identity, output))
273 .map_err(refusal)?;
274 }
275 Ok(DigestMemo {
276 provider: self.provider,
277 outputs: outputs.into_owned(),
278 mapping: self.mapping,
279 field: self.field,
280 at: self.at,
281 })
282 }
283
284 pub(crate) fn provider(&self) -> &'a P {
285 self.provider
286 }
287
288 pub(crate) fn location(&self) -> (&'static str, u64) {
289 (self.field, self.at)
290 }
291}
292
293pub trait RequestSource<'provider, P: Digest<'provider>> {
296 type Error;
298 fn stream_request<W: Work>(
301 &mut self,
302 ordinal: usize,
303 provider: &'provider P,
304 identity: &P::Identity,
305 receiver: &mut impl crate::stream::Receiver,
306 execution: &W,
307 ) -> Result<(), Self::Error>;
308}
309struct SelectedSource<'s, 'p, P: Digest<'p>, S> {
310 source: &'s mut S,
311 ordinal: usize,
312 provider: &'p P,
313 identity: &'s P::Identity,
314}
315impl<'p, P: Digest<'p>, S: RequestSource<'p, P>> Source for SelectedSource<'_, 'p, P, S> {
316 type Error = S::Error;
317 fn stream<W: Work>(
318 &mut self,
319 receiver: &mut impl crate::stream::Receiver,
320 execution: &W,
321 ) -> Result<(), Self::Error> {
322 self.source.stream_request(
323 self.ordinal,
324 self.provider,
325 self.identity,
326 receiver,
327 execution,
328 )
329 }
330}
331
332struct BatchSink<'s, 'a, P: Digest<'a>>(&'s mut DigestBatch<'a, P>);
333
334impl<'a, P: Digest<'a>> Sink for BatchSink<'_, 'a, P> {
335 type Error = DigestError<P::Error>;
336 fn write<W: Work>(&mut self, bytes: &[u8], execution: &W) -> Result<(), Self::Error> {
337 self.0.feed(bytes, execution)
338 }
339}
340
341pub struct DigestMemo<'a, P: Digest<'a>> {
343 provider: &'a P,
344 outputs: OwnedVec<DigestOutput<'a, P>>,
345 mapping: OwnedVec<usize>,
346 field: &'static str,
347 at: u64,
348}
349
350pub struct RelatedDigest<'m, 'a, P: Digest<'a>> {
356 provider: &'a P,
357 identity: &'m P::Identity,
358 output: P::Output,
359}
360
361impl<'a, P: Digest<'a>> RelatedDigest<'_, 'a, P> {
362 #[must_use]
364 pub fn prehash(&self) -> Prehash<'_, '_, P, P::Identity> {
365 Prehash::new(self.provider, self.identity, self.output.as_ref())
366 }
367
368 #[must_use]
370 pub fn finished(&self) -> Finished<'_, P, P::Identity, P::Output> {
371 Finished::new(self.provider, self.identity, &self.output)
372 }
373}
374
375struct RelatedSink<'s, 'a, P: Digest<'a>> {
376 provider: &'a P,
377 state: &'s mut P::State,
378}
379
380impl<'a, P: Digest<'a>> Sink for RelatedSink<'_, 'a, P> {
381 type Error = DigestError<P::Error>;
382
383 fn write<W: Work>(&mut self, bytes: &[u8], execution: &W) -> Result<(), Self::Error> {
384 self.provider
385 .update(self.state, bytes, execution)
386 .map_err(DigestError::Callback)
387 }
388}
389
390impl<'a, P: Digest<'a>> DigestMemo<'a, P> {
391 pub fn digest_related<'m, S: Source, W: Work>(
399 &'m self,
400 ordinal: usize,
401 source: &mut S,
402 execution: &W,
403 field: &'static str,
404 at: u64,
405 ) -> PassResult<Option<RelatedDigest<'m, 'a, P>>, S::Error, P::Error> {
406 let Some(existing) = self
407 .for_request(ordinal, execution)
408 .map_err(StreamError::Callback)?
409 else {
410 return Ok(None);
411 };
412 let identity = existing.identity();
413 let mut state =
414 started(self.provider.start(identity, execution)).map_err(StreamError::Callback)?;
415 stream::run(
416 source,
417 &mut RelatedSink {
418 provider: self.provider,
419 state: &mut state,
420 },
421 execution,
422 field,
423 at,
424 )?;
425 let output = self
426 .provider
427 .finish(state, execution)
428 .map_err(|error| StreamError::Callback(DigestError::Callback(error)))?;
429 if let Some(expected) = self.provider.width(identity) {
430 let actual = output.as_ref().len();
431 if actual != expected {
432 return Err(StreamError::Callback(DigestError::OutputWidth {
433 expected,
434 actual,
435 }));
436 }
437 }
438 Ok(Some(RelatedDigest {
439 provider: self.provider,
440 identity,
441 output,
442 }))
443 }
444
445 #[must_use]
447 pub fn len(&self) -> usize {
448 self.outputs.len()
449 }
450 #[must_use]
452 pub fn is_empty(&self) -> bool {
453 self.outputs.is_empty()
454 }
455
456 #[must_use]
458 pub fn request_count(&self) -> usize {
459 self.mapping.len()
460 }
461
462 pub fn for_request<W: Work>(
468 &self,
469 ordinal: usize,
470 execution: &W,
471 ) -> DigestResult<Option<&DigestOutput<'a, P>>, P::Error> {
472 execution.charge_work(1).map_err(|reason| {
473 DigestError::Processing(Error::resource(reason, self.field, self.at))
474 })?;
475 let Some(index) = self.mapping.get(ordinal) else {
476 return Ok(None);
477 };
478 debug_assert!(*index < self.outputs.len());
481 Ok(Some(&self.outputs[*index]))
482 }
483
484 pub fn find<W: Work>(
489 &self,
490 identity: &P::Identity,
491 execution: &W,
492 ) -> DigestResult<Option<&DigestOutput<'a, P>>, P::Error> {
493 let refusal =
494 |reason| DigestError::Processing(Error::resource(reason, self.field, self.at));
495 execution.charge_work(1).map_err(refusal)?;
496 let mut from = 0;
497 let mut to = self.outputs.len();
498 while from < to {
499 execution.charge_work(1).map_err(refusal)?;
500 let middle = from + (to - from) / 2;
501 let held = &self.outputs[middle];
502 match self
503 .provider
504 .compare(held.identity(), identity, execution)
505 .map_err(DigestError::Callback)?
506 {
507 Ordering::Equal => return Ok(Some(held)),
508 Ordering::Less => from = middle + 1,
509 Ordering::Greater => to = middle,
510 }
511 }
512 Ok(None)
513 }
514}