more_convert_derive_internal/
lib.rs

1mod enum_repr;
2pub use enum_repr::derive_enum_repr;
3
4mod convert;
5pub use convert::derive_convert;
6
7mod enum_name;
8pub use enum_name::derive_enum_name;
9
10use syn::Type;
11
12pub(crate) fn require_named_field_struct(
13    input: &syn::DeriveInput,
14) -> syn::Result<&syn::FieldsNamed> {
15    match &input.data {
16        syn::Data::Struct(syn::DataStruct {
17            fields: syn::Fields::Named(fields),
18            ..
19        }) => Ok(fields),
20        _ => Err(syn::Error::new_spanned(
21            input,
22            "currently only structs with named fields are supported",
23        )),
24    }
25}
26
27pub(crate) fn require_enum(
28    input: &syn::DeriveInput,
29) -> syn::Result<&syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>> {
30    match &input.data {
31        syn::Data::Enum(syn::DataEnum { variants, .. }) => Ok(variants),
32        _ => Err(syn::Error::new_spanned(
33            input,
34            "currently only enums are supported",
35        )),
36    }
37}
38
39pub(crate) fn is_vec(ty: &Type) -> bool {
40    is_type_eq_ident(ty, "Vec")
41}
42
43pub(crate) fn is_option(ty: &Type) -> bool {
44    is_type_eq_ident(ty, "Option")
45}
46
47pub(crate) fn is_type_eq_ident<S: AsRef<str>>(ty: &Type, s: S) -> bool {
48    match get_last_path_segment(ty) {
49        Some(seg) => seg.ident == s,
50        _ => false,
51    }
52}
53
54pub(crate) fn get_last_path_segment(ty: &Type) -> Option<&syn::PathSegment> {
55    match ty {
56        Type::Path(path) => path.path.segments.last(),
57        _ => None,
58    }
59}
60
61macro_rules! check_duplicate {
62    ($span:expr, $variant:ident) => {
63        $crate::check_duplicate!(@__message $span, $variant, $variant.is_some(),);
64    };
65    ($span:expr, $variant:ident, $additional:literal) => {
66        $crate::check_duplicate!(@__message $span, $variant, $variant.is_some(), $additional);
67    };
68    ($span:expr, $variant:ident, $expr:expr) => {
69        $crate::check_duplicate!(@__message $span, $variant, $expr,);
70    };
71    (@__message $span:expr, $variant:ident, $expr:expr, $($additional:expr)?) => {
72        $crate::check_duplicate!(@__final $span, $expr, concat!("duplicate `", stringify!($variant), "` attribute.", $(" ", $additional)?));
73    };
74    (@__final $span:expr, $expr:expr, $message:expr) => {
75        if $expr {
76            return Err(syn::Error::new($span, $message));
77        }
78    };
79}
80
81pub(crate) use check_duplicate;
82
83fn require_lit_str<S: syn::spanned::Spanned>(span: &S, expr: &syn::Expr) -> syn::Result<String> {
84    if let syn::Expr::Lit(expr_lit) = &expr {
85        if let syn::Lit::Str(lit_str) = &expr_lit.lit {
86            return Ok(lit_str.value());
87        }
88    }
89
90    Err(syn::Error::new(span.span(), "expected string literal"))
91}
92
93fn unraw(ident: &proc_macro2::Ident) -> String {
94    ident.to_string().trim_start_matches("r#").to_owned()
95}