multipart_write/
lib.rs

1//! # Description
2//!
3//! This crate contains the trait `MultipartWrite`, assorted implementations,
4//! and combinators.
5//!
6//! A `MultipartWrite` is a similar interface to [`Sink`], except that writing
7//! an item or completing the write both return values.
8//!
9//! See a conceptual example of a `MultipartWrite` [here][example].
10//!
11//! # Motivation
12//!
13//! `Sink` is a useful API, but it is just that--a sink.  The end of a stream.
14//! It's useful to have the backpressure mechanism that `poll_ready`/`start_send`
15//! enables while being able to act as a stream itself and produce items that
16//! can be forwarded for more processing.
17//!
18//! [example]: https://github.com/quasi-coherent/multipart-write/blob/2cfd8bab323132ba3c0caa9f31b33b45d9faf8c1/examples/author.rs
19//! [`Sink`]: https://docs.rs/crate/futures-sink/0.3.31
20#![cfg_attr(docsrs, feature(doc_cfg))]
21use std::ops::DerefMut;
22use std::pin::Pin;
23use std::task::{Context, Poll};
24
25pub mod io;
26pub mod stream;
27pub mod write;
28
29/// A prelude for this crate.
30pub mod prelude {
31    pub use super::stream::{self, MultipartStreamExt as _};
32    pub use super::write::{self, MultipartWriteExt as _};
33    pub use super::{FusedMultipartWrite, MultipartWrite};
34}
35
36/// `MultipartWrite` is a `Sink`-like interface for asynchronously writing an
37/// object in parts.
38pub trait MultipartWrite<Part> {
39    /// The type of value returned when writing the part began successfully.
40    type Ret;
41
42    /// The type of value returned when all parts are written.
43    type Output;
44
45    /// The type of value returned when an operation fails.
46    type Error;
47
48    /// Attempts to prepare the `MultipartWrite` to receive a new part.
49    ///
50    /// This method must be called and return `Poll::Ready` before each call to
51    /// `start_send`, indicating that the underlying writer is ready to have
52    /// another part written to it.
53    ///
54    /// This method returns `Poll::Pending` when the object being prepared cannot
55    /// accept another part.
56    ///
57    /// In most cases, if the writer encounters an error, it will be permanently
58    /// unable to write more parts.
59    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
60
61    /// Begin the process of writing a part to this writer, returning the
62    /// associated type confirming this was done successfully.
63    ///
64    /// Like `Sink`, this should be preceded by a call to `poll_ready` that
65    /// returns `Poll::Ready` to ensure that the `MultipartWrite` is ready to
66    /// receive a new part.
67    ///
68    /// # Errors
69    ///
70    /// Errors returned by this method are implementation-specific, but it is
71    /// always an error to call `start_send` when `poll_ready` would return
72    /// `Poll::Pending`.
73    ///
74    /// In most cases, if the writer encounters an error, it will be permanently
75    /// unable to write more parts.
76    fn start_send(self: Pin<&mut Self>, part: Part) -> Result<Self::Ret, Self::Error>;
77
78    /// Flush any remaining output from the writer.
79    ///
80    /// Returns `Poll::Ready` when no buffered, unwritten parts remain and
81    /// `Poll::Pending` if there is more work left to do.
82    ///
83    /// In most cases, if the writer encounters an error, it will be permanently
84    /// unable to write more parts.
85    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
86
87    /// Complete this writer, returning the output.
88    ///
89    /// This method returns `Poll::Pending` until no buffered, unwritten parts
90    /// remain and the complete output object is available.
91    ///
92    /// In most cases, if the writer encounters an error, it will be permanently
93    /// unable to write more parts.
94    fn poll_complete(
95        self: Pin<&mut Self>,
96        cx: &mut Context<'_>,
97    ) -> Poll<Result<Self::Output, Self::Error>>;
98}
99
100/// An owned, dynamically typed [`MultipartWrite`] for use in cases where it is
101/// not possible or desirable to statically type it.
102pub type BoxMultipartWrite<'a, Part, R, T, E> =
103    Pin<Box<dyn MultipartWrite<Part, Ret = R, Output = T, Error = E> + Send + 'a>>;
104
105/// `BoxMultipartWrite` but without the `Send` requirement.
106pub type LocalBoxMultipartWrite<'a, Part, R, T, E> =
107    Pin<Box<dyn MultipartWrite<Part, Ret = R, Output = T, Error = E> + 'a>>;
108
109/// A writer that tracks whether or not the underlying writer should no longer
110/// be polled.
111pub trait FusedMultipartWrite<Part>: MultipartWrite<Part> {
112    /// Returns `true` if the writer should no longer be polled.
113    fn is_terminated(&self) -> bool;
114}
115
116impl<W: ?Sized + MultipartWrite<Part> + Unpin, Part> MultipartWrite<Part> for &mut W {
117    type Ret = W::Ret;
118    type Output = W::Output;
119    type Error = W::Error;
120
121    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
122        Pin::new(&mut **self).poll_ready(cx)
123    }
124
125    fn start_send(mut self: Pin<&mut Self>, part: Part) -> Result<Self::Ret, Self::Error> {
126        Pin::new(&mut **self).start_send(part)
127    }
128
129    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
130        Pin::new(&mut **self).poll_flush(cx)
131    }
132
133    fn poll_complete(
134        mut self: Pin<&mut Self>,
135        cx: &mut Context<'_>,
136    ) -> Poll<Result<Self::Output, Self::Error>> {
137        Pin::new(&mut **self).poll_complete(cx)
138    }
139}
140
141impl<W: ?Sized + FusedMultipartWrite<Part> + Unpin, Part> FusedMultipartWrite<Part> for &mut W {
142    fn is_terminated(&self) -> bool {
143        <W as FusedMultipartWrite<Part>>::is_terminated(&**self)
144    }
145}
146
147impl<P, Part> MultipartWrite<Part> for Pin<P>
148where
149    P: DerefMut + Unpin,
150    P::Target: MultipartWrite<Part>,
151{
152    type Ret = <P::Target as MultipartWrite<Part>>::Ret;
153    type Output = <P::Target as MultipartWrite<Part>>::Output;
154    type Error = <P::Target as MultipartWrite<Part>>::Error;
155
156    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
157        self.get_mut().as_mut().poll_ready(cx)
158    }
159
160    fn start_send(self: Pin<&mut Self>, part: Part) -> Result<Self::Ret, Self::Error> {
161        self.get_mut().as_mut().start_send(part)
162    }
163
164    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
165        self.get_mut().as_mut().poll_flush(cx)
166    }
167
168    fn poll_complete(
169        self: Pin<&mut Self>,
170        cx: &mut Context<'_>,
171    ) -> Poll<Result<Self::Output, Self::Error>> {
172        self.get_mut().as_mut().poll_complete(cx)
173    }
174}
175
176impl<P, Part> FusedMultipartWrite<Part> for Pin<P>
177where
178    P: DerefMut + Unpin,
179    P::Target: FusedMultipartWrite<Part>,
180{
181    fn is_terminated(&self) -> bool {
182        <P::Target as FusedMultipartWrite<Part>>::is_terminated(&**self)
183    }
184}