1use crate::backoff_policy::{BackoffPolicy, BackoffPolicyArg};
29use crate::polling_backoff_policy::{PollingBackoffPolicy, PollingBackoffPolicyArg};
30use crate::polling_error_policy::{PollingErrorPolicy, PollingErrorPolicyArg};
31use crate::retry_policy::{RetryPolicy, RetryPolicyArg};
32use crate::retry_throttler::{RetryThrottlerArg, SharedRetryThrottler};
33use std::sync::Arc;
34
35#[derive(Clone, Debug, Default)]
43pub struct RequestOptions {
44 idempotent: Option<bool>,
45 user_agent: Option<String>,
46 attempt_timeout: Option<std::time::Duration>,
47 retry_policy: Option<Arc<dyn RetryPolicy>>,
48 backoff_policy: Option<Arc<dyn BackoffPolicy>>,
49 retry_throttler: Option<SharedRetryThrottler>,
50 polling_error_policy: Option<Arc<dyn PollingErrorPolicy>>,
51 polling_backoff_policy: Option<Arc<dyn PollingBackoffPolicy>>,
52 path_template: Option<&'static str>,
53 #[cfg(google_cloud_unstable_tracing)]
54 resource_name: Option<String>,
55}
56
57impl RequestOptions {
58 pub fn idempotent(&self) -> Option<bool> {
60 self.idempotent
61 }
62
63 pub fn set_idempotency(&mut self, value: bool) {
75 self.idempotent = Some(value);
76 }
77
78 pub(crate) fn set_default_idempotency(&mut self, default: bool) {
84 self.idempotent.get_or_insert(default);
85 }
86
87 pub fn set_user_agent<T: Into<String>>(&mut self, v: T) {
89 self.user_agent = Some(v.into());
90 }
91
92 pub fn user_agent(&self) -> &Option<String> {
94 &self.user_agent
95 }
96
97 pub fn set_attempt_timeout<T: Into<std::time::Duration>>(&mut self, v: T) {
102 self.attempt_timeout = Some(v.into());
103 }
104
105 pub fn attempt_timeout(&self) -> &Option<std::time::Duration> {
107 &self.attempt_timeout
108 }
109
110 pub fn retry_policy(&self) -> &Option<Arc<dyn RetryPolicy>> {
112 &self.retry_policy
113 }
114
115 pub fn set_retry_policy<V: Into<RetryPolicyArg>>(&mut self, v: V) {
117 self.retry_policy = Some(v.into().into());
118 }
119
120 pub fn backoff_policy(&self) -> &Option<Arc<dyn BackoffPolicy>> {
122 &self.backoff_policy
123 }
124
125 pub fn set_backoff_policy<V: Into<BackoffPolicyArg>>(&mut self, v: V) {
127 self.backoff_policy = Some(v.into().into());
128 }
129
130 pub fn retry_throttler(&self) -> &Option<SharedRetryThrottler> {
132 &self.retry_throttler
133 }
134
135 pub fn set_retry_throttler<V: Into<RetryThrottlerArg>>(&mut self, v: V) {
137 self.retry_throttler = Some(v.into().into());
138 }
139
140 pub fn polling_error_policy(&self) -> &Option<Arc<dyn PollingErrorPolicy>> {
142 &self.polling_error_policy
143 }
144
145 pub fn set_polling_error_policy<V: Into<PollingErrorPolicyArg>>(&mut self, v: V) {
147 self.polling_error_policy = Some(v.into().0);
148 }
149
150 pub fn polling_backoff_policy(&self) -> &Option<Arc<dyn PollingBackoffPolicy>> {
152 &self.polling_backoff_policy
153 }
154
155 pub fn set_polling_backoff_policy<V: Into<PollingBackoffPolicyArg>>(&mut self, v: V) {
157 self.polling_backoff_policy = Some(v.into().0);
158 }
159
160 pub(crate) fn path_template(&self) -> Option<&'static str> {
162 self.path_template
163 }
164
165 pub(crate) fn set_path_template(&mut self, v: &'static str) {
167 self.path_template = Some(v);
168 }
169
170 #[cfg(google_cloud_unstable_tracing)]
172 pub(crate) fn resource_name(&self) -> Option<&str> {
173 self.resource_name.as_deref()
174 }
175
176 #[cfg(google_cloud_unstable_tracing)]
178 pub(crate) fn set_resource_name(&mut self, v: String) {
179 self.resource_name = Some(v);
180 }
181}
182
183pub trait RequestOptionsBuilder: internal::RequestBuilder {
190 fn with_idempotency(self, v: bool) -> Self;
192
193 fn with_user_agent<V: Into<String>>(self, v: V) -> Self;
195
196 fn with_attempt_timeout<V: Into<std::time::Duration>>(self, v: V) -> Self;
201
202 fn with_retry_policy<V: Into<RetryPolicyArg>>(self, v: V) -> Self;
204
205 fn with_backoff_policy<V: Into<BackoffPolicyArg>>(self, v: V) -> Self;
207
208 fn with_retry_throttler<V: Into<RetryThrottlerArg>>(self, v: V) -> Self;
210
211 fn with_polling_error_policy<V: Into<PollingErrorPolicyArg>>(self, v: V) -> Self;
213
214 fn with_polling_backoff_policy<V: Into<PollingBackoffPolicyArg>>(self, v: V) -> Self;
216}
217
218#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
219pub mod internal {
220 use super::RequestOptions;
225
226 pub trait RequestBuilder {
232 fn request_options(&mut self) -> &mut RequestOptions;
233 }
234
235 pub fn set_default_idempotency(mut options: RequestOptions, default: bool) -> RequestOptions {
236 options.set_default_idempotency(default);
237 options
238 }
239
240 pub fn set_path_template(
241 mut options: RequestOptions,
242 path_template: &'static str,
243 ) -> RequestOptions {
244 options.set_path_template(path_template);
245 options
246 }
247
248 pub fn get_path_template(options: &RequestOptions) -> Option<&'static str> {
249 options.path_template()
250 }
251
252 #[cfg(google_cloud_unstable_tracing)]
253 pub fn set_resource_name(mut options: RequestOptions, resource_name: String) -> RequestOptions {
254 options.set_resource_name(resource_name);
255 options
256 }
257
258 #[cfg(google_cloud_unstable_tracing)]
259 pub fn get_resource_name(options: &RequestOptions) -> Option<&str> {
260 options.resource_name()
261 }
262}
263
264impl<T> RequestOptionsBuilder for T
266where
267 T: internal::RequestBuilder,
268{
269 fn with_idempotency(mut self, v: bool) -> Self {
270 self.request_options().set_idempotency(v);
271 self
272 }
273
274 fn with_user_agent<V: Into<String>>(mut self, v: V) -> Self {
275 self.request_options().set_user_agent(v);
276 self
277 }
278
279 fn with_attempt_timeout<V: Into<std::time::Duration>>(mut self, v: V) -> Self {
280 self.request_options().set_attempt_timeout(v);
281 self
282 }
283
284 fn with_retry_policy<V: Into<RetryPolicyArg>>(mut self, v: V) -> Self {
285 self.request_options().set_retry_policy(v);
286 self
287 }
288
289 fn with_backoff_policy<V: Into<BackoffPolicyArg>>(mut self, v: V) -> Self {
290 self.request_options().set_backoff_policy(v);
291 self
292 }
293
294 fn with_retry_throttler<V: Into<RetryThrottlerArg>>(mut self, v: V) -> Self {
295 self.request_options().set_retry_throttler(v);
296 self
297 }
298
299 fn with_polling_error_policy<V: Into<PollingErrorPolicyArg>>(mut self, v: V) -> Self {
300 self.request_options().set_polling_error_policy(v);
301 self
302 }
303
304 fn with_polling_backoff_policy<V: Into<PollingBackoffPolicyArg>>(mut self, v: V) -> Self {
305 self.request_options().set_polling_backoff_policy(v);
306 self
307 }
308}
309
310#[cfg(test)]
311mod tests {
312 use super::internal::*;
313 use super::*;
314 use crate::exponential_backoff::ExponentialBackoffBuilder;
315 use crate::polling_error_policy;
316 use crate::retry_policy::LimitedAttemptCount;
317 use crate::retry_throttler::AdaptiveThrottler;
318 use std::time::Duration;
319 type Result = std::result::Result<(), Box<dyn std::error::Error>>;
320
321 #[derive(Debug, Default)]
322 struct TestBuilder {
323 request_options: RequestOptions,
324 }
325 impl RequestBuilder for TestBuilder {
326 fn request_options(&mut self) -> &mut RequestOptions {
327 &mut self.request_options
328 }
329 }
330
331 #[test]
332 fn request_options() {
333 let mut opts = RequestOptions::default();
334
335 assert_eq!(opts.idempotent, None);
336 opts.set_idempotency(true);
337 assert_eq!(opts.idempotent(), Some(true));
338 opts.set_idempotency(false);
339 assert_eq!(opts.idempotent(), Some(false));
340
341 opts.set_user_agent("test-only");
342 assert_eq!(opts.user_agent().as_deref(), Some("test-only"));
343 assert_eq!(opts.attempt_timeout(), &None);
344
345 let d = Duration::from_secs(123);
346 opts.set_attempt_timeout(d);
347 assert_eq!(opts.user_agent().as_deref(), Some("test-only"));
348 assert_eq!(opts.attempt_timeout(), &Some(d));
349
350 opts.set_retry_policy(LimitedAttemptCount::new(3));
351 assert!(opts.retry_policy().is_some(), "{opts:?}");
352
353 opts.set_backoff_policy(ExponentialBackoffBuilder::new().clamp());
354 assert!(opts.backoff_policy().is_some(), "{opts:?}");
355
356 opts.set_retry_throttler(AdaptiveThrottler::default());
357 assert!(opts.retry_throttler().is_some(), "{opts:?}");
358
359 opts.set_polling_error_policy(polling_error_policy::Aip194Strict);
360 assert!(opts.polling_error_policy().is_some(), "{opts:?}");
361
362 opts.set_polling_backoff_policy(ExponentialBackoffBuilder::new().clamp());
363 assert!(opts.polling_backoff_policy().is_some(), "{opts:?}");
364
365 opts.set_path_template("test");
366 assert_eq!(opts.path_template(), Some("test"));
367 }
368
369 #[test]
370 fn request_options_idempotency() {
371 let opts = set_default_idempotency(RequestOptions::default(), true);
372 assert_eq!(opts.idempotent(), Some(true));
373 let opts = set_default_idempotency(opts, false);
374 assert_eq!(opts.idempotent(), Some(true));
375
376 let opts = set_default_idempotency(RequestOptions::default(), false);
377 assert_eq!(opts.idempotent(), Some(false));
378 let opts = set_default_idempotency(opts, true);
379 assert_eq!(opts.idempotent(), Some(false));
380 }
381
382 #[test]
383 fn request_options_path_template() {
384 let opts = RequestOptions::default();
385 assert_eq!(opts.path_template(), None);
386 let opts = set_path_template(opts, "test");
387 assert_eq!(opts.path_template(), Some("test"));
388 }
389
390 #[test]
391 #[cfg(google_cloud_unstable_tracing)]
392 fn request_options_resource_name() {
393 let opts = RequestOptions::default();
394 assert_eq!(opts.resource_name(), None);
395 let opts = set_resource_name(opts, "test".to_string());
396 assert_eq!(opts.resource_name(), Some("test"));
397 }
398
399 #[test]
400 fn request_options_builder() -> Result {
401 let mut builder = TestBuilder::default();
402 assert_eq!(builder.request_options().user_agent(), &None);
403 assert_eq!(builder.request_options().attempt_timeout(), &None);
404
405 let mut builder = TestBuilder::default().with_idempotency(true);
406 assert_eq!(builder.request_options().idempotent(), Some(true));
407 let mut builder = TestBuilder::default().with_idempotency(false);
408 assert_eq!(builder.request_options().idempotent(), Some(false));
409
410 let mut builder = TestBuilder::default().with_user_agent("test-only");
411 assert_eq!(
412 builder.request_options().user_agent().as_deref(),
413 Some("test-only")
414 );
415 assert_eq!(builder.request_options().attempt_timeout(), &None);
416
417 let d = Duration::from_secs(123);
418 let mut builder = TestBuilder::default().with_attempt_timeout(d);
419 assert_eq!(builder.request_options().user_agent(), &None);
420 assert_eq!(builder.request_options().attempt_timeout(), &Some(d));
421
422 let mut builder = TestBuilder::default().with_retry_policy(LimitedAttemptCount::new(3));
423 assert!(
424 builder.request_options().retry_policy().is_some(),
425 "{builder:?}"
426 );
427
428 let mut builder =
429 TestBuilder::default().with_backoff_policy(ExponentialBackoffBuilder::new().build()?);
430 assert!(
431 builder.request_options().backoff_policy().is_some(),
432 "{builder:?}"
433 );
434
435 let mut builder = TestBuilder::default().with_retry_throttler(AdaptiveThrottler::default());
436 assert!(
437 builder.request_options().retry_throttler().is_some(),
438 "{builder:?}"
439 );
440
441 let mut builder =
442 TestBuilder::default().with_polling_error_policy(polling_error_policy::Aip194Strict);
443 assert!(
444 builder.request_options().polling_error_policy().is_some(),
445 "{builder:?}"
446 );
447
448 let mut builder = TestBuilder::default()
449 .with_polling_backoff_policy(ExponentialBackoffBuilder::new().build()?);
450 assert!(
451 builder.request_options().polling_backoff_policy().is_some(),
452 "{builder:?}"
453 );
454
455 Ok(())
456 }
457}