1use std::{borrow::Cow, fmt, time::Duration};
12
13use bytes::Bytes;
14use http::{HeaderMap, Method, StatusCode, Uri};
15use serde::{
16 Deserialize, Deserializer, Serialize, Serializer,
17 de::{self, IgnoredAny, MapAccess, Visitor},
18 ser::SerializeStruct,
19};
20
21use crate::{
22 client::Client,
23 codec,
24 de::{KeyIn, invalid_response},
25 error::Error,
26 request::{CallHeaders, Deadline},
27 response::ResponseMeta,
28 retry::{self, RetryPolicy},
29 transport::{self, Exchange, HttpService},
30};
31
32pub struct Models<'a, S> {
36 client: &'a Client<S>,
37}
38
39impl<'a, S> Models<'a, S> {
40 pub(crate) fn new(client: &'a Client<S>) -> Self {
41 Self { client }
42 }
43
44 pub fn list(&self) -> ListModels<'a, S> {
46 ListModels {
47 client: self.client,
48 deadline: Deadline::Client,
49 headers: CallHeaders::default(),
50 retry: None,
51 }
52 }
53}
54
55impl<S> fmt::Debug for Models<'_, S> {
56 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57 formatter.debug_struct("Models").finish_non_exhaustive()
58 }
59}
60
61#[must_use = "a request does nothing until it is sent"]
66pub struct ListModels<'a, S> {
67 client: &'a Client<S>,
68 deadline: Deadline,
69 headers: CallHeaders<'a>,
70 retry: Option<RetryPolicy>,
72}
73
74impl<'a, S> ListModels<'a, S> {
75 pub fn timeout(mut self, timeout: Duration) -> Self {
77 self.deadline = Deadline::After(timeout);
78 self
79 }
80
81 pub fn no_timeout(mut self) -> Self {
83 self.deadline = Deadline::Never;
84 self
85 }
86
87 pub fn header(mut self, name: impl Into<Cow<'a, str>>, value: impl Into<Cow<'a, str>>) -> Self {
90 self.headers.push(name.into(), value.into());
91 self
92 }
93
94 pub fn retry(mut self, policy: RetryPolicy) -> Self {
97 self.retry = Some(policy);
98 self
99 }
100}
101
102impl<S> ListModels<'_, S>
103where
104 S: HttpService,
105{
106 pub async fn send(self) -> Result<ListModelsResponse, Error> {
125 let shared = self.client.shared();
126 let deadline = self.deadline.resolve(shared.config.timeout())?;
127 let headers = self.headers.parse(false)?;
128
129 let uri = shared.config.endpoints().models();
130 let exchange = Exchange {
131 method: &Method::GET,
132 uri,
133 base_headers: &shared.get_headers,
134 call_headers: &headers,
135 deadline,
136 max_response_bytes: shared.config.max_response_bytes(),
137 };
138 let policy = self.retry.as_ref().unwrap_or(&shared.retry);
139 retry::run(policy, &Method::GET, uri, |retry| async move {
140 let (status, headers, body) =
141 transport::attempt(&shared.service, exchange, retry, None).await?;
142 decode_list_models(body, status, headers, Some((&Method::GET, uri)))
145 })
146 .await
147 }
148}
149
150impl<S> fmt::Debug for ListModels<'_, S> {
151 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
154 let mut shown = formatter.debug_struct("ListModels");
155 shown.field("deadline", &self.deadline).field("headers", &self.headers);
156 if let Some(retry) = &self.retry {
157 shown.field("retry", retry);
158 }
159 shown.finish_non_exhaustive()
160 }
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
167pub struct ModelMetadata {
168 name: String,
169 description: String,
170 release_date: String,
171}
172
173impl ModelMetadata {
174 #[must_use]
176 pub fn name(&self) -> &str {
177 &self.name
178 }
179
180 #[must_use]
182 pub fn description(&self) -> &str {
183 &self.description
184 }
185
186 #[must_use]
188 pub fn release_date(&self) -> &str {
189 &self.release_date
190 }
191}
192
193#[derive(Debug, Clone, PartialEq)]
198pub struct ListModelsResponse {
199 models: Vec<ModelMetadata>,
200 meta: ResponseMeta,
201}
202
203impl ListModelsResponse {
204 #[must_use]
206 pub fn models(&self) -> &[ModelMetadata] {
207 &self.models
208 }
209
210 #[must_use]
212 pub fn meta(&self) -> &ResponseMeta {
213 &self.meta
214 }
215
216 #[must_use]
218 pub fn into_models(self) -> Vec<ModelMetadata> {
219 self.models
220 }
221}
222
223impl Serialize for ListModelsResponse {
224 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
225 where
226 S: Serializer,
227 {
228 let mut out = serializer.serialize_struct("ListModelsResponse", 1)?;
229 out.serialize_field("models", &self.models)?;
230 out.end()
231 }
232}
233
234impl<'de> Deserialize<'de> for ModelMetadata {
235 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
238 where
239 D: Deserializer<'de>,
240 {
241 deserializer.deserialize_map(CardVisitor)
242 }
243}
244
245struct CardVisitor;
248
249impl<'de> Visitor<'de> for CardVisitor {
250 type Value = ModelMetadata;
251
252 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
253 formatter.write_str("a model card")
254 }
255
256 fn visit_map<M>(self, mut map: M) -> Result<ModelMetadata, M::Error>
257 where
258 M: MapAccess<'de>,
259 {
260 let (mut name, mut description, mut release_date) = (None, None, None);
261 while let Some(index) =
262 map.next_key_seed(KeyIn(&["name", "description", "release_date"]))?
263 {
264 match index {
265 Some(0) => name = Some(map.next_value()?),
266 Some(1) => description = Some(map.next_value()?),
267 Some(2) => release_date = Some(map.next_value()?),
268 _ => {
269 map.next_value::<IgnoredAny>()?;
270 }
271 }
272 }
273 Ok(ModelMetadata {
274 name: name.ok_or_else(|| de::Error::missing_field("name"))?,
275 description: description.ok_or_else(|| de::Error::missing_field("description"))?,
276 release_date: release_date.ok_or_else(|| de::Error::missing_field("release_date"))?,
277 })
278 }
279}
280
281struct ModelList {
283 models: Vec<ModelMetadata>,
284}
285
286impl<'de> Deserialize<'de> for ModelList {
287 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
288 where
289 D: Deserializer<'de>,
290 {
291 deserializer.deserialize_map(ModelListVisitor)
292 }
293}
294
295struct ModelListVisitor;
296
297impl<'de> Visitor<'de> for ModelListVisitor {
298 type Value = ModelList;
299
300 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
301 formatter.write_str("a list of models")
302 }
303
304 fn visit_map<M>(self, mut map: M) -> Result<ModelList, M::Error>
305 where
306 M: MapAccess<'de>,
307 {
308 let mut models = None;
309 while let Some(index) = map.next_key_seed(KeyIn(&["models"]))? {
310 match index {
311 Some(_) => models = Some(map.next_value()?),
312 None => {
313 map.next_value::<IgnoredAny>()?;
314 }
315 }
316 }
317 Ok(ModelList { models: models.ok_or_else(|| de::Error::missing_field("models"))? })
318 }
319}
320
321pub(crate) fn decode_list_models(
329 body: Bytes,
330 status: StatusCode,
331 headers: HeaderMap,
332 endpoint: Option<(&Method, &Uri)>,
333) -> Result<ListModelsResponse, Error> {
334 let meta = ResponseMeta::new(status, headers, body);
335 let decoded = codec::decode::<ModelList>(meta.raw_body());
336 match decoded {
337 Ok(ModelList { models }) => Ok(ListModelsResponse { models, meta }),
338 Err(source) => Err(invalid_response(meta, endpoint, source)),
339 }
340}
341
342#[cfg(test)]
343#[path = "models_tests.rs"]
344mod tests;