Skip to main content

base_http/body/
mod.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4//! Native HTTP bodies, following `Protocol::HTTP::Body`.
5//!
6//! [`ReadableBody`] combines synchronous observations and abandonment with
7//! asynchronous frame reads using explicit cancellation. I/O-backed
8//! implementations retain explicitly constructed scheduler-bound capabilities.
9//!
10//! Body length describes the whole representation. It does not decrease as chunks
11//! are consumed, and a [`HeadBody`] body may report a nonzero length while emitting no
12//! data. Reads move owned [`BodyFrame`] events, including trailing fields and
13//! completion. An empty data chunk is distinct from completion.
14//!
15//! [`BodyReader`] and [`BodyWriter`] are bounded consumer/producer halves.
16//! A protocol driver pulls data directly; bodies do not spawn tasks.
17use base_scheduler::Cancellation;
18use std::future::Future;
19
20mod buffered;
21mod empty;
22mod error;
23mod frame;
24mod head;
25mod writable;
26
27pub use buffered::BufferedBody;
28pub use empty::EmptyBody;
29pub use error::BodyError;
30pub use frame::BodyFrame;
31pub use head::HeadBody;
32pub use writable::{BodyReader, BodyWriter};
33
34/// Protocol-independent body observations and lifecycle.
35///
36/// No observation performs I/O or requires a scheduler. Readiness, exhaustion,
37/// known representation length and rewindability are independent properties.
38pub trait ReadableBody: Send {
39    /// Application data, without imposing completion-I/O buffer requirements.
40    type Data: AsRef<[u8]> + Send;
41    type Error: std::error::Error + Send + Sync + 'static;
42
43    /// Whether another read can proceed without waiting for produced data.
44    ///
45    /// This is a conservative batching hint. Terminal completion/error can also
46    /// be ready. It does not promise that an I/O operation will finish in one poll.
47    fn is_ready(&self) -> bool {
48        false
49    }
50
51    /// Whether no unread payload frames remain. False can mean unknown; an open
52    /// queue with no frames is not exhausted. This does not suppress read errors.
53    fn is_empty(&self) -> bool {
54        false
55    }
56
57    /// Total representation length, independent of the current read position.
58    fn length(&self) -> Option<u64> {
59        None
60    }
61
62    /// Whether this body can emit trailing headers. HTTP/1 needs this before
63    /// reading to choose chunked framing, even when the data length is known.
64    /// Returning false promises that no Headers frame will be produced.
65    fn may_have_trailers(&self) -> bool {
66        true
67    }
68
69    fn is_rewindable(&self) -> bool {
70        false
71    }
72
73    /// Restore the read position when supported, reporting success.
74    fn rewind(&mut self) -> bool {
75        false
76    }
77
78    /// Abandon further application reads, optionally reporting their failure.
79    ///
80    /// This synchronous operation does not guarantee asynchronous resource
81    /// retirement. An I/O-backed implementation must leave cleanup with an
82    /// explicit resource/driver owner. Cancelling or dropping a read does not
83    /// prove that backend access ended, nor that a connection can be reused.
84    fn close(&mut self, error: Option<Self::Error>);
85
86    /// Read one owned frame. Pre-cancellation prevents consumption. The caller
87    /// stops after `frame.is_end()`; subsequent reads return `BodyFrame::End`.
88    /// Headers occur at most once, after all data. Dropping a pending read is
89    /// not transport retirement, and must not lose an unreturned queued frame.
90    fn read(
91        &mut self,
92        cancellation: &Cancellation,
93    ) -> impl Future<Output = Result<BodyFrame<Self::Data>, Self::Error>> + Send;
94}
95impl<R: ReadableBody + ?Sized> ReadableBody for &mut R {
96    type Data = R::Data;
97    type Error = R::Error;
98
99    fn is_ready(&self) -> bool {
100        (**self).is_ready()
101    }
102    fn is_empty(&self) -> bool {
103        (**self).is_empty()
104    }
105    fn length(&self) -> Option<u64> {
106        (**self).length()
107    }
108    fn may_have_trailers(&self) -> bool {
109        (**self).may_have_trailers()
110    }
111    fn is_rewindable(&self) -> bool {
112        (**self).is_rewindable()
113    }
114    fn rewind(&mut self) -> bool {
115        (**self).rewind()
116    }
117    fn close(&mut self, error: Option<Self::Error>) {
118        (**self).close(error)
119    }
120
121    async fn read(
122        &mut self,
123        cancellation: &Cancellation,
124    ) -> Result<BodyFrame<Self::Data>, Self::Error> {
125        (**self).read(cancellation).await
126    }
127}
128
129/// A body producer accepting owned frames with backpressure.
130/// Normal closure preserves accepted frames; failure abandons unfinished output.
131/// Flushing exposes accepted frames to the consumer, without promising peer receipt.
132pub trait WritableBody: Send {
133    type Data: AsRef<[u8]> + Send;
134    type Error: std::error::Error + Send + Sync + 'static;
135
136    /// Accept one whole frame. Headers follow all data; a terminal frame closes
137    /// output atomically with acceptance. Later writes fail. Queue capacity
138    /// becoming available does not mean the transport has released its buffers.
139    fn write_frame(
140        &mut self,
141        frame: BodyFrame<Self::Data>,
142        cancellation: &Cancellation,
143    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
144
145    /// Write a nonfinal data frame. Use `write_frame` to carry fields or end.
146    fn write(
147        &mut self,
148        data: Self::Data,
149        cancellation: &Cancellation,
150    ) -> impl Future<Output = Result<(), Self::Error>> + Send {
151        self.write_frame(BodyFrame::Data { data, end: false }, cancellation)
152    }
153    fn flush(
154        &mut self,
155        cancellation: &Cancellation,
156    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
157    fn close_write(&mut self, error: Option<Self::Error>);
158    fn abort(&mut self);
159}
160
161impl<W: WritableBody + ?Sized> WritableBody for &mut W {
162    type Data = W::Data;
163    type Error = W::Error;
164    async fn write_frame(
165        &mut self,
166        frame: BodyFrame<Self::Data>,
167        cancellation: &Cancellation,
168    ) -> Result<(), Self::Error> {
169        (**self).write_frame(frame, cancellation).await
170    }
171    async fn write(
172        &mut self,
173        data: Self::Data,
174        cancellation: &Cancellation,
175    ) -> Result<(), Self::Error> {
176        (**self).write(data, cancellation).await
177    }
178    async fn flush(&mut self, cancellation: &Cancellation) -> Result<(), Self::Error> {
179        (**self).flush(cancellation).await
180    }
181    fn close_write(&mut self, error: Option<Self::Error>) {
182        (**self).close_write(error)
183    }
184    fn abort(&mut self) {
185        (**self).abort()
186    }
187}