Skip to main content

qcs_api_client_openapi/apis/
mod.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
15use std::error;
16use std::fmt;
17
18use qcs_dependencies_client::reqwest;
19#[cfg(feature = "tracing-opentelemetry")]
20use qcs_dependencies_client::reqwest_middleware;
21
22#[derive(Debug, Clone)]
23pub struct ResponseContent<T> {
24    pub status: reqwest::StatusCode,
25    pub content: String,
26    pub entity: Option<T>,
27    pub retry_delay: Option<std::time::Duration>,
28}
29
30#[derive(Debug)]
31pub enum Error<T> {
32    Reqwest(reqwest::Error),
33    Serde(serde_path_to_error::Error<serde_json::Error>),
34    Io(std::io::Error),
35    QcsToken(crate::common::configuration::TokenError),
36    ResponseError(ResponseContent<T>),
37    InvalidContentType {
38        content_type: String,
39        return_type: &'static str,
40    },
41    #[cfg(feature = "tracing-opentelemetry")]
42    ReqwestMiddleware(anyhow::Error),
43}
44
45impl<T> Error<T> {
46    pub fn status_code(&self) -> Option<reqwest::StatusCode> {
47        match self {
48            Self::ResponseError(err) => Some(err.status),
49            _ => None,
50        }
51    }
52}
53
54impl<T> fmt::Display for Error<T> {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        let (module, e) = match self {
57            Error::Reqwest(e) => ("reqwest", e.to_string()),
58            Error::Serde(e) => ("serde", e.to_string()),
59            Error::Io(e) => ("IO", e.to_string()),
60            Error::QcsToken(e) => ("refresh_qcs_token", e.to_string()),
61            Error::ResponseError(e) => (
62                "response",
63                format!("status code {}: {}", e.status, e.content),
64            ),
65            Error::InvalidContentType {
66                content_type,
67                return_type,
68            } => (
69                "api",
70                format!(
71                    "received {content_type} content type response that cannot be converted to `{return_type}`"
72                ),
73            ),
74            #[cfg(feature = "tracing-opentelemetry")]
75            Error::ReqwestMiddleware(e) => ("reqwest-middleware", e.to_string()),
76        };
77        write!(f, "error in {}: {}", module, e)
78    }
79}
80
81impl<T: fmt::Debug> error::Error for Error<T> {
82    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
83        Some(match self {
84            Error::Reqwest(e) => e,
85            Error::Serde(e) => e,
86            Error::Io(e) => e,
87            Error::QcsToken(e) => e,
88            #[cfg(feature = "tracing-opentelemetry")]
89            Error::ReqwestMiddleware(e) => e.source()?,
90            Error::InvalidContentType { .. } => return None,
91            Error::ResponseError(_) => return None,
92        })
93    }
94}
95
96impl<T> From<reqwest::Error> for Error<T> {
97    fn from(e: reqwest::Error) -> Self {
98        Error::Reqwest(e)
99    }
100}
101
102#[cfg(feature = "tracing-opentelemetry")]
103impl<T> From<reqwest_middleware::Error> for Error<T> {
104    fn from(e: reqwest_middleware::Error) -> Self {
105        match e {
106            reqwest_middleware::Error::Reqwest(e) => Error::Reqwest(e),
107            reqwest_middleware::Error::Middleware(e) => Error::ReqwestMiddleware(e),
108        }
109    }
110}
111
112impl<T> From<serde_path_to_error::Error<serde_json::Error>> for Error<T> {
113    fn from(e: serde_path_to_error::Error<serde_json::Error>) -> Self {
114        Error::Serde(e)
115    }
116}
117
118impl<T> From<std::io::Error> for Error<T> {
119    fn from(e: std::io::Error) -> Self {
120        Error::Io(e)
121    }
122}
123
124impl<T> From<crate::common::configuration::TokenError> for Error<T> {
125    fn from(e: crate::common::configuration::TokenError) -> Self {
126        Error::QcsToken(e)
127    }
128}
129
130pub fn urlencode<T: AsRef<str>>(s: T) -> String {
131    ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect()
132}
133
134pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String, String)> {
135    if let serde_json::Value::Object(object) = value {
136        let mut params = vec![];
137
138        for (key, value) in object {
139            match value {
140                serde_json::Value::Object(_) => params.append(&mut parse_deep_object(
141                    &format!("{}[{}]", prefix, key),
142                    value,
143                )),
144                serde_json::Value::Array(array) => {
145                    for (i, value) in array.iter().enumerate() {
146                        params.append(&mut parse_deep_object(
147                            &format!("{}[{}][{}]", prefix, key, i),
148                            value,
149                        ));
150                    }
151                }
152                serde_json::Value::String(s) => {
153                    params.push((format!("{}[{}]", prefix, key), s.clone()))
154                }
155                _ => params.push((format!("{}[{}]", prefix, key), value.to_string())),
156            }
157        }
158
159        return params;
160    }
161
162    unimplemented!("Only objects are supported with style=deepObject, got: {value:#}")
163}
164
165/// Internal use only
166/// A content type supported by this client.
167#[allow(dead_code)]
168enum ContentType {
169    Json,
170    Text,
171    Unsupported(String),
172}
173
174impl From<&str> for ContentType {
175    fn from(content_type: &str) -> Self {
176        if content_type.starts_with("application") && content_type.contains("json") {
177            Self::Json
178        } else if content_type.starts_with("text/plain") {
179            Self::Text
180        } else {
181            Self::Unsupported(content_type.to_string())
182        }
183    }
184}
185
186pub mod account_api;
187pub mod authentication_api;
188pub mod client_applications_api;
189pub mod default_api;
190pub mod endpoints_api;
191pub mod engagements_api;
192pub mod quantum_processors_api;
193pub mod reservations_api;
194
195pub mod configuration;