Split group method generation
This commit is contained in:
parent
a383e60294
commit
c633a6c33f
|
@ -0,0 +1,162 @@
|
||||||
|
use case::CaseExt;
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
use crate::{generate::util, parser, types};
|
||||||
|
|
||||||
|
use super::return_type::create_return_type;
|
||||||
|
|
||||||
|
pub fn create_method_with_params(
|
||||||
|
group: &parser::ApiGroup,
|
||||||
|
method: &parser::ApiMethod,
|
||||||
|
params: &[types::Type],
|
||||||
|
method_name: &proc_macro2::Ident,
|
||||||
|
url: &str,
|
||||||
|
) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
|
||||||
|
let parameter_type = util::to_ident(&format!(
|
||||||
|
"{}{}Parameters",
|
||||||
|
group.name.to_camel(),
|
||||||
|
method.name.to_camel()
|
||||||
|
));
|
||||||
|
|
||||||
|
let mandatory_params = params
|
||||||
|
.iter()
|
||||||
|
.filter(|param| !param.get_type_info().is_optional);
|
||||||
|
|
||||||
|
let mandatory_param_args = mandatory_params.clone().map(|param| {
|
||||||
|
let name = util::to_ident(¶m.get_type_info().name.to_snake());
|
||||||
|
let t = util::to_ident(¶m.to_borrowed_type());
|
||||||
|
|
||||||
|
if param.should_borrow() {
|
||||||
|
quote! {
|
||||||
|
#name: &#t
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
#name: #t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mandatory_param_names = mandatory_params.clone().map(|param| {
|
||||||
|
let name = util::to_ident(¶m.get_type_info().name.to_snake());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#name
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mandatory_param_args_clone = mandatory_param_args.clone();
|
||||||
|
let mandatory_param_form_build = mandatory_params.map(|param| {
|
||||||
|
let n = ¶m.get_type_info().name;
|
||||||
|
let name = util::to_ident(&n.to_snake());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
let form = form.text(#n, #name.to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let optional_params = params
|
||||||
|
.iter()
|
||||||
|
.filter(|param| param.get_type_info().is_optional)
|
||||||
|
.map(|param| {
|
||||||
|
let n = ¶m.get_type_info().name;
|
||||||
|
let name = util::to_ident(&n.to_snake());
|
||||||
|
let t = util::to_ident(¶m.to_borrowed_type());
|
||||||
|
|
||||||
|
let method = if param.should_borrow() {
|
||||||
|
quote! {
|
||||||
|
pub fn #name(mut self, value: &#t) -> Self {
|
||||||
|
self.form = self.form.text(#n, value.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
pub fn #name(mut self, value: #t) -> Self {
|
||||||
|
self.form = self.form.text(#n, value.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
util::add_docs(¶m.get_type_info().description, method)
|
||||||
|
});
|
||||||
|
|
||||||
|
let group_name = util::to_ident(&group.name.to_camel());
|
||||||
|
|
||||||
|
let send = match create_return_type(group, method) {
|
||||||
|
Some((return_type_name, return_type)) => {
|
||||||
|
quote! {
|
||||||
|
impl<'a> #parameter_type<'a> {
|
||||||
|
fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self {
|
||||||
|
let form = reqwest::multipart::Form::new();
|
||||||
|
#(#mandatory_param_form_build)*
|
||||||
|
Self { group, form }
|
||||||
|
}
|
||||||
|
|
||||||
|
#(#optional_params)*
|
||||||
|
|
||||||
|
pub async fn send(self) -> Result<#return_type_name> {
|
||||||
|
let res = self.group
|
||||||
|
.auth
|
||||||
|
.authenticated_client(#url)
|
||||||
|
.multipart(self.form)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json::<#return_type_name>()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#return_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
quote! {
|
||||||
|
impl<'a> #parameter_type<'a> {
|
||||||
|
fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self {
|
||||||
|
let form = reqwest::multipart::Form::new();
|
||||||
|
#(#mandatory_param_form_build)*
|
||||||
|
Self { group, form }
|
||||||
|
}
|
||||||
|
|
||||||
|
#(#optional_params)*
|
||||||
|
|
||||||
|
pub async fn send(self) -> Result<String> {
|
||||||
|
let res = self.group
|
||||||
|
.auth
|
||||||
|
.authenticated_client(#url)
|
||||||
|
.multipart(self.form)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.text()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
util::add_docs(
|
||||||
|
&method.description,
|
||||||
|
quote! {
|
||||||
|
pub fn #method_name(&self, #(#mandatory_param_args_clone),*) -> #parameter_type {
|
||||||
|
#parameter_type::new(self, #(#mandatory_param_names),*)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Some(quote! {
|
||||||
|
pub struct #parameter_type<'a> {
|
||||||
|
group: &'a #group_name<'a>,
|
||||||
|
form: reqwest::multipart::Form,
|
||||||
|
}
|
||||||
|
|
||||||
|
#send
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
use crate::{generate::util, parser};
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
use super::return_type::create_return_type;
|
||||||
|
|
||||||
|
pub fn create_method_without_params(
|
||||||
|
group: &parser::ApiGroup,
|
||||||
|
method: &parser::ApiMethod,
|
||||||
|
method_name: proc_macro2::Ident,
|
||||||
|
url: &str,
|
||||||
|
) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
|
||||||
|
match create_return_type(group, method) {
|
||||||
|
Some((return_type_name, return_type)) => (
|
||||||
|
util::add_docs(
|
||||||
|
&method.description,
|
||||||
|
quote! {
|
||||||
|
pub async fn #method_name(&self) -> Result<#return_type_name> {
|
||||||
|
let res = self.auth
|
||||||
|
.authenticated_client(#url)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json::<#return_type_name>()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Some(return_type),
|
||||||
|
),
|
||||||
|
None => (
|
||||||
|
util::add_docs(
|
||||||
|
&method.description,
|
||||||
|
quote! {
|
||||||
|
pub async fn #method_name(&self) -> Result<String> {
|
||||||
|
let res = self.auth
|
||||||
|
.authenticated_client(#url)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.text()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
), // assume that all methods without a return type returns a string
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,15 @@
|
||||||
use std::collections::HashMap;
|
mod method_with_params;
|
||||||
|
mod method_without_params;
|
||||||
|
mod return_type;
|
||||||
|
|
||||||
use crate::{generate::util, parser, types};
|
use crate::{generate::util, parser};
|
||||||
use case::CaseExt;
|
use case::CaseExt;
|
||||||
use quote::{format_ident, quote};
|
use quote::quote;
|
||||||
use regex::Regex;
|
|
||||||
|
use self::{
|
||||||
|
method_with_params::create_method_with_params,
|
||||||
|
method_without_params::create_method_without_params,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn generate_methods(
|
pub fn generate_methods(
|
||||||
group: &parser::ApiGroup,
|
group: &parser::ApiGroup,
|
||||||
|
@ -43,371 +49,3 @@ fn generate_method(
|
||||||
None => create_method_without_params(group, method, method_name, &url),
|
None => create_method_without_params(group, method, method_name, &url),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_method_without_params(
|
|
||||||
group: &parser::ApiGroup,
|
|
||||||
method: &parser::ApiMethod,
|
|
||||||
method_name: proc_macro2::Ident,
|
|
||||||
url: &str,
|
|
||||||
) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
|
|
||||||
match create_return_type(group, method) {
|
|
||||||
Some((return_type_name, return_type)) => (
|
|
||||||
util::add_docs(
|
|
||||||
&method.description,
|
|
||||||
quote! {
|
|
||||||
pub async fn #method_name(&self) -> Result<#return_type_name> {
|
|
||||||
let res = self.auth
|
|
||||||
.authenticated_client(#url)
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.json::<#return_type_name>()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Some(return_type),
|
|
||||||
),
|
|
||||||
None => (
|
|
||||||
util::add_docs(
|
|
||||||
&method.description,
|
|
||||||
quote! {
|
|
||||||
pub async fn #method_name(&self) -> Result<String> {
|
|
||||||
let res = self.auth
|
|
||||||
.authenticated_client(#url)
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.text()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
), // assume that all methods without a return type returns a string
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_method_with_params(
|
|
||||||
group: &parser::ApiGroup,
|
|
||||||
method: &parser::ApiMethod,
|
|
||||||
params: &[types::Type],
|
|
||||||
method_name: &proc_macro2::Ident,
|
|
||||||
url: &str,
|
|
||||||
) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
|
|
||||||
let parameter_type = util::to_ident(&format!(
|
|
||||||
"{}{}Parameters",
|
|
||||||
group.name.to_camel(),
|
|
||||||
method.name.to_camel()
|
|
||||||
));
|
|
||||||
|
|
||||||
let mandatory_params = params
|
|
||||||
.iter()
|
|
||||||
.filter(|param| !param.get_type_info().is_optional);
|
|
||||||
|
|
||||||
let mandatory_param_args = mandatory_params.clone().map(|param| {
|
|
||||||
let name = util::to_ident(¶m.get_type_info().name.to_snake());
|
|
||||||
let t = util::to_ident(¶m.to_borrowed_type());
|
|
||||||
|
|
||||||
if param.should_borrow() {
|
|
||||||
quote! {
|
|
||||||
#name: &#t
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
#name: #t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mandatory_param_names = mandatory_params.clone().map(|param| {
|
|
||||||
let name = util::to_ident(¶m.get_type_info().name.to_snake());
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#name
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mandatory_param_args_clone = mandatory_param_args.clone();
|
|
||||||
let mandatory_param_form_build = mandatory_params.map(|param| {
|
|
||||||
let n = ¶m.get_type_info().name;
|
|
||||||
let name = util::to_ident(&n.to_snake());
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
let form = form.text(#n, #name.to_string());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let optional_params = params
|
|
||||||
.iter()
|
|
||||||
.filter(|param| param.get_type_info().is_optional)
|
|
||||||
.map(|param| {
|
|
||||||
let n = ¶m.get_type_info().name;
|
|
||||||
let name = util::to_ident(&n.to_snake());
|
|
||||||
let t = util::to_ident(¶m.to_borrowed_type());
|
|
||||||
|
|
||||||
let method = if param.should_borrow() {
|
|
||||||
quote! {
|
|
||||||
pub fn #name(mut self, value: &#t) -> Self {
|
|
||||||
self.form = self.form.text(#n, value.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
pub fn #name(mut self, value: #t) -> Self {
|
|
||||||
self.form = self.form.text(#n, value.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
util::add_docs(¶m.get_type_info().description, method)
|
|
||||||
});
|
|
||||||
|
|
||||||
let group_name = util::to_ident(&group.name.to_camel());
|
|
||||||
|
|
||||||
let send = match create_return_type(group, method) {
|
|
||||||
Some((return_type_name, return_type)) => {
|
|
||||||
quote! {
|
|
||||||
impl<'a> #parameter_type<'a> {
|
|
||||||
fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self {
|
|
||||||
let form = reqwest::multipart::Form::new();
|
|
||||||
#(#mandatory_param_form_build)*
|
|
||||||
Self { group, form }
|
|
||||||
}
|
|
||||||
|
|
||||||
#(#optional_params)*
|
|
||||||
|
|
||||||
pub async fn send(self) -> Result<#return_type_name> {
|
|
||||||
let res = self.group
|
|
||||||
.auth
|
|
||||||
.authenticated_client(#url)
|
|
||||||
.multipart(self.form)
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.json::<#return_type_name>()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#return_type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
quote! {
|
|
||||||
impl<'a> #parameter_type<'a> {
|
|
||||||
fn new(group: &'a #group_name, #(#mandatory_param_args),*) -> Self {
|
|
||||||
let form = reqwest::multipart::Form::new();
|
|
||||||
#(#mandatory_param_form_build)*
|
|
||||||
Self { group, form }
|
|
||||||
}
|
|
||||||
|
|
||||||
#(#optional_params)*
|
|
||||||
|
|
||||||
pub async fn send(self) -> Result<String> {
|
|
||||||
let res = self.group
|
|
||||||
.auth
|
|
||||||
.authenticated_client(#url)
|
|
||||||
.multipart(self.form)
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.text()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
util::add_docs(
|
|
||||||
&method.description,
|
|
||||||
quote! {
|
|
||||||
pub fn #method_name(&self, #(#mandatory_param_args_clone),*) -> #parameter_type {
|
|
||||||
#parameter_type::new(self, #(#mandatory_param_names),*)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Some(quote! {
|
|
||||||
pub struct #parameter_type<'a> {
|
|
||||||
group: &'a #group_name<'a>,
|
|
||||||
form: reqwest::multipart::Form,
|
|
||||||
}
|
|
||||||
|
|
||||||
#send
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_return_type(
|
|
||||||
group: &parser::ApiGroup,
|
|
||||||
method: &parser::ApiMethod,
|
|
||||||
) -> Option<(proc_macro2::TokenStream, proc_macro2::TokenStream)> {
|
|
||||||
let return_type = match &method.return_type {
|
|
||||||
Some(t) => t,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let to_enum_name = |name: &str| {
|
|
||||||
format!(
|
|
||||||
"{}{}{}",
|
|
||||||
group.name.to_camel(),
|
|
||||||
method.name.to_camel(),
|
|
||||||
name.to_camel()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let enum_types_with_names =
|
|
||||||
return_type
|
|
||||||
.parameters
|
|
||||||
.iter()
|
|
||||||
.flat_map(|parameter| match ¶meter.return_type {
|
|
||||||
types::Type::Number(types::TypeInfo {
|
|
||||||
ref name,
|
|
||||||
type_description: Some(type_description),
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
let enum_fields = type_description.values.iter().map(|value| {
|
|
||||||
let v = &value.value;
|
|
||||||
let re = Regex::new(r#"\(.*\)"#).unwrap();
|
|
||||||
let desc = &value
|
|
||||||
.description
|
|
||||||
.replace(' ', "_")
|
|
||||||
.replace('-', "_")
|
|
||||||
.replace(',', "_");
|
|
||||||
let desc_without_parentheses = re.replace_all(desc, "");
|
|
||||||
let ident = util::to_ident(&desc_without_parentheses.to_camel());
|
|
||||||
|
|
||||||
util::add_docs(
|
|
||||||
&Some(value.description.clone()),
|
|
||||||
quote! {
|
|
||||||
#[serde(rename = #v)]
|
|
||||||
#ident
|
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let enum_name = util::to_ident(&to_enum_name(name));
|
|
||||||
|
|
||||||
Some((
|
|
||||||
name,
|
|
||||||
quote! {
|
|
||||||
#[allow(clippy::enum_variant_names)]
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
|
||||||
pub enum #enum_name {
|
|
||||||
#(#enum_fields,)*
|
|
||||||
}
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
types::Type::String(types::TypeInfo {
|
|
||||||
ref name,
|
|
||||||
type_description: Some(type_description),
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
let enum_fields = type_description.values.iter().map(|type_description| {
|
|
||||||
let value = &type_description.value;
|
|
||||||
let value_as_ident = util::to_ident(&value.to_camel());
|
|
||||||
|
|
||||||
util::add_docs(
|
|
||||||
&Some(type_description.description.clone()),
|
|
||||||
quote! {
|
|
||||||
#[serde(rename = #value)]
|
|
||||||
#value_as_ident
|
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let enum_name = util::to_ident(&to_enum_name(name));
|
|
||||||
|
|
||||||
Some((
|
|
||||||
name,
|
|
||||||
quote! {
|
|
||||||
#[allow(clippy::enum_variant_names)]
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
|
||||||
pub enum #enum_name {
|
|
||||||
#(#enum_fields,)*
|
|
||||||
}
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let enum_names: HashMap<&String, String> = enum_types_with_names
|
|
||||||
.clone()
|
|
||||||
.map(|(enum_name, _)| (enum_name, to_enum_name(enum_name)))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let enum_types = enum_types_with_names.map(|(_, enum_type)| enum_type);
|
|
||||||
|
|
||||||
let parameters = return_type.parameters.iter().map(|parameter| {
|
|
||||||
let namestr = ¶meter.name;
|
|
||||||
let name = util::to_ident(&namestr.to_snake().replace("__", "_"));
|
|
||||||
let rtype = if let Some(enum_type) = enum_names.get(namestr) {
|
|
||||||
util::to_ident(enum_type)
|
|
||||||
} else {
|
|
||||||
util::to_ident(¶meter.return_type.to_owned_type())
|
|
||||||
};
|
|
||||||
let type_info = parameter.return_type.get_type_info();
|
|
||||||
|
|
||||||
let rtype_as_quote = if type_info.is_list {
|
|
||||||
quote! {
|
|
||||||
std::vec::Vec<#rtype>
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
#rtype
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// "type" is a reserved keyword in Rust, so we use a different name.
|
|
||||||
if namestr == "type" {
|
|
||||||
let non_reserved_name = format_ident!("t_{}", name);
|
|
||||||
quote! {
|
|
||||||
#[serde(rename = #namestr)]
|
|
||||||
pub #non_reserved_name: #rtype_as_quote
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
#[serde(rename = #namestr)]
|
|
||||||
pub #name: #rtype_as_quote
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let return_type_name = util::to_ident(&format!(
|
|
||||||
"{}{}Result",
|
|
||||||
&group.name.to_camel(),
|
|
||||||
&method.name.to_camel()
|
|
||||||
));
|
|
||||||
|
|
||||||
let result_type = if return_type.is_list {
|
|
||||||
quote! {
|
|
||||||
std::vec::Vec<#return_type_name>
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
#return_type_name
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some((
|
|
||||||
result_type,
|
|
||||||
quote! {
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct #return_type_name {
|
|
||||||
#(#parameters,)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#(#enum_types)*
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
173
qbittorrent-web-api-gen/src/generate/group/method/return_type.rs
Normal file
173
qbittorrent-web-api-gen/src/generate/group/method/return_type.rs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use case::CaseExt;
|
||||||
|
use quote::{quote, format_ident};
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::{generate::util, parser, types};
|
||||||
|
|
||||||
|
pub fn create_return_type(
|
||||||
|
group: &parser::ApiGroup,
|
||||||
|
method: &parser::ApiMethod,
|
||||||
|
) -> Option<(proc_macro2::TokenStream, proc_macro2::TokenStream)> {
|
||||||
|
let return_type = match &method.return_type {
|
||||||
|
Some(t) => t,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_enum_name = |name: &str| {
|
||||||
|
format!(
|
||||||
|
"{}{}{}",
|
||||||
|
group.name.to_camel(),
|
||||||
|
method.name.to_camel(),
|
||||||
|
name.to_camel()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let enum_types_with_names =
|
||||||
|
return_type
|
||||||
|
.parameters
|
||||||
|
.iter()
|
||||||
|
.flat_map(|parameter| match ¶meter.return_type {
|
||||||
|
types::Type::Number(types::TypeInfo {
|
||||||
|
ref name,
|
||||||
|
type_description: Some(type_description),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let enum_fields = type_description.values.iter().map(|value| {
|
||||||
|
let v = &value.value;
|
||||||
|
let re = Regex::new(r#"\(.*\)"#).unwrap();
|
||||||
|
let desc = &value
|
||||||
|
.description
|
||||||
|
.replace(' ', "_")
|
||||||
|
.replace('-', "_")
|
||||||
|
.replace(',', "_");
|
||||||
|
let desc_without_parentheses = re.replace_all(desc, "");
|
||||||
|
let ident = util::to_ident(&desc_without_parentheses.to_camel());
|
||||||
|
|
||||||
|
util::add_docs(
|
||||||
|
&Some(value.description.clone()),
|
||||||
|
quote! {
|
||||||
|
#[serde(rename = #v)]
|
||||||
|
#ident
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let enum_name = util::to_ident(&to_enum_name(name));
|
||||||
|
|
||||||
|
Some((
|
||||||
|
name,
|
||||||
|
quote! {
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum #enum_name {
|
||||||
|
#(#enum_fields,)*
|
||||||
|
}
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
types::Type::String(types::TypeInfo {
|
||||||
|
ref name,
|
||||||
|
type_description: Some(type_description),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let enum_fields = type_description.values.iter().map(|type_description| {
|
||||||
|
let value = &type_description.value;
|
||||||
|
let value_as_ident = util::to_ident(&value.to_camel());
|
||||||
|
|
||||||
|
util::add_docs(
|
||||||
|
&Some(type_description.description.clone()),
|
||||||
|
quote! {
|
||||||
|
#[serde(rename = #value)]
|
||||||
|
#value_as_ident
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let enum_name = util::to_ident(&to_enum_name(name));
|
||||||
|
|
||||||
|
Some((
|
||||||
|
name,
|
||||||
|
quote! {
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum #enum_name {
|
||||||
|
#(#enum_fields,)*
|
||||||
|
}
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let enum_names: HashMap<&String, String> = enum_types_with_names
|
||||||
|
.clone()
|
||||||
|
.map(|(enum_name, _)| (enum_name, to_enum_name(enum_name)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let enum_types = enum_types_with_names.map(|(_, enum_type)| enum_type);
|
||||||
|
|
||||||
|
let parameters = return_type.parameters.iter().map(|parameter| {
|
||||||
|
let namestr = ¶meter.name;
|
||||||
|
let name = util::to_ident(&namestr.to_snake().replace("__", "_"));
|
||||||
|
let rtype = if let Some(enum_type) = enum_names.get(namestr) {
|
||||||
|
util::to_ident(enum_type)
|
||||||
|
} else {
|
||||||
|
util::to_ident(¶meter.return_type.to_owned_type())
|
||||||
|
};
|
||||||
|
let type_info = parameter.return_type.get_type_info();
|
||||||
|
|
||||||
|
let rtype_as_quote = if type_info.is_list {
|
||||||
|
quote! {
|
||||||
|
std::vec::Vec<#rtype>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
#rtype
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// "type" is a reserved keyword in Rust, so we use a different name.
|
||||||
|
if namestr == "type" {
|
||||||
|
let non_reserved_name = format_ident!("t_{}", name);
|
||||||
|
quote! {
|
||||||
|
#[serde(rename = #namestr)]
|
||||||
|
pub #non_reserved_name: #rtype_as_quote
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
#[serde(rename = #namestr)]
|
||||||
|
pub #name: #rtype_as_quote
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let return_type_name = util::to_ident(&format!(
|
||||||
|
"{}{}Result",
|
||||||
|
&group.name.to_camel(),
|
||||||
|
&method.name.to_camel()
|
||||||
|
));
|
||||||
|
|
||||||
|
let result_type = if return_type.is_list {
|
||||||
|
quote! {
|
||||||
|
std::vec::Vec<#return_type_name>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
#return_type_name
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((
|
||||||
|
result_type,
|
||||||
|
quote! {
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct #return_type_name {
|
||||||
|
#(#parameters,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#(#enum_types)*
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user