upgrade to syn 2.x
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
3b5607ecdc
commit
ca82b59c6f
11 changed files with 138 additions and 99 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -731,9 +731,10 @@ dependencies = [
|
|||
name = "conduit_macros"
|
||||
version = "0.4.5"
|
||||
dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.71",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -426,7 +426,7 @@ default-features = false
|
|||
version = "0.1"
|
||||
|
||||
[workspace.dependencies.syn]
|
||||
version = "1.0"
|
||||
version = "2.0"
|
||||
features = ["full", "extra-traits"]
|
||||
|
||||
[workspace.dependencies.quote]
|
||||
|
|
|
@ -16,19 +16,19 @@ use crate::Result;
|
|||
|
||||
#[cargo_manifest]
|
||||
const WORKSPACE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("macros")]
|
||||
#[cargo_manifest(crate = "macros")]
|
||||
const MACROS_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("core")]
|
||||
#[cargo_manifest(crate = "core")]
|
||||
const CORE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("database")]
|
||||
#[cargo_manifest(crate = "database")]
|
||||
const DATABASE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("service")]
|
||||
#[cargo_manifest(crate = "service")]
|
||||
const SERVICE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("admin")]
|
||||
#[cargo_manifest(crate = "admin")]
|
||||
const ADMIN_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("router")]
|
||||
#[cargo_manifest(crate = "router")]
|
||||
const ROUTER_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("main")]
|
||||
#[cargo_manifest(crate = "main")]
|
||||
const MAIN_MANIFEST: &'static str = ();
|
||||
|
||||
/// Processed list of features access all project crates. This is generated from
|
||||
|
|
|
@ -18,6 +18,7 @@ proc-macro = true
|
|||
syn.workspace = true
|
||||
quote.workspace = true
|
||||
proc-macro2.workspace = true
|
||||
itertools.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
use itertools::Itertools;
|
||||
use proc_macro::{Span, TokenStream};
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, AttributeArgs, Fields, Ident, ItemEnum, Variant};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{Error, Fields, Ident, ItemEnum, Meta, Variant};
|
||||
|
||||
use crate::utils::camel_to_snake_string;
|
||||
use crate::{utils::camel_to_snake_string, Result};
|
||||
|
||||
pub(super) fn command_dispatch(args: TokenStream, input_: TokenStream) -> TokenStream {
|
||||
let input = input_.clone();
|
||||
let item = parse_macro_input!(input as ItemEnum);
|
||||
let _args = parse_macro_input!(args as AttributeArgs);
|
||||
let arm = item.variants.iter().map(dispatch_arm);
|
||||
let name = item.ident;
|
||||
let q = quote! {
|
||||
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! {
|
||||
pub(super) async fn process(command: #name, body: Vec<&str>) -> Result<RoomMessageEventContent> {
|
||||
use #name::*;
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -21,14 +19,17 @@ pub(super) fn command_dispatch(args: TokenStream, input_: TokenStream) -> TokenS
|
|||
}
|
||||
};
|
||||
|
||||
[input_, q.into()].into_iter().collect::<TokenStream>()
|
||||
Ok([item.into_token_stream(), switch]
|
||||
.into_iter()
|
||||
.collect::<TokenStream2>()
|
||||
.into())
|
||||
}
|
||||
|
||||
fn dispatch_arm(v: &Variant) -> TokenStream2 {
|
||||
fn dispatch_arm(v: &Variant) -> Result<TokenStream2> {
|
||||
let name = &v.ident;
|
||||
let target = camel_to_snake_string(&format!("{name}"));
|
||||
let handler = Ident::new(&target, Span::call_site().into());
|
||||
match &v.fields {
|
||||
let res = match &v.fields {
|
||||
Fields::Named(fields) => {
|
||||
let field = fields.named.iter().filter_map(|f| f.ident.as_ref());
|
||||
let arg = field.clone();
|
||||
|
@ -37,7 +38,9 @@ fn dispatch_arm(v: &Variant) -> TokenStream2 {
|
|||
}
|
||||
},
|
||||
Fields::Unnamed(fields) => {
|
||||
let field = &fields.unnamed.first().expect("one field");
|
||||
let Some(ref field) = fields.unnamed.first() else {
|
||||
return Err(Error::new(Span::call_site().into(), "One unnamed field required"));
|
||||
};
|
||||
quote! {
|
||||
#name ( #field ) => Box::pin(#handler::process(#field, body)).await?,
|
||||
}
|
||||
|
@ -47,5 +50,7 @@ fn dispatch_arm(v: &Variant) -> TokenStream2 {
|
|||
#name => Box::pin(#handler(&body)).await?,
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
|
|
@ -1,39 +1,34 @@
|
|||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, AttributeArgs, ItemConst, Lit, NestedMeta};
|
||||
use syn::{Error, ItemConst, Meta};
|
||||
|
||||
pub(super) fn manifest(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let item = parse_macro_input!(item as ItemConst);
|
||||
let args = parse_macro_input!(args as AttributeArgs);
|
||||
let member = args.into_iter().find_map(|arg| {
|
||||
let NestedMeta::Lit(arg) = arg else {
|
||||
return None;
|
||||
};
|
||||
let Lit::Str(arg) = arg else {
|
||||
return None;
|
||||
};
|
||||
Some(arg.value())
|
||||
});
|
||||
use crate::{utils, Result};
|
||||
|
||||
let path = manifest_path(member.as_deref());
|
||||
pub(super) fn manifest(item: ItemConst, args: &[Meta]) -> Result<TokenStream> {
|
||||
let member = utils::get_named_string(args, "crate");
|
||||
let path = manifest_path(member.as_deref())?;
|
||||
let manifest = read_to_string(&path).unwrap_or_default();
|
||||
|
||||
let name = item.ident;
|
||||
let val = manifest.as_str();
|
||||
let name = item.ident;
|
||||
let ret = quote! {
|
||||
const #name: &'static str = #val;
|
||||
};
|
||||
|
||||
ret.into()
|
||||
Ok(ret.into())
|
||||
}
|
||||
|
||||
#[allow(clippy::option_env_unwrap)]
|
||||
fn manifest_path(member: Option<&str>) -> PathBuf {
|
||||
let mut path: PathBuf = option_env!("CARGO_MANIFEST_DIR")
|
||||
.expect("missing CARGO_MANIFEST_DIR in environment")
|
||||
.into();
|
||||
fn manifest_path(member: Option<&str>) -> Result<PathBuf> {
|
||||
let Some(path) = option_env!("CARGO_MANIFEST_DIR") else {
|
||||
return Err(Error::new(
|
||||
Span::call_site().into(),
|
||||
"missing CARGO_MANIFEST_DIR in environment",
|
||||
));
|
||||
};
|
||||
|
||||
let mut path: PathBuf = path.into();
|
||||
|
||||
// conduwuit/src/macros/ -> conduwuit/src/
|
||||
path.pop();
|
||||
|
@ -47,5 +42,6 @@ fn manifest_path(member: Option<&str>) -> PathBuf {
|
|||
}
|
||||
|
||||
path.push("Cargo.toml");
|
||||
path
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use std::cmp;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{parse_macro_input, AttributeArgs, Item};
|
||||
use quote::ToTokens;
|
||||
use syn::{Item, Meta};
|
||||
|
||||
pub(super) fn recursion_depth(args: TokenStream, item_: TokenStream) -> TokenStream {
|
||||
let item = item_.clone();
|
||||
let item = parse_macro_input!(item as Item);
|
||||
let _args = parse_macro_input!(args as AttributeArgs);
|
||||
use crate::Result;
|
||||
|
||||
pub(super) fn recursion_depth(item: Item, _args: &[Meta]) -> Result<TokenStream> {
|
||||
let mut best: usize = 0;
|
||||
let mut count: usize = 0;
|
||||
// think you'd find a fancy recursive ast visitor? think again
|
||||
|
@ -24,5 +23,5 @@ pub(super) fn recursion_depth(args: TokenStream, item_: TokenStream) -> TokenStr
|
|||
println!("DEPTH: {best}");
|
||||
println!("LENGTH: {count}");
|
||||
|
||||
item_
|
||||
Ok(item.into_token_stream().into())
|
||||
}
|
||||
|
|
|
@ -1,23 +1,26 @@
|
|||
use proc_macro::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{parse_macro_input, AttributeArgs, ItemFn, Meta, NestedMeta};
|
||||
use quote::quote;
|
||||
use syn::{ItemFn, Meta, MetaList};
|
||||
|
||||
pub(super) fn implement(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let args = parse_macro_input!(args as AttributeArgs);
|
||||
let item = parse_macro_input!(input as ItemFn);
|
||||
use crate::Result;
|
||||
|
||||
let NestedMeta::Meta(Meta::Path(receiver)) = args
|
||||
pub(super) fn implement(item: ItemFn, args: &[Meta]) -> Result<TokenStream> {
|
||||
let Meta::List(MetaList {
|
||||
path,
|
||||
..
|
||||
}) = &args
|
||||
.first()
|
||||
.expect("missing path to trait or item to implement")
|
||||
else {
|
||||
panic!("invalid path to item for implement");
|
||||
};
|
||||
|
||||
let input = item;
|
||||
let out = quote! {
|
||||
impl #receiver {
|
||||
#item
|
||||
impl #path {
|
||||
#input
|
||||
}
|
||||
};
|
||||
|
||||
out.into_token_stream().into()
|
||||
Ok(out.into())
|
||||
}
|
||||
|
|
|
@ -7,23 +7,50 @@ mod rustc;
|
|||
mod utils;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{
|
||||
parse::{Parse, Parser},
|
||||
parse_macro_input, Error, Item, ItemConst, ItemEnum, ItemFn, Meta,
|
||||
};
|
||||
|
||||
pub(crate) type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn admin_command_dispatch(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
admin::command_dispatch(args, input)
|
||||
attribute_macro::<ItemEnum, _>(args, input, admin::command_dispatch)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn cargo_manifest(args: TokenStream, input: TokenStream) -> TokenStream { cargo::manifest(args, input) }
|
||||
pub fn cargo_manifest(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
attribute_macro::<ItemConst, _>(args, input, cargo::manifest)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn recursion_depth(args: TokenStream, input: TokenStream) -> TokenStream { debug::recursion_depth(args, input) }
|
||||
pub fn recursion_depth(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
attribute_macro::<Item, _>(args, input, debug::recursion_depth)
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn rustc_flags_capture(args: TokenStream) -> TokenStream { rustc::flags_capture(args) }
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn refutable(args: TokenStream, input: TokenStream) -> TokenStream { refutable::refutable(args, input) }
|
||||
pub fn refutable(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
attribute_macro::<ItemFn, _>(args, input, refutable::refutable)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn implement(args: TokenStream, input: TokenStream) -> TokenStream { implement::implement(args, input) }
|
||||
pub fn implement(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
attribute_macro::<ItemFn, _>(args, input, implement::implement)
|
||||
}
|
||||
|
||||
fn attribute_macro<I, F>(args: TokenStream, input: TokenStream, func: F) -> TokenStream
|
||||
where
|
||||
F: Fn(I, &[Meta]) -> Result<TokenStream>,
|
||||
I: Parse,
|
||||
{
|
||||
let item = parse_macro_input!(input as I);
|
||||
syn::punctuated::Punctuated::<Meta, syn::Token![,]>::parse_terminated
|
||||
.parse(args)
|
||||
.map(|args| args.iter().cloned().collect::<Vec<_>>())
|
||||
.and_then(|ref args| func(item, args))
|
||||
.unwrap_or_else(|e| e.to_compile_error().into())
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use proc_macro::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{parse_macro_input, AttributeArgs, FnArg::Typed, Ident, ItemFn, Pat, PatIdent, PatType, Stmt};
|
||||
use syn::{FnArg::Typed, Ident, ItemFn, Meta, Pat, PatIdent, PatType, Stmt};
|
||||
|
||||
pub(super) fn refutable(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let _args = parse_macro_input!(args as AttributeArgs);
|
||||
let mut item = parse_macro_input!(input as ItemFn);
|
||||
use crate::Result;
|
||||
|
||||
pub(super) fn refutable(mut item: ItemFn, _args: &[Meta]) -> Result<TokenStream> {
|
||||
let inputs = item.sig.inputs.clone();
|
||||
let stmt = &mut item.block.stmts;
|
||||
let sig = &mut item.sig;
|
||||
|
@ -25,37 +24,30 @@ pub(super) fn refutable(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
let variant = &pat.path;
|
||||
let fields = &pat.fields;
|
||||
|
||||
// new versions of syn can replace this kronecker kludge with get_mut()
|
||||
for (j, input) in sig.inputs.iter_mut().enumerate() {
|
||||
if i != j {
|
||||
continue;
|
||||
}
|
||||
let Some(Typed(PatType {
|
||||
ref mut pat,
|
||||
..
|
||||
})) = sig.inputs.get_mut(i)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Typed(PatType {
|
||||
ref mut pat,
|
||||
..
|
||||
}) = input
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let name = format!("_args_{i}");
|
||||
*pat = Box::new(Pat::Ident(PatIdent {
|
||||
ident: Ident::new(&name, Span::call_site().into()),
|
||||
attrs: Vec::new(),
|
||||
by_ref: None,
|
||||
mutability: None,
|
||||
subpat: None,
|
||||
}));
|
||||
|
||||
let name = format!("_args_{i}");
|
||||
*pat = Box::new(Pat::Ident(PatIdent {
|
||||
ident: Ident::new(&name, Span::call_site().into()),
|
||||
attrs: Vec::new(),
|
||||
by_ref: None,
|
||||
mutability: None,
|
||||
subpat: None,
|
||||
}));
|
||||
let field = fields.iter();
|
||||
let refute = quote! {
|
||||
let #variant { #( #field ),*, .. } = #name else { panic!("incorrect variant passed to function argument {i}"); };
|
||||
};
|
||||
|
||||
let field = fields.iter();
|
||||
let refute = quote! {
|
||||
let #variant { #( #field ),*, .. } = #name else { panic!("incorrect variant passed to function argument {i}"); };
|
||||
};
|
||||
|
||||
stmt.insert(0, syn::parse2::<Stmt>(refute).expect("syntax error"));
|
||||
}
|
||||
stmt.insert(0, syn::parse2::<Stmt>(refute)?);
|
||||
}
|
||||
|
||||
item.into_token_stream().into()
|
||||
Ok(item.into_token_stream().into())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
use syn::{Expr, Lit, Meta};
|
||||
|
||||
pub(crate) fn get_named_string(args: &[Meta], name: &str) -> Option<String> {
|
||||
args.iter().find_map(|arg| {
|
||||
let value = arg.require_name_value().ok()?;
|
||||
let Expr::Lit(ref lit) = value.value else {
|
||||
return None;
|
||||
};
|
||||
let Lit::Str(ref str) = lit.lit else {
|
||||
return None;
|
||||
};
|
||||
value.path.is_ident(name).then_some(str.value())
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn camel_to_snake_string(s: &str) -> String {
|
||||
let mut output = String::with_capacity(
|
||||
|
|
Loading…
Add table
Reference in a new issue