ploidy_codegen_rust/
client.rs1use itertools::Itertools;
2use ploidy_core::codegen::IntoCode;
3use proc_macro2::TokenStream;
4use quote::{ToTokens, TokenStreamExt, quote};
5
6use super::{
7 graph::CodegenGraph,
8 naming::{CodegenIdent, CodegenIdentUsage},
9};
10
11#[derive(Clone, Copy, Debug)]
13pub struct CodegenClientModule<'a> {
14 graph: &'a CodegenGraph<'a>,
15 resources: &'a [&'a str],
16}
17
18impl<'a> CodegenClientModule<'a> {
19 pub fn new(graph: &'a CodegenGraph<'a>, resources: &'a [&'a str]) -> Self {
20 Self { graph, resources }
21 }
22}
23
24impl ToTokens for CodegenClientModule<'_> {
25 fn to_tokens(&self, tokens: &mut TokenStream) {
26 let mods = self
27 .resources
28 .iter()
29 .map(|resource| {
30 let ident = CodegenIdent::new(resource);
31 let mod_name = CodegenIdentUsage::Module(&ident);
32 quote! {
33 #[cfg(feature = #resource)]
34 pub mod #mod_name;
35 }
36 })
37 .collect_vec();
38
39 let client_doc = {
40 let info = self.graph.spec().info;
41 format!("API client for {} (version {})", info.title, info.version)
42 };
43
44 tokens.append_all(quote! {
45 #[doc = #client_doc]
46 #[derive(Clone, Debug)]
47 pub struct Client {
48 client: ::reqwest::Client,
49 headers: ::http::HeaderMap,
50 base_url: ::url::Url,
51 }
52
53 impl Client {
54 pub fn new(base_url: impl AsRef<str>) -> Result<Self, crate::error::Error> {
56 Ok(Self::with_reqwest_client(
57 ::reqwest::Client::new(),
58 base_url.as_ref().parse()?,
59 ))
60 }
61
62 pub fn with_reqwest_client(client: ::reqwest::Client, base_url: ::url::Url) -> Self {
63 Self {
64 client,
65 headers: ::http::HeaderMap::new(),
66 base_url,
67 }
68 }
69
70 pub fn with_header<K, V>(mut self, name: K, value: V) -> Result<Self, crate::error::Error>
72 where
73 K: TryInto<::http::HeaderName>,
74 V: TryInto<::http::HeaderValue>,
75 K::Error: Into<::http::Error>,
76 V::Error: Into<::http::Error>,
77 {
78 let name = name
79 .try_into()
80 .map_err(|err| crate::error::Error::BadHeaderName(err.into()))?;
81 let value = value
82 .try_into()
83 .map_err(|err| crate::error::Error::BadHeaderValue(name.clone(), err.into()))?;
84 self.headers.insert(name, value);
85 Ok(Self {
86 client: self.client,
87 headers: self.headers,
88 base_url: self.base_url,
89 })
90 }
91
92 pub fn with_sensitive_header<K, V>(self, name: K, value: V) -> Result<Self, crate::error::Error>
105 where
106 K: TryInto<::http::HeaderName>,
107 V: TryInto<::http::HeaderValue>,
108 K::Error: Into<::http::Error>,
109 V::Error: Into<::http::Error>,
110 {
111 let name = name
112 .try_into()
113 .map_err(|err| crate::error::Error::BadHeaderName(err.into()))?;
114 let mut value: ::http::HeaderValue = value
115 .try_into()
116 .map_err(|err| crate::error::Error::BadHeaderValue(name.clone(), err.into()))?;
117 value.set_sensitive(true);
118 self.with_header(name, value)
119 }
120
121 pub fn with_user_agent<V>(self, value: V) -> Result<Self, crate::error::Error>
122 where
123 V: TryInto<::http::HeaderValue>,
124 V::Error: Into<::http::Error>,
125 {
126 self.with_header(::http::header::USER_AGENT, value)
127 }
128 }
129
130 #(#mods)*
131 });
132 }
133}
134
135impl IntoCode for CodegenClientModule<'_> {
136 type Code = (&'static str, TokenStream);
137
138 fn into_code(self) -> Self::Code {
139 ("src/client/mod.rs", self.into_token_stream())
140 }
141}