Hi,
I have tried my hand at a macro that should wrap slog macro calls to make it easier to have consistent messages.
I can use this macro like this:
gen_log_error!(1010, "Things are {how} bad");
Which generates a mcro called log_error_1010
.
I have one issue and one question:
Issue
Whenever I try to call my macro from another crate I get an error:
use of undeclared type or module `slog`
I'm not sure why.
In my proc_macro created I declared slog as a dependency so it should transitively be also available in the crate using it, no?
I've also specified the full name slog::error
What am I missing?
Question
I'd love to auto generate documentation for the inner macro and put all required named arguments in it.
In my example above I'd love to say that how is a required parameter.
But I can't find a way to parse the string and get the named arguments. format_args
requires a string literal which I don't have at that point.
Any ideas?
Bonus Question: Does another library maybe already exist to define log message catalogs?
Here is the code in full
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::parse::{Parse, ParseStream, Result};
use syn::{parse_macro_input, ExprLit, Lit, Token};
struct Log {
code: ExprLit,
msg: ExprLit,
}
impl Parse for Log {
fn parse(input: ParseStream) -> Result<Self> {
let code: ExprLit = input.parse()?;
input.parse::<Token![,]>()?;
let msg = input.parse()?;
Ok(Log {
code,
msg
})
}
}
#[proc_macro]
pub fn gen_log_error(input: TokenStream) -> TokenStream {
let Log {
code,
msg
} = parse_macro_input!(input as Log);
let code = match &code.lit {
Lit::Int(code) => code,
_ => panic!("[code] needs to be Not a number")
};
let msg = match &msg.lit {
Lit::Str(msg) => msg,
_ => panic!("[msg] needs to be a string literal")
};
let msg = format!("E{code}: {msg}", code = code, msg = msg.value());
let macro_name= format_ident!("log_error_{}", code.base10_digits());
let expanded = quote! {
macro_rules! #macro_name {
($log:expr, #$tag:expr, $($arg:tt)*) => {
slog::error!($log, #$tag, #msg, $($arg)*);
};
($log:expr, $($arg:tt)*) => {
slog::error!($log, #msg, $($arg)*);
}
}
};
TokenStream::from(expanded)
}
This is my very first time using Rust so any other pointers are welcome as well.