1use super::budget::{ConditionErrorPolicy, RunAccountant};
4use super::message::AuditMode;
5use crate::base::{CancelToken, Instant};
6use crate::function::CallLayer;
7use crate::observe::{Observer, TraceOptions};
8use std::fmt;
9use std::sync::Arc;
10
11#[derive(Clone)]
13#[non_exhaustive]
14pub struct RunOptions<'a> {
15 pub channel: Option<&'a str>,
17 pub routing_bucket: Option<u8>,
20 pub capture_changes: bool,
24 pub audit: AuditMode,
26 pub deadline: Option<Instant>,
40 pub cancel: Option<&'a CancelToken>,
48 pub layers: &'a [Arc<dyn CallLayer>],
51 pub observer: Option<&'a dyn Observer>,
56 pub trace: Option<TraceOptions>,
62 pub condition_error_policy: Option<ConditionErrorPolicy>,
66 pub task_budget: Option<u64>,
70 pub expr_ops_budget: Option<u64>,
73 pub accountant: Option<&'a dyn RunAccountant>,
76}
77
78impl RunOptions<'static> {
79 pub(crate) const DEFAULT: Self = Self {
81 channel: None,
82 routing_bucket: None,
83 capture_changes: true,
84 audit: AuditMode::Full,
85 deadline: None,
86 cancel: None,
87 layers: &[],
88 observer: None,
89 trace: None,
90 condition_error_policy: None,
91 task_budget: None,
92 expr_ops_budget: None,
93 accountant: None,
94 };
95}
96
97impl Default for RunOptions<'_> {
98 fn default() -> Self {
99 RunOptions::DEFAULT
100 }
101}
102
103impl fmt::Debug for RunOptions<'_> {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 let observer = if self.observer.is_some() {
107 "present"
108 } else {
109 "absent"
110 };
111 let mut s = f.debug_struct("RunOptions");
112 s.field("channel", &self.channel)
113 .field("routing_bucket", &self.routing_bucket)
114 .field("capture_changes", &self.capture_changes)
115 .field("audit", &self.audit)
116 .field("deadline", &self.deadline)
117 .field("cancel", &self.cancel)
118 .field("layers", &self.layers.len())
119 .field("observer", &format_args!("{observer}"))
120 .field("trace", &self.trace);
121 if let Some(policy) = &self.condition_error_policy {
122 s.field("condition_error_policy", policy);
123 }
124 if let Some(budget) = &self.task_budget {
125 s.field("task_budget", budget);
126 }
127 if let Some(budget) = &self.expr_ops_budget {
128 s.field("expr_ops_budget", budget);
129 }
130 if self.accountant.is_some() {
131 s.field("accountant", &format_args!("present"));
132 }
133 s.finish()
134 }
135}
136
137impl<'a> RunOptions<'a> {
138 #[must_use]
140 pub fn channel(mut self, c: &'a str) -> Self {
141 self.channel = Some(c);
142 self
143 }
144
145 #[must_use]
149 pub fn routing_bucket(mut self, b: u8) -> Self {
150 self.routing_bucket = Some(b);
151 self
152 }
153
154 #[must_use]
156 pub fn capture_changes(mut self, on: bool) -> Self {
157 self.capture_changes = on;
158 self
159 }
160
161 #[must_use]
163 pub fn audit(mut self, mode: AuditMode) -> Self {
164 self.audit = mode;
165 self
166 }
167
168 #[must_use]
170 pub fn deadline(mut self, deadline: Instant) -> Self {
171 self.deadline = Some(deadline);
172 self
173 }
174
175 #[must_use]
178 pub fn cancel(mut self, token: &'a CancelToken) -> Self {
179 self.cancel = Some(token);
180 self
181 }
182
183 #[must_use]
186 pub fn layers(mut self, layers: &'a [Arc<dyn CallLayer>]) -> Self {
187 self.layers = layers;
188 self
189 }
190
191 #[must_use]
193 pub fn observer(mut self, o: &'a dyn Observer) -> Self {
194 self.observer = Some(o);
195 self
196 }
197
198 #[must_use]
200 pub fn trace(mut self, opts: TraceOptions) -> Self {
201 self.trace = Some(opts);
202 self
203 }
204
205 #[must_use]
207 pub fn condition_error_policy(mut self, policy: ConditionErrorPolicy) -> Self {
208 self.condition_error_policy = Some(policy);
209 self
210 }
211
212 #[must_use]
214 pub fn with_condition_error_policy(self, policy: ConditionErrorPolicy) -> Self {
215 self.condition_error_policy(policy)
216 }
217
218 #[must_use]
220 pub fn task_budget(mut self, max_tasks: u64) -> Self {
221 self.task_budget = Some(max_tasks);
222 self
223 }
224
225 #[must_use]
227 pub fn with_task_budget(self, max_tasks: u64) -> Self {
228 self.task_budget(max_tasks)
229 }
230
231 #[must_use]
234 pub fn expr_ops_budget(mut self, max_ops: u64) -> Self {
235 self.expr_ops_budget = Some(max_ops);
236 self
237 }
238
239 #[must_use]
241 pub fn with_expr_ops_budget(self, max_ops: u64) -> Self {
242 self.expr_ops_budget(max_ops)
243 }
244
245 #[must_use]
247 pub fn accountant(mut self, accountant: &'a dyn RunAccountant) -> Self {
248 self.accountant = Some(accountant);
249 self
250 }
251
252 #[must_use]
254 pub fn with_accountant(self, accountant: &'a dyn RunAccountant) -> Self {
255 self.accountant(accountant)
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn run_options_default_captures_changes_and_keeps_the_full_audit() {
265 let o = RunOptions::default();
266 assert!(o.capture_changes);
267 assert_eq!(o.audit, AuditMode::Full);
268 assert_eq!(o.channel, None);
269 assert_eq!(o.routing_bucket, None);
270 assert!(o.deadline.is_none() && o.cancel.is_none());
271 assert!(o.layers.is_empty());
272 assert!(o.observer.is_none());
273 assert!(o.trace.is_none());
274 let layers: Vec<Arc<dyn CallLayer>> = vec![Arc::new(Pass)];
275 let token = CancelToken::new();
276 let o = o
277 .channel("c")
278 .routing_bucket(7)
279 .capture_changes(false)
280 .audit(AuditMode::Off)
281 .cancel(&token)
282 .layers(&layers);
283 assert_eq!((o.channel, o.routing_bucket), (Some("c"), Some(7)));
284 assert!(!o.capture_changes);
285 assert_eq!(o.audit, AuditMode::Off);
286 assert_eq!(o.layers.len(), 1);
287 assert_eq!(
288 format!("{o:?}"),
289 r#"RunOptions { channel: Some("c"), routing_bucket: Some(7), capture_changes: false, audit: Off, deadline: None, cancel: Some(CancelToken { cancelled: false, .. }), layers: 1, observer: absent, trace: None }"#
290 );
291 let watcher = Quiet;
292 let o = o.observer(&watcher);
293 assert!(format!("{o:?}").ends_with("layers: 1, observer: present, trace: None }"));
294 let o = o.trace(TraceOptions::default().timings(true));
295 assert!(o.trace.as_ref().is_some_and(|t| t.timings && t.changes));
296 let at = Instant::now();
297 assert_eq!(o.deadline(at).deadline, Some(at));
298 }
299
300 struct Quiet;
302
303 impl Observer for Quiet {
304 fn on(&self, _event: &crate::observe::Event<'_>) {}
305 }
306
307 struct Pass;
309
310 impl CallLayer for Pass {
311 fn call<'a>(
312 &'a self,
313 ctx: &'a mut crate::function::Ctx<'_>,
314 next: crate::function::Next<'a>,
315 ) -> crate::function::BoxFuture<'a, crate::base::Result<crate::function::Outcome>> {
316 next.run(ctx)
317 }
318 }
319}