1use alloc::boxed::Box;
43use alloc::vec;
44use alloc::vec::Vec;
45use core::fmt;
46use core::future::Future;
47
48use enough::{Stop, StopReason};
49use how_far::{Pulse, SharedPulse};
50use tokio::sync::{mpsc, oneshot};
51use zencodec::decode::{
52 BatchMeta, BoxedError, ByteRange, DecodeRowSink, Event, IncrementalDecode, InputRequest,
53 OutputInfo, SinkError, StepError,
54};
55use zencodec::encode::Encoder;
56use zencodec::how_far::NoPulse;
57use zencodec::source::{DynReadAt, SourceError};
58use zenpixels::{PixelBuffer, PixelDescriptor, PixelSliceMut};
59
60use crate::admission::{self, InputError};
61use crate::drive::{DriveOptions, Progressor};
62use crate::window::{ProtocolViolation, Window, check_need, read_target};
63
64#[allow(clippy::len_without_is_empty)]
70pub trait AsyncSource: Send {
71 fn read_at(
76 &mut self,
77 offset: u64,
78 out: &mut [u8],
79 ) -> impl Future<Output = Result<usize, BoxedError>> + Send;
80
81 fn read_ranges(
85 &mut self,
86 reqs: &mut [(u64, &mut [u8])],
87 ) -> impl Future<Output = Result<(), BoxedError>> + Send {
88 async move {
89 for (offset, out) in reqs.iter_mut() {
90 read_full(self, *offset, out).await?;
91 }
92 Ok(())
93 }
94 }
95
96 fn len_hint(&self) -> Option<u64> {
98 None
99 }
100
101 fn len(&mut self) -> impl Future<Output = Result<u64, BoxedError>> + Send;
104}
105
106async fn read_full<S: AsyncSource + ?Sized>(
109 source: &mut S,
110 offset: u64,
111 out: &mut [u8],
112) -> Result<(), BoxedError> {
113 let mut filled = 0;
114 while filled < out.len() {
115 let n = source
116 .read_at(offset + filled as u64, &mut out[filled..])
117 .await?;
118 if n == 0 {
119 return Err(Box::new(SourceError::UnexpectedEof {
120 offset,
121 len: out.len() as u64,
122 total: Some(offset + filled as u64),
123 }));
124 }
125 filled += n;
126 }
127 Ok(())
128}
129
130#[derive(Debug, Clone)]
132pub struct BytesSource(pub alloc::sync::Arc<[u8]>);
133
134impl AsyncSource for BytesSource {
135 async fn read_at(&mut self, offset: u64, out: &mut [u8]) -> Result<usize, BoxedError> {
136 let start = (offset as usize).min(self.0.len());
137 let n = (self.0.len() - start).min(out.len());
138 out[..n].copy_from_slice(&self.0[start..start + n]);
139 Ok(n)
140 }
141
142 fn len_hint(&self) -> Option<u64> {
143 Some(self.0.len() as u64)
144 }
145
146 async fn len(&mut self) -> Result<u64, BoxedError> {
147 Ok(self.0.len() as u64)
148 }
149}
150
151#[derive(Debug)]
156pub struct AsyncReadSource<R> {
157 reader: R,
158 pos: u64,
159 eof: bool,
160}
161
162impl<R> AsyncReadSource<R> {
163 pub fn new(reader: R) -> Self {
165 Self {
166 reader,
167 pos: 0,
168 eof: false,
169 }
170 }
171}
172
173impl<R: tokio::io::AsyncRead + Unpin + Send> AsyncSource for AsyncReadSource<R> {
174 async fn read_at(&mut self, offset: u64, out: &mut [u8]) -> Result<usize, BoxedError> {
175 use tokio::io::AsyncReadExt;
176 if offset < self.pos {
177 return Err(Box::new(SourceError::BeyondWindow {
178 offset,
179 oldest_retained: self.pos,
180 }));
181 }
182 let mut skip = [0u8; 4096];
183 while self.pos < offset && !self.eof {
184 let want = ((offset - self.pos) as usize).min(skip.len());
185 let n = self.reader.read(&mut skip[..want]).await?;
186 if n == 0 {
187 self.eof = true;
188 }
189 self.pos += n as u64;
190 }
191 if self.eof || out.is_empty() {
192 return Ok(0);
193 }
194 let n = self.reader.read(out).await?;
196 if n == 0 {
197 self.eof = true;
198 }
199 self.pos += n as u64;
200 Ok(n)
201 }
202
203 fn len_hint(&self) -> Option<u64> {
204 self.eof.then_some(self.pos)
205 }
206
207 async fn len(&mut self) -> Result<u64, BoxedError> {
208 if self.eof {
209 Ok(self.pos)
210 } else {
211 Err("a sequential stream cannot report its length before it ends".into())
212 }
213 }
214}
215
216pub type Job = Box<dyn FnOnce() + Send + 'static>;
218
219pub trait Compute: Send + Sync {
224 fn spawn(&self, job: Job);
226
227 fn runs_inline(&self) -> bool {
231 false
232 }
233}
234
235impl<F: Fn(Job) + Send + Sync> Compute for F {
236 fn spawn(&self, job: Job) {
237 self(job)
238 }
239}
240
241#[derive(Debug, Clone, Copy, Default)]
245pub struct Inline;
246
247impl Compute for Inline {
248 fn spawn(&self, job: Job) {
249 job()
250 }
251
252 fn runs_inline(&self) -> bool {
253 true
254 }
255}
256
257fn run_on<C: Compute + ?Sized, T: Send + 'static>(
263 compute: &C,
264 f: impl FnOnce() -> T + Send + 'static,
265) -> impl Future<Output = Result<T, AsyncDriveError<core::convert::Infallible>>> + Send + 'static {
266 let (done, rx) = if compute.runs_inline() {
267 (Some(f()), None)
268 } else {
269 let (tx, rx) = oneshot::channel();
270 compute.spawn(Box::new(move || {
271 let _ = tx.send(f());
272 }));
273 (None, Some(rx))
274 };
275 async move {
276 match (done, rx) {
277 (Some(v), _) => Ok(v),
278 (None, Some(rx)) => rx.await.map_err(|_| AsyncDriveError::Disconnected),
279 (None, None) => Err(AsyncDriveError::Disconnected),
280 }
281 }
282}
283
284#[derive(Debug)]
288#[non_exhaustive]
289pub enum AsyncDriveError<E> {
290 Step(StepError<E>),
292 Source(BoxedError),
294 Write(std::io::Error),
296 Protocol(ProtocolViolation),
298 Input(InputError),
300 Cancelled(StopReason),
302 Disconnected,
305}
306
307fn widen<F>(e: AsyncDriveError<core::convert::Infallible>) -> AsyncDriveError<F> {
309 {
310 match e {
311 AsyncDriveError::Step(s) => match s {
312 StepError::Codec(never) => match never {},
313 StepError::Sink(e) => AsyncDriveError::Step(StepError::Sink(e)),
314 StepError::Cancelled(r) => AsyncDriveError::Step(StepError::Cancelled(r)),
315 StepError::Finished => AsyncDriveError::Step(StepError::Finished),
316 _ => AsyncDriveError::Disconnected,
317 },
318 AsyncDriveError::Source(e) => AsyncDriveError::Source(e),
319 AsyncDriveError::Write(e) => AsyncDriveError::Write(e),
320 AsyncDriveError::Protocol(p) => AsyncDriveError::Protocol(p),
321 AsyncDriveError::Input(e) => AsyncDriveError::Input(e),
322 AsyncDriveError::Cancelled(r) => AsyncDriveError::Cancelled(r),
323 AsyncDriveError::Disconnected => AsyncDriveError::Disconnected,
324 }
325 }
326}
327
328impl<E: fmt::Display> fmt::Display for AsyncDriveError<E> {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 match self {
331 Self::Step(e) => write!(f, "{e}"),
332 Self::Source(e) => write!(f, "source: {e}"),
333 Self::Write(e) => write!(f, "writing output: {e}"),
334 Self::Protocol(e) => write!(f, "protocol: {e}"),
335 Self::Input(e) => write!(f, "input: {e}"),
336 Self::Cancelled(r) => write!(f, "cancelled: {r:?}"),
337 Self::Disconnected => write!(f, "compute job dropped without a result"),
338 }
339 }
340}
341
342impl<E: core::error::Error + 'static> core::error::Error for AsyncDriveError<E> {
343 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
344 match self {
345 Self::Step(e) => Some(e),
346 Self::Source(e) => Some(e.as_ref()),
347 Self::Write(e) => Some(e),
348 Self::Protocol(e) => Some(e),
349 Self::Input(e) => Some(e),
350 _ => None,
351 }
352 }
353}
354
355struct Batch<D: IncrementalDecode, S> {
359 decoder: D,
360 sink: S,
361 window: Window,
362 outcome: Result<BatchEnd, BatchFail<D>>,
363}
364
365enum BatchEnd {
366 Need,
368 Yield,
369 Done(OutputInfo),
370}
371
372enum BatchFail<D: IncrementalDecode> {
373 Step(StepError<D::Error>),
374 Protocol(ProtocolViolation),
375}
376
377fn run_batch<D, S>(
379 mut decoder: D,
380 mut sink: S,
381 mut window: Window,
382 pulse: Option<SharedPulse>,
383 quota: crate::WorkQuota,
384) -> Batch<D, S>
385where
386 D: IncrementalDecode,
387 S: DecodeRowSink,
388{
389 let pulse_ref: Option<&dyn Pulse> = pulse.as_ref().map(|p| p as &dyn Pulse);
390 let mut progress = Progressor::new(pulse_ref);
391 let mut steps = 0usize;
392 let outcome = loop {
393 if steps == quota.max_steps() {
394 break Ok(BatchEnd::Yield);
395 }
396 let input = window.input();
397 let p = match decoder.step(input, &mut sink, pulse_ref) {
398 Ok(p) => p,
399 Err(e) => break Err(BatchFail::Step(e)),
400 };
401 steps += 1;
402 progress.observe(&decoder, &p.event);
403 if p.event == Event::Need
404 && let Err(v) = check_need(decoder.requested(), &input, p.consumed)
405 {
406 break Err(BatchFail::Protocol(v));
407 }
408 window.consume(p.consumed);
409 match p.event {
410 Event::Need => break Ok(BatchEnd::Need),
411 Event::Done(info) => break Ok(BatchEnd::Done(info)),
412 _ => continue,
413 }
414 };
415 Batch {
416 decoder,
417 sink,
418 window,
419 outcome,
420 }
421}
422
423#[allow(clippy::manual_async_fn)]
430fn fill<'a, Src: AsyncSource + ?Sized, E: 'a>(
431 source: &'a mut Src,
432 window: &'a mut Window,
433 fetched: &'a mut Vec<(u64, Vec<u8>)>,
434 requests: &'a [InputRequest],
435 opts: DriveOptions,
436) -> impl Future<Output = Result<(), AsyncDriveError<E>>> + Send + 'a {
437 async move {
438 let limits = opts.limits;
439 let request = admission::select(requests, limits).map_err(AsyncDriveError::Input)?;
440 match request {
441 InputRequest::AtLeast { offset, min_len } => {
442 window.position(offset, fetched);
443 let target = read_target(min_len, opts.read_size)
447 .min(limits.max_input_bytes())
448 .min(usize::try_from(u64::MAX - offset).unwrap_or(usize::MAX));
449 admission::make_room(window, fetched, target, limits);
450 while window.len() < min_len.max(1) && window.total != Some(window.end()) {
451 limits.reading().map_err(AsyncDriveError::Input)?;
452 let end = window.end();
453 let want = (target - window.len().min(target))
454 .min(usize::try_from(u64::MAX - end).unwrap_or(usize::MAX));
455 let spare = window
456 .try_spare(
457 want,
458 limits.max_input_bytes() - admission::capacity(fetched),
459 )
460 .map_err(AsyncDriveError::Input)?;
461 let n = source
462 .read_at(end, spare)
463 .await
464 .map_err(AsyncDriveError::Source)?;
465 window.commit(n);
466 if n == 0 {
467 window.total = Some(end);
468 }
469 }
470 }
471 InputRequest::Range(r) => {
472 if r.offset >= window.base() && r.end() <= window.end() {
473 window.consume((r.offset - window.base()) as usize);
474 return Ok(());
475 }
476 if let Some(i) = fetched
477 .iter()
478 .position(|(off, buf)| r.offset >= *off && r.end() <= off + buf.len() as u64)
479 {
480 let (off, buf) = fetched.swap_remove(i);
481 window.adopt(off, buf);
482 window.consume((r.offset - off) as usize);
483 return Ok(());
484 }
485 if window.position(r.offset, fetched) {
486 let missing = (r.end() - window.end()) as usize;
487 let offset = window.end();
488 limits.reading().map_err(AsyncDriveError::Input)?;
489 admission::make_room(window, fetched, r.length as usize, limits);
490 let spare = window
491 .try_spare(
492 missing,
493 limits.max_input_bytes() - admission::capacity(fetched),
494 )
495 .map_err(AsyncDriveError::Input)?;
496 read_full(source, offset, spare)
497 .await
498 .map_err(AsyncDriveError::Source)?;
499 window.commit(missing);
500 return Ok(());
501 }
502 let mut coalesced = Vec::new();
503 admission::plan(r, requests, opts.max_gap, limits, &mut coalesced)
504 .map_err(AsyncDriveError::Input)?;
505 window.release();
506 let mut pending = core::mem::take(fetched);
507 admission::allocate_ranges(&coalesced, limits, &mut pending)
508 .map_err(AsyncDriveError::Input)?;
509 {
510 let mut reqs = Vec::new();
511 admission::reserve(&mut reqs, pending.len()).map_err(AsyncDriveError::Input)?;
512 reqs.extend(pending.iter_mut().map(|(o, b)| (*o, &mut b[..])));
513 for batch in reqs.chunks_mut(limits.max_in_flight()) {
514 source
515 .read_ranges(batch)
516 .await
517 .map_err(AsyncDriveError::Source)?;
518 }
519 }
520 *fetched = pending;
522 let i = fetched
523 .iter()
524 .position(|(off, buf)| r.offset >= *off && r.end() <= off + buf.len() as u64)
525 .expect("coalesced ranges cover every request");
526 let (off, buf) = fetched.swap_remove(i);
527 window.adopt(off, buf);
528 window.consume((r.offset - off) as usize);
529 }
530 InputRequest::Len => {
531 if window.total.is_none() {
532 limits.reading().map_err(AsyncDriveError::Input)?;
533 window.total = Some(source.len().await.map_err(AsyncDriveError::Source)?);
534 }
535 }
536 _ => return Err(AsyncDriveError::Protocol(ProtocolViolation::EmptyRequest)),
537 }
538 Ok(())
539 }
540}
541
542#[derive(Debug)]
553pub struct AsyncCursor {
554 opts: DriveOptions,
555 window: Window,
556 fetched: Vec<(u64, Vec<u8>)>,
557 started: bool,
558 steps_since_yield: usize,
559}
560
561impl AsyncCursor {
562 pub fn new(opts: DriveOptions) -> Self {
564 Self {
565 opts,
566 window: Window::new(),
567 fetched: Vec::new(),
568 started: false,
569 steps_since_yield: 0,
570 }
571 }
572
573 pub fn retained_input_capacity(&self) -> usize {
575 self.window
576 .capacity()
577 .saturating_add(admission::capacity(&self.fetched))
578 }
579
580 pub async fn next<S, Src>(
583 &mut self,
584 source: &mut Src,
585 stage: &mut S,
586 pulse: Option<&dyn zencodec::Pulse>,
587 ) -> Result<crate::Yield<S::Output>, crate::DriveFailure<S::Error, BoxedError>>
588 where
589 S: crate::ByteStepper + ?Sized,
590 Src: AsyncSource + ?Sized,
591 {
592 use crate::{DriveFailure, Step, Yield};
593 if !self.started {
594 self.started = true;
595 self.window.total = source.len_hint();
596 }
597 loop {
598 if self.steps_since_yield == self.opts.work_quota.max_steps() {
599 crate::work_quota::yield_once().await;
600 self.steps_since_yield = 0;
601 }
602 let input = self.window.input();
603 let p = stage.step(input, pulse).map_err(DriveFailure::Step)?;
604 self.steps_since_yield += 1;
605 if matches!(p.step, Step::Need) {
606 check_need(stage.requested(), &input, p.consumed)
607 .map_err(DriveFailure::Protocol)?;
608 }
609 self.window.consume(p.consumed);
610 match p.step {
611 Step::Output(o) => return Ok(Yield::Output(o)),
612 Step::Finished(o) => return Ok(Yield::Finished(o)),
613 Step::Need => {}
614 }
615 fill::<_, core::convert::Infallible>(
616 source,
617 &mut self.window,
618 &mut self.fetched,
619 stage.requested(),
620 self.opts,
621 )
622 .await
623 .map_err(|e| match e {
624 AsyncDriveError::Source(e) => DriveFailure::Source(e),
625 AsyncDriveError::Protocol(p) => DriveFailure::Protocol(p),
626 AsyncDriveError::Input(e) => DriveFailure::Input(e),
627 _ => DriveFailure::Protocol(ProtocolViolation::EmptyRequest),
629 })?;
630 }
631 }
632}
633
634pub async fn write_pending_async<E, W>(enc: &mut E, w: &mut W) -> std::io::Result<usize>
647where
648 E: Encoder,
649 W: tokio::io::AsyncWrite + Unpin + ?Sized,
650{
651 use tokio::io::AsyncWriteExt as _;
652 let n = enc.pending_output().len();
653 if n > 0 {
654 w.write_all(enc.pending_output()).await?;
655 enc.consume_output(n);
656 }
657 Ok(n)
658}
659
660#[allow(clippy::manual_async_fn)]
670pub fn decode_async<'a, D, S, Src, C>(
671 decoder: D,
672 sink: S,
673 source: &'a mut Src,
674 compute: C,
675 opts: DriveOptions,
676 pulse: Option<SharedPulse>,
677) -> impl Future<Output = Result<(OutputInfo, S), AsyncDriveError<D::Error>>> + Send + 'a
678where
679 D: IncrementalDecode + Send + 'static,
680 S: DecodeRowSink + Send + 'static,
681 Src: AsyncSource + ?Sized,
682 C: Compute + 'a,
683{
684 async move {
685 let mut state = Some((decoder, sink, Window::new()));
686 if let Some((_, _, w)) = state.as_mut() {
687 w.total = source.len_hint();
688 }
689 let mut fetched = Vec::new();
690 let mut requests: Vec<InputRequest> = Vec::new();
691 loop {
692 if let Some(p) = &pulse
693 && let Err(r) = p.check()
694 {
695 return Err(AsyncDriveError::Cancelled(r));
696 }
697 let (decoder, sink, window) = state.take().expect("restored after every batch");
698 let pulse_for_batch = pulse.clone();
699 let batch = run_on(&compute, move || {
700 run_batch(decoder, sink, window, pulse_for_batch, opts.work_quota)
701 })
702 .await
703 .map_err(widen)?;
704 let Batch {
705 decoder,
706 sink,
707 mut window,
708 outcome,
709 } = batch;
710 match outcome {
711 Ok(BatchEnd::Done(info)) => return Ok((info, sink)),
712 Ok(BatchEnd::Yield) => crate::work_quota::yield_once().await,
713 Ok(BatchEnd::Need) => {
714 admission::copy_requests(decoder.requested(), opts.limits, &mut requests)
717 .map_err(AsyncDriveError::Input)?;
718 fill(source, &mut window, &mut fetched, &requests, opts).await?;
719 }
720 Err(BatchFail::Step(e)) => return Err(AsyncDriveError::Step(e)),
721 Err(BatchFail::Protocol(v)) => return Err(AsyncDriveError::Protocol(v)),
722 }
723 state = Some((decoder, sink, window));
724 }
725 }
726}
727
728#[allow(clippy::manual_async_fn)]
745pub fn transcode_async<'a, D, E, Src, W, C>(
746 decoder: D,
747 encoder: E,
748 source: &'a mut Src,
749 out: &'a mut W,
750 compute: C,
751 opts: DriveOptions,
752 pulse: Option<SharedPulse>,
753) -> impl Future<Output = Result<u64, AsyncDriveError<D::Error>>> + Send + 'a
754where
755 D: IncrementalDecode + Send + 'static,
756 E: Encoder + Send + 'static,
757 E::Error: Send + Sync,
758 Src: AsyncSource + ?Sized,
759 W: tokio::io::AsyncWrite + Unpin + Send + ?Sized,
760 C: Compute + 'a,
761{
762 async move {
763 use tokio::io::AsyncWriteExt;
764 let mut written = 0u64;
765 let mut state = Some((decoder, crate::EncoderSink::new(encoder), Window::new()));
766 if let Some((_, _, w)) = state.as_mut() {
767 w.total = source.len_hint();
768 }
769 let mut fetched = Vec::new();
770 let mut requests: Vec<InputRequest> = Vec::new();
771 loop {
772 if let Some(p) = &pulse
773 && let Err(r) = p.check()
774 {
775 return Err(AsyncDriveError::Cancelled(r));
776 }
777 let (decoder, sink, window) = state.take().expect("restored after every batch");
778 let pulse_for_batch = pulse.clone();
779 let batch = run_on(&compute, move || {
780 run_batch(decoder, sink, window, pulse_for_batch, opts.work_quota)
781 })
782 .await
783 .map_err(widen)?;
784 let Batch {
785 decoder,
786 mut sink,
787 mut window,
788 outcome,
789 } = batch;
790 let pending = sink.pending_output().len();
791 if pending > 0 && matches!(outcome, Ok(BatchEnd::Need | BatchEnd::Done(_))) {
792 out.write_all(sink.pending_output())
793 .await
794 .map_err(AsyncDriveError::Write)?;
795 sink.consume_output(pending);
796 written += pending as u64;
797 }
798 match outcome {
799 Ok(BatchEnd::Yield) => crate::work_quota::yield_once().await,
800 Ok(BatchEnd::Done(_)) => {
801 let rest = run_on(&compute, move || sink.finish())
804 .await
805 .map_err(widen)?
806 .map_err(|e| AsyncDriveError::Step(StepError::Sink(Box::new(e))))?;
807 out.write_all(rest.data())
808 .await
809 .map_err(AsyncDriveError::Write)?;
810 out.flush().await.map_err(AsyncDriveError::Write)?;
811 return Ok(written + rest.data().len() as u64);
812 }
813 Ok(BatchEnd::Need) => {
814 admission::copy_requests(decoder.requested(), opts.limits, &mut requests)
817 .map_err(AsyncDriveError::Input)?;
818 fill(source, &mut window, &mut fetched, &requests, opts).await?;
819 }
820 Err(BatchFail::Step(e)) => return Err(AsyncDriveError::Step(e)),
821 Err(BatchFail::Protocol(v)) => return Err(AsyncDriveError::Protocol(v)),
822 }
823 state = Some((decoder, sink, window));
824 }
825 }
826}
827
828enum Attempt<T> {
832 Ready(T),
833 Pending,
834 Closed,
835}
836
837fn wait_with_stop<T>(
843 pulse: Option<&dyn zencodec::Pulse>,
844 mut attempt: impl FnMut() -> Attempt<T>,
845) -> Result<T, AsyncDriveError<core::convert::Infallible>> {
846 let mut sleep = core::time::Duration::from_micros(50);
847 let mut spins = 0u32;
848 loop {
849 match attempt() {
850 Attempt::Ready(v) => return Ok(v),
851 Attempt::Closed => return Err(AsyncDriveError::Disconnected),
852 Attempt::Pending => {}
853 }
854 if let Some(s) = pulse
855 && let Err(reason) = s.check()
856 {
857 return Err(AsyncDriveError::Cancelled(reason));
858 }
859 if spins < 64 {
860 spins += 1;
861 core::hint::spin_loop();
862 } else {
863 std::thread::sleep(sleep);
864 sleep = (sleep * 2).min(core::time::Duration::from_millis(2));
865 }
866 }
867}
868
869enum PullRequest {
871 ReadAt { offset: u64, len: usize },
872 Ranges(Vec<ByteRange>),
873 Len,
874}
875
876enum PullReply {
877 Bytes(Vec<u8>),
878 Ranges(Vec<Vec<u8>>),
879 Len(u64),
880 Failed(BoxedError),
881}
882
883struct Links {
884 requests: mpsc::Sender<PullRequest>,
885 replies: mpsc::Receiver<PullReply>,
886 pulse: Option<SharedPulse>,
887}
888
889impl Links {
890 fn ask(
891 &mut self,
892 req: PullRequest,
893 ) -> Result<PullReply, AsyncDriveError<core::convert::Infallible>> {
894 let pulse: &dyn zencodec::Pulse = match &self.pulse {
895 Some(p) => p,
896 None => &NoPulse,
897 };
898 pulse.check().map_err(AsyncDriveError::Cancelled)?;
899 if self.pulse.is_none() {
900 self.requests
901 .blocking_send(req)
902 .map_err(|_| AsyncDriveError::Disconnected)?;
903 return self
904 .replies
905 .blocking_recv()
906 .ok_or(AsyncDriveError::Disconnected);
907 }
908 let mut slot = Some(req);
909 let tx = &self.requests;
910 wait_with_stop(Some(pulse), || {
911 let Some(r) = slot.take() else {
912 return Attempt::Ready(());
913 };
914 match tx.try_send(r) {
915 Ok(()) => Attempt::Ready(()),
916 Err(mpsc::error::TrySendError::Full(r)) => {
917 slot = Some(r);
918 Attempt::Pending
919 }
920 Err(mpsc::error::TrySendError::Closed(_)) => Attempt::Closed,
921 }
922 })?;
923 let rx = &mut self.replies;
924 wait_with_stop(Some(pulse), || match rx.try_recv() {
925 Ok(reply) => Attempt::Ready(reply),
926 Err(mpsc::error::TryRecvError::Empty) => Attempt::Pending,
927 Err(mpsc::error::TryRecvError::Disconnected) => Attempt::Closed,
928 })
929 }
930}
931
932struct ChannelReadAt {
934 links: Links,
935 len: Option<u64>,
936}
937
938fn bridge_err(e: AsyncDriveError<core::convert::Infallible>) -> BoxedError {
939 Box::new(e.into_infallible_display())
940}
941
942impl AsyncDriveError<core::convert::Infallible> {
943 fn into_infallible_display(self) -> BridgeError {
944 BridgeError(self)
945 }
946}
947
948#[derive(Debug)]
950pub struct BridgeError(pub AsyncDriveError<core::convert::Infallible>);
951
952impl fmt::Display for BridgeError {
953 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954 fmt::Display::fmt(&self.0, f)
955 }
956}
957
958impl core::error::Error for BridgeError {
959 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
960 core::error::Error::source(&self.0)
961 }
962}
963
964impl DynReadAt for ChannelReadAt {
965 fn len(&mut self) -> Result<u64, BoxedError> {
966 if let Some(len) = self.len {
967 return Ok(len);
968 }
969 match self.links.ask(PullRequest::Len).map_err(bridge_err)? {
970 PullReply::Len(len) => {
971 self.len = Some(len);
972 Ok(len)
973 }
974 PullReply::Failed(e) => Err(e),
975 _ => Err("pull bridge: unexpected reply".into()),
976 }
977 }
978
979 fn len_hint(&self) -> Option<u64> {
980 self.len
981 }
982
983 fn read_at(&mut self, offset: u64, out: &mut [u8]) -> Result<usize, BoxedError> {
984 match self
985 .links
986 .ask(PullRequest::ReadAt {
987 offset,
988 len: out.len(),
989 })
990 .map_err(bridge_err)?
991 {
992 PullReply::Bytes(b) => {
993 out[..b.len()].copy_from_slice(&b);
994 if b.len() < out.len() {
995 self.len = Some(offset + b.len() as u64);
996 }
997 Ok(b.len())
998 }
999 PullReply::Failed(e) => Err(e),
1000 _ => Err("pull bridge: unexpected reply".into()),
1001 }
1002 }
1003
1004 fn read_exact_at(&mut self, offset: u64, out: &mut [u8]) -> Result<(), BoxedError> {
1005 let n = self.read_at(offset, out)?;
1006 if n < out.len() {
1007 return Err(Box::new(SourceError::UnexpectedEof {
1008 offset,
1009 len: out.len() as u64,
1010 total: self.len,
1011 }));
1012 }
1013 Ok(())
1014 }
1015
1016 fn read_many_at(&mut self, reqs: &mut [(u64, &mut [u8])]) -> Result<(), BoxedError> {
1017 let ranges = reqs
1018 .iter()
1019 .map(|(o, b)| ByteRange::new(*o, b.len() as u64))
1020 .collect();
1021 match self
1022 .links
1023 .ask(PullRequest::Ranges(ranges))
1024 .map_err(bridge_err)?
1025 {
1026 PullReply::Ranges(bufs) => {
1027 for ((_, out), b) in reqs.iter_mut().zip(bufs) {
1028 out.copy_from_slice(&b);
1029 }
1030 Ok(())
1031 }
1032 PullReply::Failed(e) => Err(e),
1033 _ => Err("pull bridge: unexpected reply".into()),
1034 }
1035 }
1036}
1037
1038#[allow(clippy::manual_async_fn)]
1051pub fn pull_decode_on_thread<'a, R, S, Src, C>(
1052 run: R,
1053 mut sink: S,
1054 source: &'a mut Src,
1055 compute: C,
1056 pulse: Option<SharedPulse>,
1057) -> impl Future<Output = Result<(OutputInfo, S), AsyncDriveError<BoxedError>>> + Send + 'a
1058where
1059 R: FnOnce(&mut dyn DynReadAt, &mut dyn DecodeRowSink) -> Result<OutputInfo, BoxedError>
1060 + Send
1061 + 'static,
1062 S: DecodeRowSink + Send + 'static,
1063 Src: AsyncSource + ?Sized,
1064 C: Compute + 'a,
1065{
1066 async move {
1067 let (req_tx, mut req_rx) = mpsc::channel(1);
1068 let (rep_tx, rep_rx) = mpsc::channel(1);
1069 let (done_tx, mut done_rx) = oneshot::channel();
1070 let mut reader = ChannelReadAt {
1071 links: Links {
1072 requests: req_tx,
1073 replies: rep_rx,
1074 pulse,
1075 },
1076 len: source.len_hint(),
1077 };
1078 compute.spawn(Box::new(move || {
1079 let result = run(&mut reader, &mut sink);
1080 drop(reader);
1081 let _ = done_tx.send(result.map(|info| (info, sink)));
1082 }));
1083 let finish = |done: Result<
1084 Result<(OutputInfo, S), BoxedError>,
1085 oneshot::error::RecvError,
1086 >| match done {
1087 Ok(Ok(v)) => Ok(v),
1088 Ok(Err(e)) => match e.downcast::<BridgeError>() {
1089 Ok(b) => Err(widen(b.0)),
1090 Err(e) => Err(AsyncDriveError::Step(StepError::Codec(e))),
1091 },
1092 Err(_) => Err(AsyncDriveError::Disconnected),
1093 };
1094 let mut requests_open = true;
1095 loop {
1096 let req = tokio::select! {
1100 biased;
1101 done = &mut done_rx => return finish(done),
1102 req = req_rx.recv(), if requests_open => req,
1103 };
1104 let Some(req) = req else {
1105 requests_open = false;
1106 continue;
1107 };
1108 let reply = tokio::select! {
1109 biased;
1110 done = &mut done_rx => return finish(done),
1111 reply = serve_pull(source, req) => reply,
1112 };
1113 let _ = rep_tx.send(reply).await;
1116 }
1117 }
1118}
1119
1120async fn serve_pull<Src: AsyncSource + ?Sized>(source: &mut Src, req: PullRequest) -> PullReply {
1122 match req {
1123 PullRequest::ReadAt { offset, len } => {
1124 let mut buf = vec![0u8; len];
1127 let mut filled = 0;
1128 while filled < len {
1129 match source
1130 .read_at(offset + filled as u64, &mut buf[filled..])
1131 .await
1132 {
1133 Ok(0) => break,
1134 Ok(n) => filled += n,
1135 Err(e) => return PullReply::Failed(e),
1136 }
1137 }
1138 buf.truncate(filled);
1139 PullReply::Bytes(buf)
1140 }
1141 PullRequest::Ranges(ranges) => {
1142 let mut bufs: Vec<Vec<u8>> = ranges
1143 .iter()
1144 .map(|r| vec![0u8; r.length as usize])
1145 .collect();
1146 let result = {
1147 let mut reqs: Vec<(u64, &mut [u8])> = ranges
1148 .iter()
1149 .zip(bufs.iter_mut())
1150 .map(|(r, b)| (r.offset, &mut b[..]))
1151 .collect();
1152 source.read_ranges(&mut reqs).await
1153 };
1154 match result {
1155 Ok(()) => PullReply::Ranges(bufs),
1156 Err(e) => PullReply::Failed(e),
1157 }
1158 }
1159 PullRequest::Len => match source.len().await {
1160 Ok(n) => PullReply::Len(n),
1161 Err(e) => PullReply::Failed(e),
1162 },
1163 }
1164}
1165
1166#[derive(Debug)]
1170#[non_exhaustive]
1171pub enum StripEvent {
1172 Begin {
1174 width: u32,
1176 height: u32,
1178 descriptor: PixelDescriptor,
1180 },
1181 Strip {
1183 meta: BatchMeta,
1185 pixels: PixelBuffer,
1187 },
1188 Finish,
1190}
1191
1192pub struct ChannelRowSink {
1203 tx: mpsc::Sender<StripEvent>,
1204 current: Option<(BatchMeta, PixelBuffer)>,
1205 provisional: bool,
1206 pulse: Option<SharedPulse>,
1207}
1208
1209impl fmt::Debug for ChannelRowSink {
1210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1211 f.debug_struct("ChannelRowSink")
1212 .field("provisional", &self.provisional)
1213 .field("pulse", &self.pulse.is_some())
1214 .finish_non_exhaustive()
1215 }
1216}
1217
1218impl ChannelRowSink {
1219 pub fn new(tx: mpsc::Sender<StripEvent>, provisional: bool) -> Self {
1222 Self {
1223 tx,
1224 current: None,
1225 provisional,
1226 pulse: None,
1227 }
1228 }
1229
1230 pub fn with_pulse(mut self, pulse: SharedPulse) -> Self {
1233 self.pulse = Some(pulse);
1234 self
1235 }
1236
1237 fn send(&self, event: StripEvent) -> Result<(), SinkError> {
1238 match &self.pulse {
1239 None => self
1240 .tx
1241 .blocking_send(event)
1242 .map_err(|_| SinkError::from("strip consumer went away")),
1243 Some(pulse) => {
1244 let pulse: &dyn zencodec::Pulse = pulse;
1245 let mut slot = Some(event);
1246 wait_with_stop(Some(pulse), || {
1247 let Some(ev) = slot.take() else {
1248 return Attempt::Ready(());
1249 };
1250 match self.tx.try_send(ev) {
1251 Ok(()) => Attempt::Ready(()),
1252 Err(mpsc::error::TrySendError::Full(ev)) => {
1253 slot = Some(ev);
1254 Attempt::Pending
1255 }
1256 Err(mpsc::error::TrySendError::Closed(_)) => Attempt::Closed,
1257 }
1258 })
1259 .map_err(|e| SinkError::from(alloc::format!("{e}")))
1260 }
1261 }
1262 }
1263
1264 fn ship(&mut self) -> Result<(), SinkError> {
1265 if let Some((meta, pixels)) = self.current.take() {
1266 self.send(StripEvent::Strip { meta, pixels })?;
1267 }
1268 Ok(())
1269 }
1270
1271 fn strip(
1272 &mut self,
1273 meta: BatchMeta,
1274 height: u32,
1275 width: u32,
1276 descriptor: PixelDescriptor,
1277 ) -> Result<PixelSliceMut<'_>, SinkError> {
1278 self.ship()?;
1279 let (_, pixels) = self
1280 .current
1281 .insert((meta, PixelBuffer::new(width, height, descriptor)));
1282 Ok(pixels.as_slice_mut())
1283 }
1284}
1285
1286impl DecodeRowSink for ChannelRowSink {
1287 fn begin(
1288 &mut self,
1289 width: u32,
1290 height: u32,
1291 descriptor: PixelDescriptor,
1292 ) -> Result<(), SinkError> {
1293 self.send(StripEvent::Begin {
1294 width,
1295 height,
1296 descriptor,
1297 })
1298 }
1299
1300 fn provide_next_buffer(
1301 &mut self,
1302 y: u32,
1303 height: u32,
1304 width: u32,
1305 descriptor: PixelDescriptor,
1306 ) -> Result<PixelSliceMut<'_>, SinkError> {
1307 self.strip(BatchMeta::final_rows(y), height, width, descriptor)
1308 }
1309
1310 fn accepts_provisional(&self) -> bool {
1311 self.provisional
1312 }
1313
1314 fn provide_pass_buffer(
1315 &mut self,
1316 meta: BatchMeta,
1317 height: u32,
1318 width: u32,
1319 descriptor: PixelDescriptor,
1320 ) -> Result<PixelSliceMut<'_>, SinkError> {
1321 self.strip(meta, height, width, descriptor)
1322 }
1323
1324 fn finish(&mut self) -> Result<(), SinkError> {
1325 self.ship()?;
1326 self.send(StripEvent::Finish)
1327 }
1328}