variant_map_derive/lib.rs
1//! Enum variants stored in Maps.
2//!
3//! Provides derive macros for `variant_map`
4//!
5//! Includes a `StructMap` which is a struct with a field per variant of the enum
6//!
7//! Pro: This struct has instant access to the fields (compared to the other Maps that need a lookup)
8//!
9//! Con: Restricted API
10//!
11//! # Example
12//!
13//! ```
14//! use variant_map_derive::VariantStore;
15//!
16//! #[derive(VariantStore)]
17//! enum MyEnum {
18//! A,
19//! B(i32),
20//! }
21//! ```
22//!
23//! For more detailed examples check out the [example project](https://github.com/mxyns/variant-map/tree/master/example) on this crates' [repo](https://github.com/mxyns/variant-map/)
24//!
25
26/// Parameters of the macros attributes
27pub(crate) mod attrs;
28
29/// Helper functions for the [maps] and [structs] implementations
30pub(crate) mod common;
31
32/// Implementation of the derive for variant_map
33pub(crate) mod maps;
34
35/// Implementation of the derive for `StructMap`
36/// This type is derive-only (not included in the base crate)
37///
38/// This macro expansion contains a new Key Enum, a `struct` specific to the enum type
39/// with one field per variant
40///
41/// It also features implementation of the same traits as a normal variant Map
42pub(crate) mod structs;
43
44use crate::attrs::{MapType, BaseAttr};
45use crate::common::EnumType;
46use darling::FromDeriveInput;
47use proc_macro::TokenStream;
48use quote::{format_ident, quote};
49use syn::{parse_macro_input, DeriveInput};
50use syn::spanned::Spanned;
51
52// TODO fix "private documentation" rustdoc
53// TODO publish
54// TODO allow using user generated (possibly generic or tuple variant) keys
55// TODO [1/2] add struct and array versions of the "map"
56// TODO? trait for all maps to reduce duplicate code
57// TODO? tight couple Map trait and MapValue if possible
58
59/// The only derive macro of this crate
60///
61/// Apply it on an enum to automatically generate an enum of keys and a map to store the variants
62///
63/// # Arguments
64///
65/// See [attrs::BaseAttr]
66///
67/// See other attributes in [attrs]
68///
69#[proc_macro_derive(VariantStore, attributes(VariantStore, VariantMap, VariantStruct, key_name))]
70pub fn derive(input: TokenStream) -> TokenStream {
71 let ast = parse_macro_input!(input as DeriveInput);
72
73 let enum_name = ast.ident.clone();
74
75 // VariantStore attribute parameters
76 let (key_enum_name, map_type) = {
77 let base_attr = BaseAttr::from_derive_input(&ast).expect("Wrong VariantStore parameters");
78
79 (
80 base_attr.keys_name(format_ident!("{}Key", &enum_name)),
81 base_attr.map_type()
82 )
83 };
84
85 let enum_type = &EnumType {
86 enum_name: &enum_name,
87 generics: &ast.generics,
88 };
89
90 let result = match map_type {
91 MapType::HashMap | MapType::BTreeMap => {
92 maps::generate_map_code(&ast, &map_type, enum_type, &key_enum_name)
93 }
94 MapType::Struct => {
95 structs::generate_struct_code(&ast, &map_type, enum_type, &key_enum_name)
96 }
97 };
98
99 let (out_of_const, inside_const) = match result {
100 Ok( tup ) => tup,
101 Err(_) => (Some(syn::Error::new(ast.span(), "VariantStore works only on enums").into_compile_error()), None)
102 };
103
104 let result = quote! {
105
106 #out_of_const
107
108 #[doc(hidden)]
109 #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
110 const _: () = {
111 #[allow(unused_extern_crates, clippy::useless_attribute)]
112 extern crate variant_map as _variant_map;
113 use _variant_map::common::*;
114 use _variant_map::serde;
115
116 #inside_const
117 };
118 };
119
120 result.into()
121}