actix_cloud/
response_build.rs1use anyhow::Result;
7use quote::{format_ident, quote};
8use std::{
9 env,
10 fs::{read_to_string, File},
11 io::Write,
12 path::Path,
13};
14use walkdir::WalkDir;
15use yaml_rust2::YamlLoader;
16
17#[derive(thiserror::Error, Debug)]
19pub enum BuildError {
20 #[error("response file format invalid")]
22 Format,
23
24 #[error("response file name invalid")]
26 File,
27}
28
29pub fn generate_response(import_prefix: &str, input: &str, output: &str) -> Result<()> {
51 let outfile = Path::new(&env::var("OUT_DIR")?).join(output);
52 let mut output = File::create(&outfile)?;
53 writeln!(
54 output,
55 "use {}actix_cloud::response::ResponseCodeTrait;",
56 import_prefix
57 )?;
58 for entry in WalkDir::new(input) {
59 let entry = entry?;
60 if entry.file_type().is_file() {
61 let file = read_to_string(entry.path())?;
62 let yaml = YamlLoader::load_from_str(&file)?;
63 let doc = &yaml[0];
64 let mut name_vec = Vec::new();
65 let mut code_vec = Vec::new();
66 let mut message_vec = Vec::new();
67 for (name, field) in doc.as_hash().ok_or(BuildError::Format)? {
68 name_vec.push(format_ident!(
69 "{}",
70 name.as_str().ok_or(BuildError::Format)?
71 ));
72 code_vec.push(field["code"].as_i64().ok_or(BuildError::Format)?);
73 message_vec.push(field["message"].as_str().ok_or(BuildError::Format)?);
74 }
75
76 let file_stem = entry.path().file_stem().ok_or(BuildError::File)?;
77 let stem = file_stem.to_str().ok_or(BuildError::File)?;
78 if stem.is_empty()
79 || !stem.starts_with(|c: char| c.is_alphabetic() || c == '_')
80 || !stem.chars().all(|c| c.is_alphanumeric() || c == '_')
81 {
82 return Err(BuildError::File.into());
83 }
84 let mut chars = stem.chars();
85 let s = chars.next().unwrap().to_uppercase().collect::<String>() + chars.as_str();
86 let enum_name = format_ident!("{}Response", s);
87 let mut enum_code = Vec::new();
88 for i in 0..code_vec.len() {
89 let s = &name_vec[i];
90 let c = code_vec[i];
91 enum_code.push(quote! {#enum_name::#s => #c});
92 }
93 let mut enum_message = Vec::new();
94 for i in 0..code_vec.len() {
95 let s = &name_vec[i];
96 let c = message_vec[i];
97 enum_message.push(quote! {#enum_name::#s => #c});
98 }
99 let content = quote! {
100 pub enum #enum_name {
101 #(#name_vec),*
102 }
103
104 impl ResponseCodeTrait for #enum_name {
105 fn code(&self) -> i64 {
106 match self {
107 #(#enum_code),*
108 }
109 }
110
111 fn message(&self) -> &'static str {
112 match self {
113 #(#enum_message),*
114 }
115 }
116 }
117 };
118
119 write!(
120 output,
121 "{}",
122 prettyplease::unparse(&syn::parse_file(&content.to_string())?)
123 )?;
124 }
125 }
126 Ok(())
127}