redis_module_ext_macros/
utils.rs1use 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}