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}