actix_cloud_codegen/
lib.rs1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2
3use proc_macro::TokenStream;
4use quote::quote;
5#[cfg(feature = "i18n")]
6use std::{collections::HashMap, env, path};
7
8#[cfg(feature = "i18n")]
9mod i18n;
10
11#[proc_macro_attribute]
12pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
13 let mut output: TokenStream = (quote! {
14 #[actix_cloud::actix_web::rt::main(system = "actix_cloud::actix_web::rt::System")]
15 })
16 .into();
17
18 output.extend(item);
19 output
20}
21
22#[cfg(feature = "i18n")]
23#[proc_macro]
35pub fn i18n(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
36 let option = match syn::parse::<i18n::Option>(input) {
37 Ok(input) => input,
38 Err(err) => return err.to_compile_error().into(),
39 };
40
41 let cargo_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is empty");
43 let current_dir = path::PathBuf::from(cargo_dir);
44 let locales_path = current_dir.join(option.locales_path);
45
46 let data = rust_i18n_support::load_locales(&locales_path.display().to_string(), |_| false);
47 let mut translation = HashMap::new();
48 for (lang, mp) in data {
49 for (k, v) in mp {
50 translation.insert(format!("{lang}.{k}"), v);
51 }
52 }
53 let code = i18n::generate_code(&translation);
54
55 if rust_i18n_support::is_debug() {
56 println!("{code}");
57 }
58
59 code.into()
60}
61
62#[cfg(feature = "seaorm")]
63#[proc_macro_attribute]
79pub fn entity_timestamp(_: TokenStream, input: TokenStream) -> TokenStream {
80 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
81 entity.items.push(syn::parse_quote!(
82 fn entity_timestamp(&self, e: &mut Self, insert: bool) {
83 let tm: sea_orm::ActiveValue<i64> =
84 sea_orm::ActiveValue::set(chrono::Utc::now().timestamp_millis());
85 if insert {
86 e.created_at = tm.clone();
87 e.updated_at = tm.clone();
88 } else {
89 e.updated_at = tm.clone();
90 }
91 }
92 ));
93 quote! {
94 #entity
95 }
96 .into()
97}
98
99#[cfg(feature = "seaorm")]
100#[proc_macro_attribute]
115pub fn entity_id(attr: TokenStream, input: TokenStream) -> TokenStream {
116 let attr = syn::parse_macro_input!(attr as syn::ExprCall);
117 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
118 entity.items.push(syn::parse_quote!(
119 fn entity_id(&self, e: &mut Self, insert: bool) {
120 if insert && e.id.is_not_set() {
121 e.id = sea_orm::ActiveValue::set(#attr);
122 }
123 }
124 ));
125 quote! {
126 #entity
127 }
128 .into()
129}
130
131#[cfg(feature = "seaorm")]
132#[proc_macro_attribute]
146pub fn entity_behavior(_: TokenStream, input: TokenStream) -> TokenStream {
147 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
148
149 entity.items.push(syn::parse_quote!(
150 async fn before_save<C>(self, _: &C, insert: bool) -> Result<Self, DbErr>
151 where
152 C: ConnectionTrait,
153 {
154 let mut new = self.clone();
155 self.entity_id(&mut new, insert);
156 self.entity_timestamp(&mut new, insert);
157 Ok(new)
158 }
159 ));
160 quote! {
161 #[async_trait::async_trait]
162 #entity
163 }
164 .into()
165}
166
167#[cfg(feature = "seaorm")]
168#[proc_macro_attribute]
187pub fn partial_entity(attr: TokenStream, input: TokenStream) -> TokenStream {
188 let attr = syn::parse_macro_input!(attr as syn::ExprPath);
189 let input = syn::parse_macro_input!(input as syn::ItemStruct);
190 let name = &input.ident;
191 let mut fields = Vec::new();
192 for i in &input.fields {
193 let field_name = &i.ident;
194 fields.push(quote!(#field_name: self.#field_name,));
195 }
196
197 quote! {
198 #input
199 impl Into<#name> for #attr {
200 fn into(self) -> #name {
201 #name {
202 #(#fields)*
203 }
204 }
205 }
206 }
207 .into()
208}