ringline_http/streaming.rs
1//! Streaming response types for incremental body delivery.
2
3use bytes::Bytes;
4
5use crate::error::HttpError;
6use crate::h1_conn::H1StreamingResponse;
7use crate::h2_conn::H2StreamingResponse;
8
9/// A streaming HTTP response that yields body chunks incrementally.
10///
11/// Wraps either an HTTP/2 or HTTP/1.1 streaming response. The connection
12/// is borrowed exclusively while this type exists — no other requests can
13/// be sent until the body is fully consumed or the response is dropped.
14///
15/// # Example
16///
17/// ```rust,ignore
18/// let mut stream = client.post("/v1/chat/completions")
19/// .header("content-type", "application/json")
20/// .body(payload)
21/// .send_streaming()
22/// .await?;
23///
24/// assert_eq!(stream.status(), 200);
25/// while let Some(chunk) = stream.next_chunk().await? {
26/// // process each body chunk as it arrives
27/// }
28/// ```
29pub enum StreamingResponse<'a> {
30 H2(H2StreamingResponse<'a>),
31 H1(H1StreamingResponse<'a>),
32}
33
34impl StreamingResponse<'_> {
35 /// HTTP status code.
36 pub fn status(&self) -> u16 {
37 match self {
38 Self::H2(s) => s.status(),
39 Self::H1(s) => s.status(),
40 }
41 }
42
43 /// Response headers as (name, value) pairs.
44 pub fn headers(&self) -> &[(String, String)] {
45 match self {
46 Self::H2(s) => s.headers(),
47 Self::H1(s) => s.headers(),
48 }
49 }
50
51 /// Get the first header value matching `name` (case-insensitive).
52 pub fn header(&self, name: &str) -> Option<&str> {
53 match self {
54 Self::H2(s) => s.header(name),
55 Self::H1(s) => s.header(name),
56 }
57 }
58
59 /// Yield the next body chunk, or `None` when the body is complete.
60 pub async fn next_chunk(&mut self) -> Result<Option<Bytes>, HttpError> {
61 match self {
62 Self::H2(s) => s.next_chunk().await,
63 Self::H1(s) => s.next_chunk().await,
64 }
65 }
66}