Extract more fields

This commit is contained in:
Joel Wachsler 2022-07-12 16:01:47 +00:00
parent 5f120f39fc
commit 5b70b293b9
4 changed files with 108 additions and 83 deletions

View File

@ -15,81 +15,22 @@ pub fn create_return_type(
None => return None,
};
let to_enum_name = |name: &str| {
format!(
"{}{}{}",
group.name.to_camel(),
method.name.to_camel(),
name.to_camel()
)
};
let to_enum_name = |name: &str| to_enum_name(&group.name, &method.name, name);
let enum_types_with_names = return_type
.parameters
.iter()
.flat_map(|parameter| match &parameter.return_type {
types::Type::Number(types::TypeInfo {
ref name,
type_description: Some(type_description),
..
}) => create_enum_field_value(type_description, name, create_number_enum_value),
types::Type::String(types::TypeInfo {
ref name,
type_description: Some(type_description),
..
}) => create_enum_field_value(type_description, name, create_string_enum_value),
_ => None,
})
.flat_map(|(name, enum_fields)| {
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,)*
}
},
))
});
let enum_types_with_names: Vec<(String, proc_macro2::TokenStream)> =
create_enum_with_names(return_type, &group.name, &method.name);
let enum_names: HashMap<String, String> = enum_types_with_names
.clone()
.map(|(enum_name, _)| (enum_name.clone(), to_enum_name(&enum_name)))
.iter()
.map(|(enum_name, _)| (enum_name.clone(), to_enum_name(enum_name)))
.collect();
let enum_types = enum_types_with_names.map(|(_, enum_type)| enum_type);
let enum_types = enum_types_with_names.iter().map(|(_, enum_type)| enum_type);
let builder_fields = return_type.parameters.iter().map(|parameter| {
let namestr = &parameter.name;
let name = util::to_ident(&namestr.to_snake().replace("__", "_"));
let enum_name = match enum_names.get(namestr) {
Some(enum_type) => enum_type.to_owned(),
None => parameter.return_type.to_owned_type(),
};
let rtype = util::to_ident(&enum_name);
let rtype_as_quote = if parameter.return_type.get_type_info().is_list {
quote! { std::vec::Vec<#rtype> }
} else {
quote! { #rtype }
};
let generate_field = |field_name| {
quote! {
#[serde(rename = #namestr)]
pub #field_name: #rtype_as_quote
}
};
// "type" is a reserved keyword in Rust, so we just add "t_" to it.
if namestr == "type" {
generate_field(format_ident!("t_{}", name))
} else {
generate_field(name)
}
});
let builder_fields = return_type
.parameters
.iter()
.map(|parameter| generate_builder_field(parameter, &enum_names));
let return_type_name = util::to_ident(&format!(
"{}{}Result",
@ -98,13 +39,9 @@ pub fn create_return_type(
));
let result_type = if return_type.is_list {
quote! {
std::vec::Vec<#return_type_name>
}
quote! { std::vec::Vec<#return_type_name> }
} else {
quote! {
#return_type_name
}
quote! { #return_type_name }
};
Some((
@ -120,6 +57,87 @@ pub fn create_return_type(
))
}
fn create_enum_with_names(
return_type: &parser::ReturnType,
group_name: &str,
method_name: &str,
) -> Vec<(String, proc_macro2::TokenStream)> {
return_type
.parameters
.iter()
.flat_map(create_enum_fields)
.map(|(name, enum_fields)| create_enum(enum_fields, group_name, method_name, name))
.collect()
}
fn create_enum(
enum_fields: Vec<proc_macro2::TokenStream>,
group_name: &str,
method_name: &str,
name: String,
) -> (String, proc_macro2::TokenStream) {
let enum_name = util::to_ident(&to_enum_name(group_name, method_name, &name));
(
name,
quote! {
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub enum #enum_name {
#(#enum_fields,)*
}
},
)
}
fn create_enum_fields(
parameter: &parser::ReturnTypeParameter,
) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
match &parameter.return_type {
types::Type::Number(types::TypeInfo {
ref name,
type_description: Some(type_description),
..
}) => create_enum_field_value(type_description, name, create_number_enum_value),
types::Type::String(types::TypeInfo {
ref name,
type_description: Some(type_description),
..
}) => create_enum_field_value(type_description, name, create_string_enum_value),
_ => None,
}
}
fn generate_builder_field(
parameter: &parser::ReturnTypeParameter,
enum_names: &HashMap<String, String>,
) -> proc_macro2::TokenStream {
let namestr = &parameter.name;
let name = util::to_ident(&namestr.to_snake().replace("__", "_"));
let enum_name = match enum_names.get(namestr) {
Some(enum_type) => enum_type.to_owned(),
None => parameter.return_type.to_owned_type(),
};
let rtype = util::to_ident(&enum_name);
let rtype_as_quote = if parameter.return_type.get_type_info().is_list {
quote! { std::vec::Vec<#rtype> }
} else {
quote! { #rtype }
};
let generate_field = |field_name| {
quote! {
#[serde(rename = #namestr)]
pub #field_name: #rtype_as_quote
}
};
// "type" is a reserved keyword in Rust, so we just add "t_" to it.
if namestr == "type" {
generate_field(format_ident!("t_{}", name))
} else {
generate_field(name)
}
}
fn create_enum_field_value<F>(
type_description: &types::TypeDescription,
name: &str,
@ -174,3 +192,12 @@ fn create_enum_field(
},
)
}
fn to_enum_name(group_name: &str, method_name: &str, name: &str) -> String {
format!(
"{}{}{}",
group_name.to_camel(),
method_name.to_camel(),
name.to_camel()
)
}

View File

@ -5,11 +5,11 @@ mod url;
use crate::{md_parser, parser::util, types};
pub use return_type::ReturnType;
use self::{
description::parse_method_description,
parameters::parse_parameters,
return_type::{parse_return_type, ReturnType},
url::get_method_url,
description::parse_method_description, parameters::parse_parameters,
return_type::parse_return_type, url::get_method_url,
};
#[derive(Debug)]

View File

@ -5,6 +5,7 @@ mod url;
use crate::md_parser;
use self::{description::parse_group_description, method::parse_api_method, url::get_group_url};
pub use method::{ApiMethod, ReturnType};
#[derive(Debug)]
pub struct ApiGroup {
@ -14,8 +15,6 @@ pub struct ApiGroup {
pub url: String,
}
pub use method::ApiMethod;
pub fn parse_api_group(tree: &md_parser::TokenTree) -> ApiGroup {
let methods = tree.children.iter().flat_map(parse_api_method).collect();

View File

@ -12,8 +12,7 @@ pub struct ReturnTypeParameter {
pub return_type: types::Type,
}
pub use group::ApiGroup;
pub use group::ApiMethod;
pub use group::{ApiGroup, ApiMethod, ReturnType};
pub fn parse_api_groups(token_tree: md_parser::TokenTree) -> Vec<ApiGroup> {
parse_groups(extract_relevant_parts(token_tree))