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 async fn run_async<S: stream::AsyncSource, W: Work>(
191 mut self,
192 source: &mut S,
193 execution: &W,
194 ) -> Result<DigestMemo<'a, P>, PassError<S::Error, P::Error>> {
195 let field = self.field;
196 let at = self.at;
197 let mut outputs = execution.vector();
198 outputs
199 .try_reserve_exact(self.pending.len())
200 .map_err(|cause| StreamError::Processing(Error::resource(cause, field, at)))?;
201 stream::run_async(source, &mut BatchSink(&mut self), execution, field, at).await?;
202 self.finish(outputs, execution)
203 .map_err(StreamError::Callback)
204 }
205
206 pub fn run_requests<S: RequestSource<'a, P>, W: Work>(
216 mut self,
217 source: &mut S,
218 execution: &W,
219 ) -> PassResult<DigestMemo<'a, P>, S::Error, P::Error> {
220 let mut outputs = execution.vector();
221 outputs
222 .try_reserve_exact(self.pending.len())
223 .map_err(|cause| {
224 StreamError::Processing(Error::resource(cause, self.field, self.at))
225 })?;
226 for pending in &mut self.pending {
227 execution.charge_work(1).map_err(|cause| {
228 StreamError::Processing(Error::resource(cause, self.field, self.at))
229 })?;
230 let mut selected = SelectedSource {
231 source,
232 ordinal: pending.ordinal,
233 provider: self.provider,
234 identity: &pending.identity,
235 };
236 stream::run(
237 &mut selected,
238 &mut RelatedSink {
239 provider: self.provider,
240 state: &mut pending.state,
241 },
242 execution,
243 self.field,
244 self.at,
245 )?;
246 }
247 self.finish(outputs, execution)
248 .map_err(StreamError::Callback)
249 }
250
251 pub(crate) fn feed<W: Work>(
252 &mut self,
253 bytes: &[u8],
254 execution: &W,
255 ) -> Result<(), DigestError<P::Error>> {
256 for pending in &mut self.pending {
257 execution.charge_work(1).map_err(|reason| {
258 DigestError::Processing(Error::resource(reason, self.field, self.at))
259 })?;
260 self.provider
261 .update(&mut pending.state, bytes, execution)
262 .map_err(DigestError::Callback)?;
263 }
264 Ok(())
265 }
266
267 pub(crate) fn finish<W: Work>(
268 self,
269 mut outputs: OwnedVec<DigestOutput<'a, P>, W>,
270 execution: &W,
271 ) -> Result<DigestMemo<'a, P>, DigestError<P::Error>> {
272 let refusal =
273 |reason| DigestError::Processing(Error::resource(reason, self.field, self.at));
274 execution
275 .charge_work(core::mem::size_of_val(&*self.pending) as u64)
276 .map_err(refusal)?;
277 for pending in self.pending {
278 execution.charge_work(1).map_err(refusal)?;
279 let output = self
280 .provider
281 .finish(pending.state, execution)
282 .map_err(DigestError::Callback)?;
283 if let Some(expected) = self.provider.width(&pending.identity) {
284 let actual = output.as_ref().len();
285 if actual != expected {
286 return Err(DigestError::OutputWidth { expected, actual });
287 }
288 }
289 outputs
290 .try_push(Finalized::new(self.provider, pending.identity, output))
291 .map_err(refusal)?;
292 }
293 Ok(DigestMemo {
294 provider: self.provider,
295 outputs: outputs.into_owned(),
296 mapping: self.mapping,
297 field: self.field,
298 at: self.at,
299 })
300 }
301
302 pub(crate) fn provider(&self) -> &'a P {
303 self.provider
304 }
305
306 pub(crate) fn location(&self) -> (&'static str, u64) {
307 (self.field, self.at)
308 }
309}
310
311pub trait RequestSource<'provider, P: Digest<'provider>> {
314 type Error;
316 fn stream_request<W: Work>(
319 &mut self,
320 ordinal: usize,
321 provider: &'provider P,
322 identity: &P::Identity,
323 receiver: &mut impl crate::stream::Receiver,
324 execution: &W,
325 ) -> Result<(), Self::Error>;
326}
327struct SelectedSource<'s, 'p, P: Digest<'p>, S> {
328 source: &'s mut S,
329 ordinal: usize,
330 provider: &'p P,
331 identity: &'s P::Identity,
332}
333impl<'p, P: Digest<'p>, S: RequestSource<'p, P>> Source for SelectedSource<'_, 'p, P, S> {
334 type Error = S::Error;
335 fn stream<W: Work>(
336 &mut self,
337 receiver: &mut impl crate::stream::Receiver,
338 execution: &W,
339 ) -> Result<(), Self::Error> {
340 self.source.stream_request(
341 self.ordinal,
342 self.provider,
343 self.identity,
344 receiver,
345 execution,
346 )
347 }
348}
349
350struct BatchSink<'s, 'a, P: Digest<'a>>(&'s mut DigestBatch<'a, P>);
351
352impl<'a, P: Digest<'a>> Sink for BatchSink<'_, 'a, P> {
353 type Error = DigestError<P::Error>;
354 fn write<W: Work>(&mut self, bytes: &[u8], execution: &W) -> Result<(), Self::Error> {
355 self.0.feed(bytes, execution)
356 }
357}
358
359pub struct DigestMemo<'a, P: Digest<'a>> {
361 provider: &'a P,
362 outputs: OwnedVec<DigestOutput<'a, P>>,
363 mapping: OwnedVec<usize>,
364 field: &'static str,
365 at: u64,
366}
367
368pub struct RelatedDigest<'m, 'a, P: Digest<'a>> {
374 provider: &'a P,
375 identity: &'m P::Identity,
376 output: P::Output,
377}
378
379impl<'a, P: Digest<'a>> RelatedDigest<'_, 'a, P> {
380 #[must_use]
382 pub fn prehash(&self) -> Prehash<'_, '_, P, P::Identity> {
383 Prehash::new(self.provider, self.identity, self.output.as_ref())
384 }
385
386 #[must_use]
388 pub fn finished(&self) -> Finished<'_, P, P::Identity, P::Output> {
389 Finished::new(self.provider, self.identity, &self.output)
390 }
391}
392
393struct RelatedSink<'s, 'a, P: Digest<'a>> {
394 provider: &'a P,
395 state: &'s mut P::State,
396}
397
398impl<'a, P: Digest<'a>> Sink for RelatedSink<'_, 'a, P> {
399 type Error = DigestError<P::Error>;
400
401 fn write<W: Work>(&mut self, bytes: &[u8], execution: &W) -> Result<(), Self::Error> {
402 self.provider
403 .update(self.state, bytes, execution)
404 .map_err(DigestError::Callback)
405 }
406}
407
408impl<'a, P: Digest<'a>> DigestMemo<'a, P> {
409 pub fn digest_related<'m, S: Source, W: Work>(
417 &'m self,
418 ordinal: usize,
419 source: &mut S,
420 execution: &W,
421 field: &'static str,
422 at: u64,
423 ) -> PassResult<Option<RelatedDigest<'m, 'a, P>>, S::Error, P::Error> {
424 let Some(existing) = self
425 .for_request(ordinal, execution)
426 .map_err(StreamError::Callback)?
427 else {
428 return Ok(None);
429 };
430 let identity = existing.identity();
431 let mut state =
432 started(self.provider.start(identity, execution)).map_err(StreamError::Callback)?;
433 stream::run(
434 source,
435 &mut RelatedSink {
436 provider: self.provider,
437 state: &mut state,
438 },
439 execution,
440 field,
441 at,
442 )?;
443 let output = self
444 .provider
445 .finish(state, execution)
446 .map_err(|error| StreamError::Callback(DigestError::Callback(error)))?;
447 if let Some(expected) = self.provider.width(identity) {
448 let actual = output.as_ref().len();
449 if actual != expected {
450 return Err(StreamError::Callback(DigestError::OutputWidth {
451 expected,
452 actual,
453 }));
454 }
455 }
456 Ok(Some(RelatedDigest {
457 provider: self.provider,
458 identity,
459 output,
460 }))
461 }
462
463 #[must_use]
465 pub fn len(&self) -> usize {
466 self.outputs.len()
467 }
468 #[must_use]
470 pub fn is_empty(&self) -> bool {
471 self.outputs.is_empty()
472 }
473
474 #[must_use]
476 pub fn request_count(&self) -> usize {
477 self.mapping.len()
478 }
479
480 pub fn for_request<W: Work>(
486 &self,
487 ordinal: usize,
488 execution: &W,
489 ) -> DigestResult<Option<&DigestOutput<'a, P>>, P::Error> {
490 execution.charge_work(1).map_err(|reason| {
491 DigestError::Processing(Error::resource(reason, self.field, self.at))
492 })?;
493 let Some(index) = self.mapping.get(ordinal) else {
494 return Ok(None);
495 };
496 debug_assert!(*index < self.outputs.len());
499 Ok(Some(&self.outputs[*index]))
500 }
501
502 pub fn find<W: Work>(
507 &self,
508 identity: &P::Identity,
509 execution: &W,
510 ) -> DigestResult<Option<&DigestOutput<'a, P>>, P::Error> {
511 let refusal =
512 |reason| DigestError::Processing(Error::resource(reason, self.field, self.at));
513 execution.charge_work(1).map_err(refusal)?;
514 let mut from = 0;
515 let mut to = self.outputs.len();
516 while from < to {
517 execution.charge_work(1).map_err(refusal)?;
518 let middle = from + (to - from) / 2;
519 let held = &self.outputs[middle];
520 match self
521 .provider
522 .compare(held.identity(), identity, execution)
523 .map_err(DigestError::Callback)?
524 {
525 Ordering::Equal => return Ok(Some(held)),
526 Ordering::Less => from = middle + 1,
527 Ordering::Greater => to = middle,
528 }
529 }
530 Ok(None)
531 }
532}