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}