redis_module_ext_macros/
utils.rs

1use std::ffi::CString;
2
3use proc_macro2::TokenStream;
4use syn::Token;
5use syn::parse::Parser;
6
7pub fn repeated_parse<T: syn::parse::Parse>(item: &syn::Meta) -> darling::Result<Vec<T>> {
8    match item {
9        syn::Meta::List(list) => Ok(syn::punctuated::Punctuated::<T, Token![,]>::parse_terminated
10            .parse2(list.tokens.clone())
11            .map(|punctuated| punctuated.into_iter().collect())?),
12        _ => Err(darling::Error::custom("expected list").with_span(item)),
13    }
14}
15
16pub fn format_command_ident(ident: &syn::Ident) -> syn::Ident {
17    quote::format_ident!("__command__{ident}").set_span(ident.span())
18}
19
20pub fn str_to_cstr(s: &syn::LitStr) -> syn::Result<syn::LitCStr> {
21    let Ok(cstr) = CString::new(s.value()) else {
22        return Err(syn::Error::new(s.span(), "string cannot have nul bytes"));
23    };
24
25    Ok(syn::LitCStr::new(&cstr, s.span()))
26}
27
28pub fn opt_to_tokens<T: quote::ToTokens>(opt: Option<T>) -> TokenStream {
29    match opt {
30        Some(opt) => quote::quote!(::core::option::Option::Some(#opt)),
31        None => quote::quote!(::core::option::Option::None),
32    }
33}
34
35pub fn collect_to_vec<T: quote::ToTokens>(items: impl IntoIterator<Item = T>) -> TokenStream {
36    let items = items.into_iter();
37    quote::quote! {
38        ::std::vec::Vec::from(::std::boxed::Box::new([#(#items),*]) as ::std::boxed::Box<[_]>)
39    }
40}
41
42pub trait SetSpan {
43    fn set_span(&self, span: proc_macro2::Span) -> Self;
44}
45
46impl<T> SetSpan for T
47where
48    T: quote::ToTokens + syn::parse::Parse,
49{
50    fn set_span(&self, span: proc_macro2::Span) -> Self {
51        syn::LitStr::new(&self.to_token_stream().to_string(), span).parse().unwrap()
52    }
53}