Skip to main content

typesafe_rs/
blocking.rs

1use serde::Serialize;
2
3use crate::Client;
4use crate::config::{CallOptions, ClientConfig};
5use crate::error::Error;
6use crate::types::{ModelCard, Questions, SystemOneRequest, SystemOneResponse};
7
8/// Blocking wrapper around [`Client`] using a current-thread Tokio runtime.
9///
10/// Do not use this type from inside an existing Tokio runtime (`block_on` will panic).
11///
12/// Enable with `typesafe-rs = { version = "0.1", features = ["blocking"] }`.
13#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
14#[derive(Debug)]
15pub struct BlockingClient {
16    client: Client,
17    rt: tokio::runtime::Runtime,
18}
19
20impl BlockingClient {
21    /// Build a blocking client. See [`Client::new`].
22    pub fn new(config: ClientConfig) -> Result<Self, Error> {
23        let rt = tokio::runtime::Builder::new_current_thread()
24            .enable_all()
25            .build()
26            .map_err(|err| Error::InvalidRequest(format!("failed to create runtime: {err}")))?;
27        let client = Client::new(config)?;
28        Ok(Self { client, rt })
29    }
30
31    /// [`Self::new`] using process environment fallbacks.
32    pub fn from_env() -> Result<Self, Error> {
33        Self::new(ClientConfig::default())
34    }
35
36    /// Like [`Client::new_with_env`].
37    pub fn new_with_env(
38        config: ClientConfig,
39        lookup: impl FnMut(&str) -> Option<String>,
40    ) -> Result<Self, Error> {
41        let rt = tokio::runtime::Builder::new_current_thread()
42            .enable_all()
43            .build()
44            .map_err(|err| Error::InvalidRequest(format!("failed to create runtime: {err}")))?;
45        let client = Client::new_with_env(config, lookup)?;
46        Ok(Self { client, rt })
47    }
48
49    /// Blocking [`Client::system_one`].
50    pub fn system_one(
51        &self,
52        state: impl Serialize,
53        questions: Questions,
54    ) -> Result<SystemOneResponse, Error> {
55        self.rt.block_on(self.client.system_one(state, questions))
56    }
57
58    /// Blocking [`Client::system_one_with`].
59    pub fn system_one_with(
60        &self,
61        req: &SystemOneRequest,
62        opts: CallOptions,
63    ) -> Result<SystemOneResponse, Error> {
64        self.rt.block_on(self.client.system_one_with(req, opts))
65    }
66
67    /// Access the Models resource.
68    #[must_use]
69    pub fn models(&self) -> BlockingModels<'_> {
70        BlockingModels { client: self }
71    }
72
73    /// Blocking [`Client::warm_up`].
74    pub fn warm_up(&self) -> Result<(), Error> {
75        self.rt.block_on(self.client.warm_up())
76    }
77
78    /// Default model used when a request omits `model`.
79    #[must_use]
80    pub fn default_model(&self) -> &str {
81        self.client.default_model()
82    }
83
84    /// Resolved API root, without a trailing slash.
85    #[must_use]
86    pub fn base_url(&self) -> &crate::Url {
87        self.client.base_url()
88    }
89}
90
91/// Blocking Models API resource.
92#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
93#[derive(Debug)]
94pub struct BlockingModels<'a> {
95    client: &'a BlockingClient,
96}
97
98impl BlockingModels<'_> {
99    /// List models available to the account.
100    pub fn list(&self) -> Result<Vec<ModelCard>, Error> {
101        self.client.rt.block_on(self.client.client.models().list())
102    }
103
104    /// [`Self::list`] with per-call options.
105    pub fn list_with(&self, opts: &CallOptions) -> Result<Vec<ModelCard>, Error> {
106        self.client
107            .rt
108            .block_on(self.client.client.models().list_with(opts))
109    }
110}