Files
continuwuity/src/macros/admin.rs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

57 lines
1.6 KiB
Rust
Raw Normal View History

2024-07-26 20:40:07 +00:00
use itertools::Itertools;
2024-07-24 00:14:03 +00:00
use proc_macro::{Span, TokenStream};
use proc_macro2::TokenStream as TokenStream2;
2024-07-26 20:40:07 +00:00
use quote::{quote, ToTokens};
use syn::{Error, Fields, Ident, ItemEnum, Meta, Variant};
2024-07-24 00:14:03 +00:00
2024-07-26 20:40:07 +00:00
use crate::{utils::camel_to_snake_string, Result};
2024-07-24 03:55:01 +00:00
2024-07-26 20:40:07 +00:00
pub(super) fn command_dispatch(item: ItemEnum, _args: &[Meta]) -> Result<TokenStream> {
let name = &item.ident;
let arm: Vec<TokenStream2> = item.variants.iter().map(dispatch_arm).try_collect()?;
let switch = quote! {
2024-07-24 00:14:03 +00:00
pub(super) async fn process(command: #name, body: Vec<&str>) -> Result<RoomMessageEventContent> {
use #name::*;
#[allow(non_snake_case)]
Ok(match command {
#( #arm )*
})
}
};
2024-07-26 20:40:07 +00:00
Ok([item.into_token_stream(), switch]
.into_iter()
.collect::<TokenStream2>()
.into())
2024-07-24 00:14:03 +00:00
}
2024-07-26 20:40:07 +00:00
fn dispatch_arm(v: &Variant) -> Result<TokenStream2> {
2024-07-24 00:14:03 +00:00
let name = &v.ident;
let target = camel_to_snake_string(&format!("{name}"));
let handler = Ident::new(&target, Span::call_site().into());
2024-07-26 20:40:07 +00:00
let res = match &v.fields {
2024-07-24 00:14:03 +00:00
Fields::Named(fields) => {
let field = fields.named.iter().filter_map(|f| f.ident.as_ref());
let arg = field.clone();
quote! {
2024-07-24 01:26:23 +00:00
#name { #( #field ),* } => Box::pin(#handler(&body, #( #arg ),*)).await?,
2024-07-24 00:14:03 +00:00
}
},
Fields::Unnamed(fields) => {
2024-07-26 20:40:07 +00:00
let Some(ref field) = fields.unnamed.first() else {
return Err(Error::new(Span::call_site().into(), "One unnamed field required"));
};
2024-07-24 00:14:03 +00:00
quote! {
#name ( #field ) => Box::pin(#handler::process(#field, body)).await?,
}
},
Fields::Unit => {
quote! {
2024-07-24 01:26:23 +00:00
#name => Box::pin(#handler(&body)).await?,
2024-07-24 00:14:03 +00:00
}
},
2024-07-26 20:40:07 +00:00
};
Ok(res)
2024-07-24 00:14:03 +00:00
}