Skip to main content

qcs_api_client_openapi/apis/
deployments_api.rs

1// Copyright 2026 Rigetti Computing
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*
16 * Rigetti QCS API
17 *
18 * # Introduction  This is the documentation for the Rigetti QCS HTTP API.  You can find out more about Rigetti at [https://rigetti.com](https://rigetti.com), and also interact with QCS via the web at [https://qcs.rigetti.com](https://qcs.rigetti.com).  This API is documented in **OpenAPI format** and so is compatible with the dozens of language-specific client generators available [here](https://github.com/OpenAPITools/openapi-generator) and elsewhere on the web.  # Principles  This API follows REST design principles where appropriate, and otherwise an HTTP RPC paradigm. We adhere to the Google [API Improvement Proposals](https://google.aip.dev/general) where reasonable to provide a consistent, intuitive developer experience. HTTP response codes match their specifications, and error messages fit a common format.  # Authentication  All access to the QCS API requires OAuth2 authentication provided by Okta. You can request access [here](https://www.rigetti.com/get-quantum). Once you have a user account, you can download your access token from QCS [here](https://qcs.rigetti.com/auth/token).   That access token is valid for 24 hours after issuance. The value of `access_token` within the JSON file is the token used for authentication (don't use the entire JSON file).  Authenticate requests using the `Authorization` header and a `Bearer` prefix:  ``` curl --header \"Authorization: Bearer eyJraW...Iow\" ```  # Quantum Processor Access  Access to the quantum processors themselves is not yet provided directly by this HTTP API, but is instead performed over ZeroMQ/[rpcq](https://github.com/rigetti/rpcq). Until that changes, we suggest using [pyquil](https://github.com/rigetti/pyquil) to build and execute quantum programs via the Legacy API.  # Legacy API  Our legacy HTTP API remains accessible at https://forest-server.qcs.rigetti.com, and it shares a source of truth with this API's services. You can use either service with the same user account and means of authentication. We strongly recommend using the API documented here, as the legacy API is on the path to deprecation.
19 *
20 * The version of the OpenAPI document: 2020-07-31
21 * Contact: support@rigetti.com
22 * Generated by: https://openapi-generator.tech
23 */
24
25use super::{ContentType, Error, configuration};
26use crate::{apis::ResponseContent, models};
27use ::qcs_api_client_common::backoff::{
28    BackoffBuilder, ExponentialBackoff, duration_from_io_error, duration_from_reqwest_error,
29    duration_from_response,
30};
31#[cfg(feature = "tracing")]
32use qcs_api_client_common::configuration::tokens::TokenRefresher;
33use qcs_dependencies_client::reqwest::{self, StatusCode};
34use serde::{Deserialize, Serialize};
35
36#[cfg(feature = "clap")]
37#[allow(unused, reason = "not used in all templates, but required in some")]
38use ::{miette::IntoDiagnostic as _, qcs_api_client_common::clap_utils::JsonMaybeStdin};
39
40/// Serialize command-line arguments for [`get_default_endpoint`]
41#[cfg(feature = "clap")]
42#[derive(Debug, clap::Args)]
43pub struct GetDefaultEndpointClapParams {
44    #[arg(long)]
45    pub quantum_processor_id: String,
46}
47
48#[cfg(feature = "clap")]
49impl GetDefaultEndpointClapParams {
50    pub async fn execute(
51        self,
52        configuration: &configuration::Configuration,
53    ) -> Result<models::Endpoint, miette::Error> {
54        get_default_endpoint(configuration, self.quantum_processor_id.as_str())
55            .await
56            .into_diagnostic()
57    }
58}
59
60/// Serialize command-line arguments for [`get_endpoint`]
61#[cfg(feature = "clap")]
62#[derive(Debug, clap::Args)]
63pub struct GetEndpointClapParams {
64    #[arg(long)]
65    pub endpoint_id: String,
66}
67
68#[cfg(feature = "clap")]
69impl GetEndpointClapParams {
70    pub async fn execute(
71        self,
72        configuration: &configuration::Configuration,
73    ) -> Result<models::Endpoint, miette::Error> {
74        get_endpoint(configuration, self.endpoint_id.as_str())
75            .await
76            .into_diagnostic()
77    }
78}
79
80/// Serialize command-line arguments for [`get_endpoint_accessors`]
81#[cfg(feature = "clap")]
82#[derive(Debug, clap::Args)]
83pub struct GetEndpointAccessorsClapParams {
84    #[arg(long)]
85    pub endpoint_id: String,
86}
87
88#[cfg(feature = "clap")]
89impl GetEndpointAccessorsClapParams {
90    pub async fn execute(
91        self,
92        configuration: &configuration::Configuration,
93    ) -> Result<models::ListQuantumProcessorAccessorsResponse, miette::Error> {
94        get_endpoint_accessors(configuration, self.endpoint_id.as_str())
95            .await
96            .into_diagnostic()
97    }
98}
99
100/// struct for typed errors of method [`get_default_endpoint`]
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(untagged)]
103pub enum GetDefaultEndpointError {
104    Status422(models::ValidationError),
105    DefaultResponse(models::Error),
106    UnknownValue(serde_json::Value),
107}
108
109/// struct for typed errors of method [`get_endpoint`]
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(untagged)]
112pub enum GetEndpointError {
113    Status422(models::ValidationError),
114    DefaultResponse(models::Error),
115    UnknownValue(serde_json::Value),
116}
117
118/// struct for typed errors of method [`get_endpoint_accessors`]
119#[derive(Debug, Clone, Serialize, Deserialize)]
120#[serde(untagged)]
121pub enum GetEndpointAccessorsError {
122    Status422(models::ValidationError),
123    DefaultResponse(models::Error),
124    UnknownValue(serde_json::Value),
125}
126
127async fn get_default_endpoint_inner(
128    configuration: &configuration::Configuration,
129    backoff: &mut ExponentialBackoff,
130    quantum_processor_id: &str,
131) -> Result<models::Endpoint, Error<GetDefaultEndpointError>> {
132    let local_var_configuration = configuration;
133    // add a prefix to parameters to efficiently prevent name collisions
134    let p_path_quantum_processor_id = quantum_processor_id;
135
136    let local_var_client = &local_var_configuration.client;
137
138    let local_var_uri_str = format!(
139        "{}/v1/quantumProcessors/{quantumProcessorId}/endpoints:getDefault",
140        local_var_configuration.qcs_config.api_url(),
141        quantumProcessorId = crate::apis::urlencode(p_path_quantum_processor_id)
142    );
143    let mut local_var_req_builder =
144        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
145
146    #[cfg(feature = "tracing")]
147    {
148        // Ignore parsing errors if the URL is invalid for some reason.
149        // If it is invalid, it will turn up as an error later when actually making the request.
150        let local_var_do_tracing = local_var_uri_str
151            .parse::<::url::Url>()
152            .ok()
153            .is_none_or(|url| {
154                configuration
155                    .qcs_config
156                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
157            });
158
159        if local_var_do_tracing {
160            ::tracing::debug!(
161                url=%local_var_uri_str,
162                method="GET",
163                "making get_default_endpoint request",
164            );
165        }
166    }
167
168    // Use the QCS Bearer token if a client OAuthSession is present,
169    // but do not require one when the security schema says it is optional.
170    {
171        use qcs_api_client_common::configuration::TokenError;
172
173        #[allow(
174            clippy::nonminimal_bool,
175            clippy::eq_op,
176            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
177        )]
178        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
179
180        let token = local_var_configuration
181            .qcs_config
182            .get_bearer_access_token()
183            .await;
184
185        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
186            // the client is configured without any OAuthSession, but this call does not require one.
187            #[cfg(feature = "tracing")]
188            tracing::debug!(
189                "No client credentials found, but this call does not require authentication."
190            );
191        } else {
192            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
193        }
194    }
195
196    let local_var_req = local_var_req_builder.build()?;
197    let local_var_resp = local_var_client.execute(local_var_req).await?;
198
199    let local_var_status = local_var_resp.status();
200    let local_var_raw_content_type = local_var_resp
201        .headers()
202        .get("content-type")
203        .and_then(|v| v.to_str().ok())
204        .unwrap_or("application/octet-stream")
205        .to_string();
206    let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
207
208    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
209        let local_var_content = local_var_resp.text().await?;
210        match local_var_content_type {
211            ContentType::Json => serde_path_to_error::deserialize(
212                &mut serde_json::Deserializer::from_str(&local_var_content),
213            )
214            .map_err(Error::from),
215            ContentType::Text => Err(Error::InvalidContentType {
216                content_type: local_var_raw_content_type,
217                return_type: "models::Endpoint",
218            }),
219            ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
220                content_type: unknown_type,
221                return_type: "models::Endpoint",
222            }),
223        }
224    } else {
225        let local_var_retry_delay =
226            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
227        let local_var_content = local_var_resp.text().await?;
228        let local_var_entity: Option<GetDefaultEndpointError> =
229            serde_json::from_str(&local_var_content).ok();
230        let local_var_error = ResponseContent {
231            status: local_var_status,
232            content: local_var_content,
233            entity: local_var_entity,
234            retry_delay: local_var_retry_delay,
235        };
236        Err(Error::ResponseError(local_var_error))
237    }
238}
239
240/// If no endpoint is set as the default, return \"not found.\"
241pub async fn get_default_endpoint(
242    configuration: &configuration::Configuration,
243    quantum_processor_id: &str,
244) -> Result<models::Endpoint, Error<GetDefaultEndpointError>> {
245    let mut backoff = configuration.backoff.build();
246    let mut refreshed_credentials = false;
247    let method = reqwest::Method::GET;
248    loop {
249        let result =
250            get_default_endpoint_inner(configuration, &mut backoff, quantum_processor_id.clone())
251                .await;
252
253        match result {
254            Ok(result) => return Ok(result),
255            Err(Error::ResponseError(response)) => {
256                if !refreshed_credentials
257                    && matches!(
258                        response.status,
259                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
260                    )
261                {
262                    // Attempt to refresh credentials
263                    match configuration.qcs_config.refresh().await {
264                        Ok(_) => {
265                            refreshed_credentials = true;
266                            continue;
267                        }
268                        Err(::qcs_api_client_common::configuration::TokenError::Write {
269                            error,
270                            oauth_session: _,
271                        }) => {
272                            // Token refresh succeeded but persistence failed
273                            // The token is already in memory and will be used for this request
274                            #[cfg(feature = "tracing")]
275                            tracing::warn!(
276                                "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
277                                error
278                            );
279                            refreshed_credentials = true;
280                            continue;
281                        }
282                        Err(e) => return Err(e.into()),
283                    }
284                } else if let Some(duration) = response.retry_delay {
285                    tokio::time::sleep(duration).await;
286                    continue;
287                }
288
289                return Err(Error::ResponseError(response));
290            }
291            Err(Error::Reqwest(error)) => {
292                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
293                    tokio::time::sleep(duration).await;
294                    continue;
295                }
296
297                return Err(Error::Reqwest(error));
298            }
299            Err(Error::Io(error)) => {
300                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
301                    tokio::time::sleep(duration).await;
302                    continue;
303                }
304
305                return Err(Error::Io(error));
306            }
307            Err(error) => return Err(error),
308        }
309    }
310}
311async fn get_endpoint_inner(
312    configuration: &configuration::Configuration,
313    backoff: &mut ExponentialBackoff,
314    endpoint_id: &str,
315) -> Result<models::Endpoint, Error<GetEndpointError>> {
316    let local_var_configuration = configuration;
317    // add a prefix to parameters to efficiently prevent name collisions
318    let p_path_endpoint_id = endpoint_id;
319
320    let local_var_client = &local_var_configuration.client;
321
322    let local_var_uri_str = format!(
323        "{}/v1/endpoints/{endpointId}",
324        local_var_configuration.qcs_config.api_url(),
325        endpointId = crate::apis::urlencode(p_path_endpoint_id)
326    );
327    let mut local_var_req_builder =
328        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
329
330    #[cfg(feature = "tracing")]
331    {
332        // Ignore parsing errors if the URL is invalid for some reason.
333        // If it is invalid, it will turn up as an error later when actually making the request.
334        let local_var_do_tracing = local_var_uri_str
335            .parse::<::url::Url>()
336            .ok()
337            .is_none_or(|url| {
338                configuration
339                    .qcs_config
340                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
341            });
342
343        if local_var_do_tracing {
344            ::tracing::debug!(
345                url=%local_var_uri_str,
346                method="GET",
347                "making get_endpoint request",
348            );
349        }
350    }
351
352    // Use the QCS Bearer token if a client OAuthSession is present,
353    // but do not require one when the security schema says it is optional.
354    {
355        use qcs_api_client_common::configuration::TokenError;
356
357        #[allow(
358            clippy::nonminimal_bool,
359            clippy::eq_op,
360            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
361        )]
362        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
363
364        let token = local_var_configuration
365            .qcs_config
366            .get_bearer_access_token()
367            .await;
368
369        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
370            // the client is configured without any OAuthSession, but this call does not require one.
371            #[cfg(feature = "tracing")]
372            tracing::debug!(
373                "No client credentials found, but this call does not require authentication."
374            );
375        } else {
376            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
377        }
378    }
379
380    let local_var_req = local_var_req_builder.build()?;
381    let local_var_resp = local_var_client.execute(local_var_req).await?;
382
383    let local_var_status = local_var_resp.status();
384    let local_var_raw_content_type = local_var_resp
385        .headers()
386        .get("content-type")
387        .and_then(|v| v.to_str().ok())
388        .unwrap_or("application/octet-stream")
389        .to_string();
390    let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
391
392    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
393        let local_var_content = local_var_resp.text().await?;
394        match local_var_content_type {
395            ContentType::Json => serde_path_to_error::deserialize(
396                &mut serde_json::Deserializer::from_str(&local_var_content),
397            )
398            .map_err(Error::from),
399            ContentType::Text => Err(Error::InvalidContentType {
400                content_type: local_var_raw_content_type,
401                return_type: "models::Endpoint",
402            }),
403            ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
404                content_type: unknown_type,
405                return_type: "models::Endpoint",
406            }),
407        }
408    } else {
409        let local_var_retry_delay =
410            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
411        let local_var_content = local_var_resp.text().await?;
412        let local_var_entity: Option<GetEndpointError> =
413            serde_json::from_str(&local_var_content).ok();
414        let local_var_error = ResponseContent {
415            status: local_var_status,
416            content: local_var_content,
417            entity: local_var_entity,
418            retry_delay: local_var_retry_delay,
419        };
420        Err(Error::ResponseError(local_var_error))
421    }
422}
423
424pub async fn get_endpoint(
425    configuration: &configuration::Configuration,
426    endpoint_id: &str,
427) -> Result<models::Endpoint, Error<GetEndpointError>> {
428    let mut backoff = configuration.backoff.build();
429    let mut refreshed_credentials = false;
430    let method = reqwest::Method::GET;
431    loop {
432        let result = get_endpoint_inner(configuration, &mut backoff, endpoint_id.clone()).await;
433
434        match result {
435            Ok(result) => return Ok(result),
436            Err(Error::ResponseError(response)) => {
437                if !refreshed_credentials
438                    && matches!(
439                        response.status,
440                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
441                    )
442                {
443                    // Attempt to refresh credentials
444                    match configuration.qcs_config.refresh().await {
445                        Ok(_) => {
446                            refreshed_credentials = true;
447                            continue;
448                        }
449                        Err(::qcs_api_client_common::configuration::TokenError::Write {
450                            error,
451                            oauth_session: _,
452                        }) => {
453                            // Token refresh succeeded but persistence failed
454                            // The token is already in memory and will be used for this request
455                            #[cfg(feature = "tracing")]
456                            tracing::warn!(
457                                "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
458                                error
459                            );
460                            refreshed_credentials = true;
461                            continue;
462                        }
463                        Err(e) => return Err(e.into()),
464                    }
465                } else if let Some(duration) = response.retry_delay {
466                    tokio::time::sleep(duration).await;
467                    continue;
468                }
469
470                return Err(Error::ResponseError(response));
471            }
472            Err(Error::Reqwest(error)) => {
473                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
474                    tokio::time::sleep(duration).await;
475                    continue;
476                }
477
478                return Err(Error::Reqwest(error));
479            }
480            Err(Error::Io(error)) => {
481                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
482                    tokio::time::sleep(duration).await;
483                    continue;
484                }
485
486                return Err(Error::Io(error));
487            }
488            Err(error) => return Err(error),
489        }
490    }
491}
492async fn get_endpoint_accessors_inner(
493    configuration: &configuration::Configuration,
494    backoff: &mut ExponentialBackoff,
495    endpoint_id: &str,
496) -> Result<models::ListQuantumProcessorAccessorsResponse, Error<GetEndpointAccessorsError>> {
497    let local_var_configuration = configuration;
498    // add a prefix to parameters to efficiently prevent name collisions
499    let p_path_endpoint_id = endpoint_id;
500
501    let local_var_client = &local_var_configuration.client;
502
503    let local_var_uri_str = format!(
504        "{}/v1/endpoints/{endpoint_id}/accessors",
505        local_var_configuration.qcs_config.api_url(),
506        endpoint_id = crate::apis::urlencode(p_path_endpoint_id)
507    );
508    let mut local_var_req_builder =
509        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
510
511    #[cfg(feature = "tracing")]
512    {
513        // Ignore parsing errors if the URL is invalid for some reason.
514        // If it is invalid, it will turn up as an error later when actually making the request.
515        let local_var_do_tracing = local_var_uri_str
516            .parse::<::url::Url>()
517            .ok()
518            .is_none_or(|url| {
519                configuration
520                    .qcs_config
521                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
522            });
523
524        if local_var_do_tracing {
525            ::tracing::debug!(
526                url=%local_var_uri_str,
527                method="GET",
528                "making get_endpoint_accessors request",
529            );
530        }
531    }
532
533    // Use the QCS Bearer token if a client OAuthSession is present,
534    // but do not require one when the security schema says it is optional.
535    {
536        use qcs_api_client_common::configuration::TokenError;
537
538        #[allow(
539            clippy::nonminimal_bool,
540            clippy::eq_op,
541            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
542        )]
543        let is_jwt_bearer_optional: bool = false || "JWTBearerOptional" == "JWTBearerOptional";
544
545        let token = local_var_configuration
546            .qcs_config
547            .get_bearer_access_token()
548            .await;
549
550        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
551            // the client is configured without any OAuthSession, but this call does not require one.
552            #[cfg(feature = "tracing")]
553            tracing::debug!(
554                "No client credentials found, but this call does not require authentication."
555            );
556        } else {
557            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
558        }
559    }
560
561    let local_var_req = local_var_req_builder.build()?;
562    let local_var_resp = local_var_client.execute(local_var_req).await?;
563
564    let local_var_status = local_var_resp.status();
565    let local_var_raw_content_type = local_var_resp
566        .headers()
567        .get("content-type")
568        .and_then(|v| v.to_str().ok())
569        .unwrap_or("application/octet-stream")
570        .to_string();
571    let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
572
573    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
574        let local_var_content = local_var_resp.text().await?;
575        match local_var_content_type {
576            ContentType::Json => serde_path_to_error::deserialize(
577                &mut serde_json::Deserializer::from_str(&local_var_content),
578            )
579            .map_err(Error::from),
580            ContentType::Text => Err(Error::InvalidContentType {
581                content_type: local_var_raw_content_type,
582                return_type: "models::ListQuantumProcessorAccessorsResponse",
583            }),
584            ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
585                content_type: unknown_type,
586                return_type: "models::ListQuantumProcessorAccessorsResponse",
587            }),
588        }
589    } else {
590        let local_var_retry_delay =
591            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
592        let local_var_content = local_var_resp.text().await?;
593        let local_var_entity: Option<GetEndpointAccessorsError> =
594            serde_json::from_str(&local_var_content).ok();
595        let local_var_error = ResponseContent {
596            status: local_var_status,
597            content: local_var_content,
598            entity: local_var_entity,
599            retry_delay: local_var_retry_delay,
600        };
601        Err(Error::ResponseError(local_var_error))
602    }
603}
604
605pub async fn get_endpoint_accessors(
606    configuration: &configuration::Configuration,
607    endpoint_id: &str,
608) -> Result<models::ListQuantumProcessorAccessorsResponse, Error<GetEndpointAccessorsError>> {
609    let mut backoff = configuration.backoff.build();
610    let mut refreshed_credentials = false;
611    let method = reqwest::Method::GET;
612    loop {
613        let result =
614            get_endpoint_accessors_inner(configuration, &mut backoff, endpoint_id.clone()).await;
615
616        match result {
617            Ok(result) => return Ok(result),
618            Err(Error::ResponseError(response)) => {
619                if !refreshed_credentials
620                    && matches!(
621                        response.status,
622                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
623                    )
624                {
625                    // Attempt to refresh credentials
626                    match configuration.qcs_config.refresh().await {
627                        Ok(_) => {
628                            refreshed_credentials = true;
629                            continue;
630                        }
631                        Err(::qcs_api_client_common::configuration::TokenError::Write {
632                            error,
633                            oauth_session: _,
634                        }) => {
635                            // Token refresh succeeded but persistence failed
636                            // The token is already in memory and will be used for this request
637                            #[cfg(feature = "tracing")]
638                            tracing::warn!(
639                                "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
640                                error
641                            );
642                            refreshed_credentials = true;
643                            continue;
644                        }
645                        Err(e) => return Err(e.into()),
646                    }
647                } else if let Some(duration) = response.retry_delay {
648                    tokio::time::sleep(duration).await;
649                    continue;
650                }
651
652                return Err(Error::ResponseError(response));
653            }
654            Err(Error::Reqwest(error)) => {
655                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
656                    tokio::time::sleep(duration).await;
657                    continue;
658                }
659
660                return Err(Error::Reqwest(error));
661            }
662            Err(Error::Io(error)) => {
663                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
664                    tokio::time::sleep(duration).await;
665                    continue;
666                }
667
668                return Err(Error::Io(error));
669            }
670            Err(error) => return Err(error),
671        }
672    }
673}