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}