1use crate::api_types::{compile, download, execute, fmt, share};
2use serde::{de::DeserializeOwned, Deserialize, Serialize};
3
4pub const BASE_URL: &str = "https://play.rust-lang.org/";
5const PATH_EXECUTE: &str = "execute";
6const PATH_COMPILE: &str = "compile";
7const PATH_FMT: &str = "format";
8const PATH_SHARE: &str = "meta/gist";
9const PATH_DL: &str = "meta/gist";
10
11pub trait API {
12 fn execute(
13 &self,
14 req: execute::Request,
15 ) -> Result<execute::Response, Box<dyn std::error::Error>>;
16 fn compile(
17 &self,
18 req: compile::Request,
19 ) -> Result<compile::Response, Box<dyn std::error::Error>>;
20
21 fn fmt(&self, req: fmt::Request) -> Result<fmt::Response, Box<dyn std::error::Error>>;
22
23 fn share(&self, req: share::Request) -> Result<share::Response, Box<dyn std::error::Error>>;
24
25 fn download(
26 &self,
27 req: download::Request,
28 ) -> Result<download::Response, Box<dyn std::error::Error>>;
29}
30
31pub struct APIClient {
32 base_url: String,
33}
34
35impl APIClient {
36 pub fn new() -> APIClient {
37 APIClient {
38 base_url: BASE_URL.to_string(),
39 }
40 }
41
42 fn get<D>(&self, path: &str) -> Result<D, Box<dyn std::error::Error>>
43 where
44 D: DeserializeOwned,
45 {
46 let url = self.base_url.clone() + path;
47 let res: D = reqwest::blocking::get(url)?.json()?;
48
49 Ok(res)
50 }
51
52 fn post<S, D>(&self, path: &str, body: S) -> Result<D, Box<dyn std::error::Error>>
53 where
54 S: Serialize,
55 D: DeserializeOwned,
56 {
57 let url = self.base_url.clone() + path;
58 let client = reqwest::blocking::Client::new();
59 let res: D = client.post(url).json(&body).send()?.json()?;
60
61 Ok(res)
62 }
63}
64
65impl API for APIClient {
66 fn execute(
67 &self,
68 req: execute::Request,
69 ) -> Result<execute::Response, Box<dyn std::error::Error>> {
70 let res: execute::Response = self.post(PATH_EXECUTE, req)?;
71 Ok(res)
72 }
73
74 fn compile(
75 &self,
76 req: compile::Request,
77 ) -> Result<compile::Response, Box<dyn std::error::Error>> {
78 let res: compile::Response = self.post(PATH_COMPILE, req)?;
79 Ok(res)
80 }
81
82 fn fmt(&self, req: fmt::Request) -> Result<fmt::Response, Box<dyn std::error::Error>> {
83 let res: fmt::Response = self.post(PATH_FMT, req)?;
84 Ok(res)
85 }
86
87 fn share(&self, req: share::Request) -> Result<share::Response, Box<dyn std::error::Error>> {
88 let res: share::Response = self.post(PATH_SHARE, req)?;
89 Ok(res)
90 }
91
92 fn download(
93 &self,
94 req: download::Request,
95 ) -> Result<download::Response, Box<dyn std::error::Error>> {
96 let path = format!("{}/{}", PATH_DL, req.id);
97 let res: download::Response = self.get(&path)?;
98
99 Ok(res)
100 }
101}