Skip to main content

yeti_types/resource/
response_body.rs

1//! `ResponseBody` — complete / streaming / subscription responses.
2
3use bytes::Bytes;
4use futures::stream::Stream;
5use std::pin::Pin;
6
7use super::realtime::Subscription;
8use crate::content_type::ContentType;
9use crate::error::Result;
10
11/// Response body — complete or streaming.
12pub enum ResponseBody {
13    /// Complete response body
14    Complete(Vec<u8>),
15    /// Streaming response body (for large datasets)
16    Stream(Pin<Box<dyn Stream<Item = Result<Bytes>> + Send>>),
17    /// Real-time subscription tagged with the negotiated streaming format
18    /// (`Sse`, `GrpcWeb`, …). The HTTP layer looks the format up in its
19    /// subscription-encoder registry to produce the wire response — the
20    /// format travels as a type, not a re-parsed `Content-Type` header.
21    Subscription(Subscription, ContentType),
22}
23
24impl std::fmt::Debug for ResponseBody {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            Self::Complete(data) => f
28                .debug_tuple("Complete")
29                .field(&format!("{} bytes", data.len()))
30                .finish(),
31            Self::Stream(_) => f.debug_tuple("Stream").field(&"<stream>").finish(),
32            Self::Subscription(_, format) => f
33                .debug_tuple("Subscription")
34                .field(&"<subscription>")
35                .field(format)
36                .finish(),
37        }
38    }
39}
40
41impl ResponseBody {
42    /// Create a complete response body.
43    #[must_use]
44    pub const fn complete(data: Vec<u8>) -> Self {
45        Self::Complete(data)
46    }
47
48    /// Create a streaming response body.
49    pub fn stream<S>(stream: S) -> Self
50    where
51        S: Stream<Item = Result<Bytes>> + Send + 'static,
52    {
53        Self::Stream(Box::pin(stream))
54    }
55
56    /// Create a subscription response body tagged with the negotiated
57    /// streaming format the HTTP layer should encode it as.
58    #[must_use]
59    pub const fn subscription(sub: Subscription, format: ContentType) -> Self {
60        Self::Subscription(sub, format)
61    }
62
63    /// Extract bytes from a Complete response body.
64    #[must_use]
65    pub fn into_bytes(self) -> Option<Vec<u8>> {
66        match self {
67            Self::Complete(data) => Some(data),
68            Self::Stream(_) | Self::Subscription(..) => None,
69        }
70    }
71
72    /// Get reference to bytes from a Complete response body.
73    #[must_use]
74    pub const fn as_bytes(&self) -> Option<&[u8]> {
75        match self {
76            Self::Complete(data) => Some(data.as_slice()),
77            Self::Stream(_) | Self::Subscription(..) => None,
78        }
79    }
80}