1#![warn(warnings)]
2#![doc = include_str!("../README.md")]
3
4mod attr;
5mod deserialize;
6mod serialize;
7
8#[proc_macro_derive(Deserialize, attributes(envir))]
9pub fn deserialize_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
10 let ast = syn::parse_macro_input!(input);
11
12 deserialize::impl_macro(&ast)
13 .unwrap_or_else(syn::Error::into_compile_error)
14 .into()
15}
16
17#[proc_macro_derive(Serialize, attributes(envir))]
18pub fn serialize_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
19 let ast = syn::parse_macro_input!(input);
20
21 serialize::impl_macro(&ast)
22 .unwrap_or_else(syn::Error::into_compile_error)
23 .into()
24}
25
26pub(crate) fn error<R>(ast: &dyn quote::ToTokens, message: &str) -> syn::Result<R> {
27 Err(syn::Error::new_spanned(ast, message))
28}
29
30pub(crate) fn is_option(ty: &syn::Type) -> bool {
31 is_ty(ty, "Option")
32}
33
34pub(crate) fn is_vec(ty: &syn::Type) -> bool {
35 is_ty(ty, "Vec")
36}
37
38pub(crate) fn is_option_vec(ty: &syn::Type) -> bool {
39 crate::extract_type_from_option(ty)
40 .map(crate::is_vec)
41 .unwrap_or_default()
42}
43
44pub(crate) fn is_ty(ty: &syn::Type, expected: &str) -> bool {
45 let syn::Type::Path(typepath) = ty else {
46 return false;
47 };
48
49 typepath.path.leading_colon.is_none()
50 && typepath.path.segments.len() == 1
51 && typepath
52 .path
53 .segments
54 .iter()
55 .next()
56 .map(|x| x.ident.to_string())
57 == Some(expected.to_string())
58}
59
60fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> {
62 use syn::{GenericArgument, Path, PathArguments, PathSegment};
63
64 fn extract_type_path(ty: &syn::Type) -> Option<&Path> {
65 match *ty {
66 syn::Type::Path(ref typepath) if typepath.qself.is_none() => Some(&typepath.path),
67 _ => None,
68 }
69 }
70
71 fn extract_option_segment(path: &Path) -> Option<&PathSegment> {
74 let idents_of_path = path
75 .segments
76 .iter()
77 .fold(String::new(), |mut acc, v| {
78 acc.push_str(&v.ident.to_string());
79 acc.push('|');
80 acc
81 });
82 vec!["Option|", "std|option|Option|", "core|option|Option|"]
83 .into_iter()
84 .find(|s| idents_of_path == *s)
85 .and_then(|_| path.segments.last())
86 }
87
88 extract_type_path(ty)
89 .and_then(|path| extract_option_segment(path))
90 .and_then(|path_seg| {
91 let type_params = &path_seg.arguments;
92 match *type_params {
94 PathArguments::AngleBracketed(ref params) => params.args.first(),
95 _ => None,
96 }
97 })
98 .and_then(|generic_arg| match *generic_arg {
99 GenericArgument::Type(ref ty) => Some(ty),
100 _ => None,
101 })
102}