pdk_classy/hl/
entity.rs

1// Copyright (c) 2025, Salesforce, Inc.,
2// All rights reserved.
3// For full license text, see the LICENSE.txt file
4
5use std::future::Future;
6
7use futures::Stream;
8
9/// A handler for accessing the headers of the current HTTP Flow.
10pub trait HeadersHandler {
11    /// Returns a list of headers represented by pairs of name and value.
12    fn headers(&self) -> Vec<(String, String)>;
13
14    /// Returns a header by `name` if it exists.
15    fn header(&self, name: &str) -> Option<String>;
16
17    /// Adds a header `value` by `name`.
18    /// If there is a header with the same `name`, this method will keep that and adding another
19    /// header entry with the same `name` and the new `value`.
20    fn add_header(&self, name: &str, value: &str);
21
22    /// Sets a header `value` by `name`.
23    /// If there is a header with the same `name`, this method will replace the header `value`.
24    fn set_header(&self, name: &str, value: &str);
25
26    /// Sets a list of headers represented by pairs of name and value.
27    fn set_headers(&self, headers: Vec<(&str, &str)>);
28
29    /// Removes a header by `name` if it exists.
30    fn remove_header(&self, name: &str);
31}
32
33/// The error for [`BodyHandler`] operations.
34#[derive(Clone, PartialEq, Eq, Debug, thiserror::Error)]
35pub enum BodyError {
36    /// The current HTTP Flow does not have a body.
37    #[error("Body not sent")]
38    BodyNotSent,
39
40    /// The body size exceeds what the low-level host allows.
41    #[error("Exceeded body size: {0}")]
42    ExceededBodySize(usize),
43}
44
45/// A handler for accessing the body of the current HTTP Flow.
46pub trait BodyHandler {
47    /// Returns the body of the current HTTP Flow.
48    fn body(&self) -> Vec<u8>;
49
50    /// Sets the `body` of the current HTTP Flow in binary format.
51    ///
52    /// # Errors
53    ///
54    /// This method will return an error in the following situations, but is not
55    /// limited to just these cases:
56    ///
57    /// * The current HTTP Flow does not have a body and it can not be injected.
58    /// * The `body` size exceeds what the low-level host allows.
59    fn set_body(&self, body: &[u8]) -> Result<(), BodyError>;
60}
61
62/// A handler for accessing the headers and body of the current HTTP Flow.
63pub trait HeadersBodyHandler: HeadersHandler + BodyHandler {}
64
65/// Abstract state of the HTTP Flow state-machine allowed to be moved into the Body state.
66pub trait IntoBodyState {
67    /// Concrete type for Body state of the Flow state-machine.
68    type BodyState: BodyState;
69
70    /// A [`Future`] that will be completed when the Body state is reached.
71    type BodyStateFuture: Future<Output = Self::BodyState>;
72
73    /// Moves the current state into the Body state of the HTTP Flow state-machine.
74    /// The [`Future`] returned by this method can be cancelled.
75    #[must_use]
76    fn into_body_state(self) -> Self::BodyStateFuture;
77}
78
79pub trait IntoBodyStreamState {
80    type BodyStreamState: BodyStreamState;
81    type BodyStreamStateFuture: Future<Output = Self::BodyStreamState>;
82
83    #[must_use]
84    fn into_body_stream_state(self) -> Self::BodyStreamStateFuture;
85}
86
87#[cfg(feature = "experimental_enable_stop_iteration")]
88/// Abstract state of the HTTP Flow state-machine allowed to be moved into the HeadersBody state.
89pub trait IntoHeadersBodyState {
90    /// Concrete type for HeadersBody state of the Flow state-machine.
91    type HeadersBodyState: HeadersBodyState;
92
93    /// A [`Future`] that will be completed when the HeadersBody state is reached.
94    type HeadersBodyStateFuture: Future<Output = Self::HeadersBodyState>;
95
96    /// Moves the current state into the HeadersBody state of the HTTP Flow state-machine.
97    /// The [`Future`] returned by this method can be cancelled.
98    #[must_use]
99    fn into_headers_body_state(self) -> Self::HeadersBodyStateFuture;
100}
101
102#[cfg(feature = "experimental_enable_stop_iteration")]
103/// Abstract initial state of the HTTP Flow state-machine.
104pub trait EntityState: IntoBodyState + IntoBodyStreamState + IntoHeadersBodyState {
105    /// Concrete type for Headers state of the Flow state-machine.
106    type HeadersState: HeadersState;
107
108    /// A [`Future`] that will be completed when the Headers state is reached.
109    type HeadersStateFuture: Future<Output = Self::HeadersState>;
110
111    /// Moves the current initial state into the Headers state of the HTTP Flow state-machine.
112    /// The [`Future`] returned by this method can be cancelled.
113    #[must_use]
114    fn into_headers_state(self) -> Self::HeadersStateFuture;
115}
116
117#[cfg(feature = "experimental_enable_stop_iteration")]
118/// Abstract Headers state of the HTTP Flow state-machine.
119pub trait HeadersState: IntoBodyState + IntoBodyStreamState + IntoHeadersBodyState {
120    /// Returns a handler for accessing the headers of the current HTTP Flow.
121    fn handler(&self) -> &dyn HeadersHandler;
122
123    /// Returns [`true`] if the current HTTP Flow contains body.
124    fn contains_body(&self) -> bool;
125}
126
127#[cfg(not(feature = "experimental_enable_stop_iteration"))]
128/// Abstract initial state of the HTTP Flow state-machine.
129pub trait EntityState: IntoBodyState + IntoBodyStreamState {
130    /// Concrete type for Headers state of the Flow state-machine.
131    type HeadersState: HeadersState;
132
133    /// A [`Future`] that will be completed when the Headers state is reached.
134    type HeadersStateFuture: Future<Output = Self::HeadersState>;
135
136    /// Moves the current initial state into the Headers state of the HTTP Flow state-machine.
137    /// The [`Future`] returned by this method can be cancelled.
138    #[must_use]
139    fn into_headers_state(self) -> Self::HeadersStateFuture;
140}
141
142#[cfg(not(feature = "experimental_enable_stop_iteration"))]
143/// Abstract Headers state of the HTTP Flow state-machine.
144pub trait HeadersState: IntoBodyState + IntoBodyStreamState {
145    /// Returns a handler for accessing the headers of the current HTTP Flow.
146    fn handler(&self) -> &dyn HeadersHandler;
147
148    /// Returns [`true`] if the current HTTP Flow contains body.
149    fn contains_body(&self) -> bool;
150}
151
152/// Abstract Body state of the HTTP Flow state-machine.
153pub trait BodyState {
154    /// Returns a handler for accessing the body of the current HTTP Flow.
155    fn handler(&self) -> &dyn BodyHandler;
156
157    /// Returns [`true`] if the current HTTP Flow contains body.
158    fn contains_body(&self) -> bool;
159}
160
161/// Abstract HeadersBody state of the HTTP Flow state-machine.
162pub trait HeadersBodyState {
163    /// Returns a handler for accessing the headers and body of the current HTTP Flow.
164    fn handler(&self) -> &dyn HeadersBodyHandler;
165
166    /// Returns [`true`] if the current HTTP Flow contains body.
167    fn contains_body(&self) -> bool;
168}
169
170pub struct Chunk {
171    bytes: Vec<u8>,
172}
173
174impl Chunk {
175    #[cfg(feature = "experimental")]
176    pub fn new(bytes: Vec<u8>) -> Self {
177        Self { bytes }
178    }
179
180    #[cfg(not(feature = "experimental"))]
181    pub(crate) fn new(bytes: Vec<u8>) -> Self {
182        Self { bytes }
183    }
184
185    pub fn bytes(&self) -> &[u8] {
186        &self.bytes
187    }
188
189    pub fn into_bytes(self) -> Vec<u8> {
190        self.bytes
191    }
192}
193
194pub trait BodyStreamState {
195    type Stream<'b>: Stream<Item = Chunk>
196    where
197        Self: 'b;
198
199    fn contains_body(&self) -> bool;
200
201    fn stream(&self) -> Self::Stream<'_>;
202
203    #[cfg(feature = "experimental")]
204    fn write_chunk(&self, chunk: Chunk) -> Result<(), BodyError>;
205}