serde_columnar_derive/
args.rs

1use std::collections::BTreeSet;
2
3use darling::ast::NestedMeta;
4#[allow(unused_imports)]
5use darling::{util::Override, Error as DarlingError, FromField, FromMeta, FromVariant};
6use proc_macro2::{Spacing, TokenTree};
7#[allow(unused_imports)]
8use proc_macro2::{Span, TokenStream};
9use quote::ToTokens;
10use syn::{parse::ParseStream, spanned::Spanned, DeriveInput, Lifetime, LitStr, Token, Type};
11
12#[derive(Debug, Clone, Copy, FromMeta)]
13pub struct DeriveArgs {
14    #[darling(default)]
15    pub(crate) vec: bool,
16    #[darling(rename = "map", default)]
17    pub(crate) hashmap: bool,
18    #[darling(default)]
19    pub(crate) ser: bool,
20    #[darling(default)]
21    pub(crate) de: bool,
22    // only row struct
23    #[darling(default)]
24    pub(crate) iterable: bool,
25}
26
27#[derive(FromField, Debug, Clone)]
28#[darling(attributes(columnar))]
29pub struct FieldArgs {
30    /// the name of field
31    pub ident: Option<syn::Ident>,
32    // pub vis: syn::Visibility,
33    /// the type of field
34    pub ty: Type,
35    // custom attributes
36    /// The index of the field in the struct, starts from 0 default.
37    pub index: Option<usize>,
38    /// If optional, this field need to be compatible with the old or new version.
39    #[darling(default)]
40    pub optional: bool,
41    /// the strategy to convert the field values to a column.
42    pub strategy: Option<String>,
43    /// the type of the column format, vec or map.
44    pub class: Option<String>,
45    /// Same as the `borrow` of `serde`
46    pub borrow: Option<Override<LitStr>>,
47    /// Same as the `skip` of serde
48    #[darling(default)]
49    pub skip: bool,
50    pub iter: Option<Type>,
51}
52
53#[derive(Debug, Clone, Copy)]
54pub enum Strategy {
55    Rle,
56    DeltaRle,
57    BoolRle,
58    DeltaOfDelta,
59    None,
60}
61
62impl Strategy {
63    fn from_str(s: Option<String>) -> Self {
64        if let Some(s) = s {
65            match s.as_str() {
66                "Rle" => Self::Rle,
67                "DeltaRle" => Self::DeltaRle,
68                "BoolRle" => Self::BoolRle,
69                "DeltaOfDelta" => Self::DeltaOfDelta,
70                _ => unreachable!("strategy should be Rle, BoolRle or DeltaRle"),
71            }
72        } else {
73            Self::None
74        }
75    }
76}
77
78pub enum AsType {
79    Vec,
80    Map,
81    Other,
82}
83
84pub trait Args {
85    // fn ident(&self) -> Option<syn::Ident>;
86    fn ty(&self) -> Option<syn::Type>;
87    // fn index(&self) -> Option<usize>;
88    // fn optional(&self) -> bool;
89    fn strategy(&self) -> Strategy;
90    fn can_copy(&self) -> bool {
91        match self.strategy() {
92            Strategy::BoolRle | Strategy::DeltaRle | Strategy::DeltaOfDelta => true,
93            Strategy::Rle | Strategy::None => false,
94        }
95    }
96    fn class(&self) -> Option<AsType>;
97    fn has_borrow_lifetime(&self) -> bool;
98    fn borrow_lifetimes(&self) -> syn::Result<Option<BTreeSet<Lifetime>>>;
99    fn self_lifetime(&self) -> syn::Result<BTreeSet<Lifetime>>;
100    fn lifetime(&self) -> syn::Result<BTreeSet<Lifetime>>;
101    fn get_strategy_column(&self, ty: TokenStream) -> syn::Result<proc_macro2::TokenStream> {
102        match self.strategy() {
103            Strategy::Rle => Ok(quote::quote!(::serde_columnar::RleColumn::<#ty>)),
104            Strategy::BoolRle => Ok(quote::quote!(::serde_columnar::BoolRleColumn)),
105            Strategy::DeltaRle => Ok(quote::quote!(::serde_columnar::DeltaRleColumn::<#ty>)),
106            Strategy::DeltaOfDelta => {
107                Ok(quote::quote!(::serde_columnar::DeltaOfDeltaColumn::<#ty>))
108            }
109            Strategy::None => {
110                if self.class().is_some() {
111                    let self_ty = &self.ty();
112
113                    let ans = match self.class().unwrap() {
114                        AsType::Map => {
115                            quote::quote!(::serde_columnar::GenericColumn::<::serde_columnar::ColumnarMap::<_, _, #self_ty>>)
116                        }
117                        AsType::Vec => {
118                            quote::quote!(::serde_columnar::GenericColumn::<::serde_columnar::ColumnarVec::<_, #self_ty>>)
119                        }
120                        _ => unreachable!(),
121                    };
122
123                    Ok(ans)
124                } else {
125                    Ok(quote::quote!(::serde_columnar::GenericColumn::<#ty>))
126                }
127            }
128        }
129    }
130}
131
132impl Args for FieldArgs {
133    fn ty(&self) -> Option<syn::Type> {
134        Some(self.ty.clone())
135    }
136
137    fn strategy(&self) -> Strategy {
138        Strategy::from_str(self.strategy.clone())
139    }
140
141    fn class(&self) -> Option<AsType> {
142        match self.class.as_deref() {
143            Some("vec") => Some(AsType::Vec),
144            Some("map") => Some(AsType::Map),
145            Some(_) => Some(AsType::Other),
146            None => None,
147        }
148    }
149
150    fn lifetime(&self) -> syn::Result<BTreeSet<Lifetime>> {
151        if self.has_borrow_lifetime() {
152            Ok(self.borrow_lifetimes()?.unwrap())
153        } else {
154            self.self_lifetime()
155        }
156    }
157
158    fn self_lifetime(&self) -> syn::Result<BTreeSet<Lifetime>> {
159        let mut lifetimes = BTreeSet::new();
160        collect_lifetimes(&self.ty, &mut lifetimes);
161
162        Ok(lifetimes)
163    }
164
165    fn borrow_lifetimes(&self) -> syn::Result<Option<BTreeSet<Lifetime>>> {
166        if self.borrow.is_none() {
167            return Ok(None);
168        }
169
170        match self.borrow.as_ref().unwrap() {
171            Override::Inherit => {
172                let mut lifetimes = BTreeSet::new();
173                collect_lifetimes(&self.ty, &mut lifetimes);
174
175                if lifetimes.is_empty() {
176                    Err(syn::Error::new_spanned(
177                        self.ty.clone().into_token_stream(),
178                        "at least one lifetime must be borrowed",
179                    ))
180                } else {
181                    Ok(Some(lifetimes))
182                }
183            }
184            Override::Explicit(string) => {
185                if let Ok(lifetimes) = string.parse_with(|input: ParseStream| {
186                    let mut set = BTreeSet::new();
187                    while !input.is_empty() {
188                        let lifetime: Lifetime = input.parse()?;
189                        if !set.insert(lifetime.clone()) {
190                            return Err(syn::Error::new_spanned(
191                                string.clone().into_token_stream(),
192                                format!("duplicate borrowed lifetime `{}`", lifetime),
193                            ));
194                        }
195                        if input.is_empty() {
196                            break;
197                        }
198                        input.parse::<Token![+]>()?;
199                    }
200                    Ok(set)
201                }) {
202                    if lifetimes.is_empty() {
203                        return Err(syn::Error::new_spanned(
204                            string.clone().into_token_stream(),
205                            "at least one lifetime must be borrowed",
206                        ));
207                    }
208
209                    if let Ok(field_lifetimes) = self.self_lifetime() {
210                        for l in &lifetimes {
211                            if !field_lifetimes.contains(l) {
212                                return Err(syn::Error::new(
213                                    self.ident.span(),
214                                    format!(
215                                        "field `{}` does not have lifetime {}",
216                                        self.ident.as_ref().unwrap(),
217                                        l,
218                                    ),
219                                ));
220                            }
221                        }
222                    }
223
224                    Ok(Some(lifetimes))
225                } else {
226                    Err(syn::Error::new_spanned(
227                        string.clone().into_token_stream(),
228                        format!("failed to parse borrowed lifetimes: {:?}", string.value()),
229                    ))
230                }
231            }
232        }
233    }
234
235    fn has_borrow_lifetime(&self) -> bool {
236        self.borrow.is_some()
237    }
238}
239
240pub fn get_derive_args(args: &[NestedMeta]) -> syn::Result<DeriveArgs> {
241    match DeriveArgs::from_list(args) {
242        Ok(v) => Ok(v),
243        Err(e) => {
244            eprintln!("get_derive_args error: {}", e);
245            Err(DarlingError::unsupported_format(
246                "columnar only supports attributes with `vec`, `map` and `ser`, `de`",
247            )
248            .into())
249        }
250    }
251}
252
253pub fn parse_field_args(st: &mut DeriveInput) -> syn::Result<Option<Vec<FieldArgs>>> {
254    match &mut st.data {
255        syn::Data::Struct(syn::DataStruct {
256            fields: syn::Fields::Named(syn::FieldsNamed { named, .. }),
257            ..
258        }) => {
259            let mut args = Vec::with_capacity(named.len());
260            for field in named.iter() {
261                let field_args = FieldArgs::from_field(field)?;
262                args.push(field_args);
263            }
264            check_args_validate(&args)?;
265            Ok(Some(args))
266        }
267        syn::Data::Enum(syn::DataEnum { variants: _, .. }) => Err(syn::Error::new_spanned(
268            st,
269            "only supported named struct type",
270        )),
271        _ => Err(syn::Error::new_spanned(
272            st,
273            "only supported named struct type",
274        )),
275    }
276}
277
278pub fn check_args_validate(field_args: &[FieldArgs]) -> syn::Result<()> {
279    // if some fields is not optional, but it appears after some optional fields, then we need to throw error
280    let mut start_optional = false;
281    let mut indexes = std::collections::HashSet::new();
282    for args in field_args {
283        let field_name = &args.ident;
284        let optional = args.optional;
285        let index = args.index;
286        if start_optional && !optional {
287            return Err(syn::Error::new_spanned(
288                field_name,
289                "optional field must be placed after non-optional field",
290            ));
291        }
292        if optional {
293            start_optional = true;
294            if index.is_none() {
295                return Err(syn::Error::new_spanned(
296                    field_name,
297                    "optional field must have index",
298                ));
299            }
300            if indexes.contains(&index.unwrap()) {
301                return Err(syn::Error::new_spanned(
302                    field_name,
303                    "index cannot have duplicate values",
304                ));
305            }
306            indexes.insert(index.unwrap());
307        };
308
309        let strategy = &args.strategy;
310        let class = &args.class;
311        if strategy.is_some() && class.is_some() {
312            return Err(syn::Error::new_spanned(
313                field_name,
314                "strategy and class cannot be set at the same time",
315            ));
316        }
317    }
318    Ok(())
319}
320
321fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
322    match ty {
323        syn::Type::Slice(ty) => {
324            collect_lifetimes(&ty.elem, out);
325        }
326        syn::Type::Array(ty) => {
327            collect_lifetimes(&ty.elem, out);
328        }
329        syn::Type::Ptr(ty) => {
330            collect_lifetimes(&ty.elem, out);
331        }
332        syn::Type::Reference(ty) => {
333            out.extend(ty.lifetime.iter().cloned());
334            collect_lifetimes(&ty.elem, out);
335        }
336        syn::Type::Tuple(ty) => {
337            for elem in &ty.elems {
338                collect_lifetimes(elem, out);
339            }
340        }
341        syn::Type::Path(ty) => {
342            if let Some(qself) = &ty.qself {
343                collect_lifetimes(&qself.ty, out);
344            }
345            for seg in &ty.path.segments {
346                if let syn::PathArguments::AngleBracketed(bracketed) = &seg.arguments {
347                    for arg in &bracketed.args {
348                        match arg {
349                            syn::GenericArgument::Lifetime(lifetime) => {
350                                out.insert(lifetime.clone());
351                            }
352                            syn::GenericArgument::Type(ty) => {
353                                collect_lifetimes(ty, out);
354                            }
355                            syn::GenericArgument::AssocType(binding) => {
356                                collect_lifetimes(&binding.ty, out);
357                            }
358                            _ => {}
359                        }
360                    }
361                }
362            }
363        }
364        syn::Type::Paren(ty) => {
365            collect_lifetimes(&ty.elem, out);
366        }
367        syn::Type::Group(ty) => {
368            collect_lifetimes(&ty.elem, out);
369        }
370        syn::Type::Macro(ty) => {
371            collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out);
372        }
373        syn::Type::BareFn(_)
374        | syn::Type::Never(_)
375        | syn::Type::TraitObject(_)
376        | syn::Type::ImplTrait(_)
377        | syn::Type::Infer(_)
378        | syn::Type::Verbatim(_) => {}
379        _ => {}
380    }
381}
382fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet<syn::Lifetime>) {
383    let mut iter = tokens.into_iter();
384    while let Some(tt) = iter.next() {
385        match &tt {
386            TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
387                if let Some(TokenTree::Ident(ident)) = iter.next() {
388                    out.insert(syn::Lifetime {
389                        apostrophe: op.span(),
390                        ident,
391                    });
392                }
393            }
394            TokenTree::Group(group) => {
395                let tokens = group.stream();
396                collect_lifetimes_from_tokens(tokens, out);
397            }
398            _ => {}
399        }
400    }
401}