playground_api/
blocking.rs

1//! Holds the blocking version of the Client. Only accessible by enabling the `blocking` feature.
2
3#[cfg(feature = "blocking")]
4use crate::{endpoints::*, error::Error};
5#[cfg(feature = "blocking")]
6use url::Url;
7
8/// A client for interacting with the Rust playground API.
9///
10/// Holds the base URL and the `reqwest::blocking::Client` struct for all requests.
11#[cfg(feature = "blocking")]
12#[derive(Clone)]
13pub struct Client {
14    url: Url,
15    client: reqwest::blocking::Client,
16}
17
18#[cfg(feature = "blocking")]
19impl Client {
20    /// Creates a new `Client` instance with the given base URL.
21    ///
22    /// Parses the provided string into a `Url`. Returns an error if the URL is invalid.
23    ///
24    /// # Arguments
25    ///
26    /// * `url` - A string slice representing the base URL of the Rust playground API.
27    ///
28    /// # Returns
29    ///
30    /// * `Result<Client, Error>` - On success, returns a `Client` configured with the parsed URL.
31    ///   On failure, returns an `Error` if the URL string is invalid.
32    pub fn new(url: &str) -> Result<Client, Error> {
33        let url = Url::parse(url)?;
34        let client = reqwest::blocking::Client::new();
35        Ok(Client { url, client })
36    }
37
38    /// Sends a code execution request to the Rust playground and returns the result.
39    ///
40    /// This asynchronous method takes and [`ExecuteRequest`] struct containing the code
41    /// execution parameters, sends it to the appropriate endpoint on the Rust playground
42    /// via a POST request, and returns the execution result.
43    ///
44    /// # Arguments
45    ///
46    /// * `request` - A reference to an [`ExecuteRequest`] that includes the code snippet
47    ///   and configuration options such as edition, crate type, and whether to run or compile.
48    ///
49    /// # Returns
50    ///
51    /// * `Result<ExecuteResponse, Error>` - On success, returns an [`ExecuteResponse`] containing
52    ///   the output, errors, and status from the Rust playground. On failure, returns an [`Error`].
53    ///
54    /// # Errors
55    ///
56    /// This function will return an error if the HTTP request fails, if the response cannot be parsed,
57    /// or if the playground service is unavailable.
58    pub fn execute<'a>(&self, request: &ExecuteRequest<'a>) -> Result<ExecuteResponse<'a>, Error> {
59        self.post(request)
60    }
61
62    /// Sends a code compilation request to the Rust playground and returns the result.
63    ///
64    /// This asynchronous method takes a [`CompileRequest`] containing the code and
65    /// compilation parameters, sends it to the Rust playground's compile endpoint,
66    /// and returns the compilation result.
67    ///
68    /// # Arguments
69    ///
70    /// * `request` - A reference to a [`CompileRequest`] that includes the code and metadata
71    ///   such as the toolchain edition, crate type, target, and any compiler settings.
72    ///
73    /// # Returns
74    ///
75    /// * `Result<CompileResponse, Error>` - On success, returns a [`CompileResponse`] containing
76    ///   the compiler output, including success/failure status, messages, and possible warnings or errors.
77    ///   On failure, returns an [`Error`] describing the issue.
78    ///
79    /// # Errors
80    ///
81    /// Returns an error if the HTTP request fails, if the response cannot be parsed correctly,
82    /// or if the playground service encounters an issue.
83    pub fn compile<'a>(&self, request: &CompileRequest<'a>) -> Result<CompileResponse<'a>, Error> {
84        self.post(request)
85    }
86
87    /// Sends a code formatting request to the Rust playground and returns the formatted result.
88    ///
89    /// This asynchronous method takes a [`FormatRequest`] containing the Rust code and formatting options,
90    /// sends it to the Rust playground's format endpoint, and returns the formatted code or any errors.
91    ///
92    /// # Arguments
93    ///
94    /// * `request` - A reference to a [`FormatRequest`] that includes the code to be formatted and
95    ///   optional parameters like the edition to use.
96    ///
97    /// # Returns
98    ///
99    /// * `Result<FormatResponse, Error>` - On success, returns a [`FormatResponse`] containing the
100    ///   formatted code or an error message if the code could not be formatted.
101    ///   On failure, returns an [`Error`] representing issues like network failure or parsing problems.
102    ///
103    /// # Errors
104    ///
105    /// This function may return an error if the request fails, the response is invalid,
106    /// or the Rust playground's formatting service encounters a problem.
107    pub fn format<'a>(&self, request: &FormatRequest<'a>) -> Result<FormatResponse<'a>, Error> {
108        self.post(request)
109    }
110
111    /// Sends a Clippy linting request to the Rust playground and returns the analysis result.
112    ///
113    /// This asynchronous method takes a [`ClippyRequest`] containing the Rust code and configuration,
114    /// sends it to the Rust playground's Clippy endpoint, and returns any linter warnings, errors,
115    /// or suggestions provided by Clippy.
116    ///
117    /// # Arguments
118    ///
119    /// * `request` - A reference to a [`ClippyRequest`] that includes the code to be analyzed
120    ///   and optional parameters such as edition or crate type.
121    ///
122    /// # Returns
123    ///
124    /// * `Result<ClippyResponse, Error>` - On success, returns a [`ClippyResponse`] containing
125    ///   Clippy's diagnostic output (warnings, errors, suggestions). On failure, returns an [`Error`]
126    ///   describing what went wrong (e.g., network error, bad request, or service issue).
127    ///
128    /// # Errors
129    ///
130    /// Returns an error if the request cannot be completed, the response is invalid,
131    /// or the Clippy service is unavailable or encounters an internal error.
132    pub fn clippy<'a>(&self, request: &ClippyRequest<'a>) -> Result<ClippyResponse<'a>, Error> {
133        self.post(request)
134    }
135
136    /// Sends a Miri request to the Rust playground and returns the result of interpreting the code.
137    ///
138    /// This asynchronous method takes a [`MiriRequest`] containing the Rust code and any
139    /// interpreter-specific options, sends it to the Rust playground's Miri endpoint, and
140    /// returns the result of running the interpreter on the code.
141    ///
142    /// # Arguments
143    ///
144    /// * `request` - A reference to a [`MiriRequest`] that includes the code and metadata
145    ///   such as edition, crate type, and other configuration options.
146    ///
147    /// # Returns
148    ///
149    /// * `Result<MiriResponse, Error>` - On success, returns a [`MiriResponse`] containing the
150    ///   result of the interpretation. On failure, returns an [`Error`] describing the issue.
151    ///
152    /// # Errors
153    ///
154    /// Returns an error if the request fails, if the response is invalid, or if the Miri service
155    /// encounters an internal issue.
156    pub fn miri<'a>(&self, request: &MiriRequest<'a>) -> Result<MiriResponse<'a>, Error> {
157        self.post(request)
158    }
159
160    /// Sends a macro expansion request to the Rust playground and returns the result.
161    ///
162    /// This asynchronous method takes a [`MacroExpansionRequest`] with Rust code containing macros,
163    /// sends it to the Rust playground's macro expansion endpoint, and returns the result
164    /// of the expanded macros.
165    ///
166    /// # Arguments
167    ///
168    /// * `request` - A reference to a [`MacroExpansionRequest`] that includes the code and any
169    ///   configuration options like the edition to use.
170    ///
171    /// # Returns
172    ///
173    /// * `Result<MacroExpansionResponse, Error>` - On success, returns a [`MacroExpansionResponse`]
174    ///   containing the macro-expanded version of the code. On failure, returns an [`Error`] describing
175    ///   the issue.
176    ///
177    /// # Errors
178    ///
179    /// Returns an error if the HTTP request fails, if the response is invalid, or if the macro expansion
180    /// service encounters an issue.
181    pub fn macro_expansion<'a>(
182        &self,
183        request: &MacroExpansionRequest<'a>,
184    ) -> Result<MacroExpansionResponse<'a>, Error> {
185        self.post(request)
186    }
187
188    /// Retrieves the list of available crates from the Rust playground.
189    ///
190    /// This asynchronous method sends a GET request to the crates endpoint
191    /// and returns a list of crates supported by the playground environment.
192    ///
193    /// # Returns
194    ///
195    /// * `Result<CratesResponse, Error>` - On success, returns a [`CratesResponse`] containing
196    ///   the names and versions of available crates. On failure, returns an [`Error`] describing
197    ///   the problem.
198    ///
199    /// # Errors
200    ///
201    /// Returns an error if the request fails, if the response cannot be parsed,
202    /// or if the crates service is unavailable.
203    pub fn crates<'a>(&self) -> Result<CratesResponse<'a>, Error> {
204        self.get(Endpoints::Crates)
205    }
206
207    /// Retrieves the supported versions and metadata of the Rust playground.
208    ///
209    /// This asynchronous method sends a GET request to the versions endpoint and
210    /// returns information about supported Rust versions, targets, and environments.
211    ///
212    /// # Returns
213    ///
214    /// * `Result<VersionsResponse, Error>` - On success, returns a [`VersionsResponse`]
215    ///   containing version details. On failure, returns an [`Error`] describing what went wrong.
216    ///
217    /// # Errors
218    ///
219    /// Returns an error if the request cannot be completed, the response is malformed,
220    /// or if the versions service is unavailable.
221    pub fn versions<'a>(&self) -> Result<VersionsResponse<'a>, Error> {
222        self.get(Endpoints::Versions)
223    }
224
225    /// Creates a GitHub Gist from the provided Rust playground code.
226    ///
227    /// This asynchronous method sends a [`GistCreateRequest`] to the Gist creation endpoint
228    /// and returns a response containing the Gist URL or error information.
229    ///
230    /// # Arguments
231    ///
232    /// * `request` - A reference to a [`GistCreateRequest`] that includes the code to be uploaded
233    ///   as a Gist and any additional metadata like description or visibility.
234    ///
235    /// # Returns
236    ///
237    /// * `Result<GistResponse, Error>` - On success, returns a [`GistResponse`] containing
238    ///   the Gist ID and URL. On failure, returns an [`Error`] describing what went wrong.
239    ///
240    /// # Errors
241    ///
242    /// Returns an error if the HTTP request fails, if the response is malformed,
243    /// or if the Gist service is unavailable.
244    pub fn gist_create<'a>(
245        &self,
246        request: &GistCreateRequest<'a>,
247    ) -> Result<GistResponse<'a>, Error> {
248        self.post(request)
249    }
250
251    /// Retrieves an existing GitHub Gist from the Rust playground.
252    ///
253    /// This asynchronous method sends a GET request to the Gist retrieval endpoint
254    /// using the provided Gist ID and returns the contents of the Gist.
255    ///
256    /// # Arguments
257    ///
258    /// * `id` - A `String` representing the unique identifier of the Gist to retrieve.
259    ///
260    /// # Returns
261    ///
262    /// * `Result<GistResponse, Error>` - On success, returns a [`GistResponse`] containing
263    ///   the Gist's code and metadata. On failure, returns an [`Error`] describing the issue.
264    ///
265    /// # Errors
266    ///
267    /// Returns an error if the HTTP request fails, if the response is invalid,
268    /// or if the Gist could not be found.
269    pub fn gist_get<'a>(&self, id: &str) -> Result<GistResponse<'a>, Error> {
270        self.get(Endpoints::GistGet(id))
271    }
272
273    /// Sends a POST request with a serialized JSON payload to the specified endpoint,
274    /// and deserializes the response into the expected type.
275    ///
276    /// Used internally to interact with Rust playground endpoints.
277    pub fn post<T, U>(&self, request: &T) -> Result<U, Error>
278    where
279        T: Request,
280        U: Response,
281    {
282        let endpoint = request.endpoint();
283        let url = self.url.join(&endpoint.path())?;
284        let res = self.client.post(url).json(request).send()?;
285
286        if !res.status().is_success() {
287            return Err(Error::NoSuccess(res.status().as_u16()));
288        }
289
290        let res = res.json::<U>()?;
291        Ok(res)
292    }
293
294    /// Sends a GET request to the specified endpoint, and deserializes the response
295    /// into the expected type.
296    ///
297    /// Used internally to interact with Rust playground endpoints.
298    pub fn get<U>(&self, endpoint: Endpoints) -> Result<U, Error>
299    where
300        U: Response,
301    {
302        let url = self.url.join(&endpoint.path())?;
303        let res = self.client.get(url).send()?;
304
305        if !res.status().is_success() {
306            return Err(Error::NoSuccess(res.status().as_u16()));
307        }
308
309        let res = res.json::<U>()?;
310        Ok(res)
311    }
312}
313
314#[cfg(feature = "blocking")]
315impl Default for Client {
316    /// Creates a `Client` instance with the following url <https://play.rust-lang.org/>
317    fn default() -> Self {
318        let client = reqwest::blocking::Client::new();
319        Self {
320            url: Url::parse("https://play.rust-lang.org/").unwrap(),
321            client,
322        }
323    }
324}