enum_update_derive/lib.rs
1#![warn(missing_docs)]
2//! Derive macros for `enum-update`.
3//!
4//! See the repository README.md for more information.
5use proc_macro::TokenStream;
6mod parse;
7use parse::{convert_ident_to_case, EnumPatch};
8mod construction;
9use construction::{EnumConstructionInfo, EnumConstructionVariant};
10use quote::TokenStreamExt;
11
12/// Generates an enum representing updates to a given struct.
13/// See the README.md for an overview.
14///
15/// The [`EnumUpdate`] macro works by creating a list of "variant groups"
16/// with each group representing a modification to the state struct. By
17/// default, a variant group is constructed for each struct member.
18/// An enum variant is generated for each variant group containing all
19/// changes for fields in that group.
20///
21/// ## Available attributes:
22///
23/// ### `variant_group`
24/// Specifies that a field should belong to an extra group.
25/// ```ignore
26/// #[derive(EnumUpdate)]
27/// pub struct TimeSeriesData {
28/// #[variant_group(RecordOne)]
29/// time: u32,
30/// #[variant_group(RecordOne)]
31/// value_one: u32,
32/// #[variant_group]
33/// value_two: u32
34/// }
35/// ```
36/// will generate
37/// ```
38/// pub enum TimeSeriesDataUpdate {
39/// RecordOne {
40/// time: u32,
41/// value_one: u32,
42/// },
43/// ValueTwo { value_two: u32 },
44/// }
45/// ```
46///
47/// ### `enum_update`
48/// Passes on any provided attributes to the generated enum.
49/// ```ignore
50/// #[derive(EnumUpdate)]
51/// #[enum_update(derive(Debug))]
52/// pub struct State {
53/// #[variant_group]
54/// value: u32
55/// }
56/// ```
57/// will generate
58/// ```
59/// #[derive(Debug)]
60/// pub enum StateUpdate {
61/// Value { value: u32 }
62/// }
63/// ```
64#[proc_macro_derive(EnumUpdate, attributes(variant_group, enum_update))]
65pub fn enum_update_derive(inputs: TokenStream) -> TokenStream {
66 enum_update_derive_impl(inputs).unwrap_or_else(|e| e.to_compile_error().into())
67}
68
69fn enum_update_derive_impl(inputs: TokenStream) -> syn::Result<TokenStream> {
70 let parsed = syn::parse(inputs)?;
71 let receiver = EnumPatch::from_item_struct(&parsed)?;
72 let construction = receiver.to_construction();
73 let mut output = construction.generate_enum();
74 output.append_all(construction.generate_enum_patch_impl());
75 Ok(output.into())
76}
77
78/// Generates setter methods that also return enum updates.
79///
80/// Must be used together with [`EnumUpdate`].
81/// See the README.md for more examples.
82#[proc_macro_derive(
83 EnumUpdateSetters,
84 attributes(variant_group, skip_default, rename_default, enum_update)
85)]
86pub fn enum_update_setters_derive(inputs: TokenStream) -> TokenStream {
87 enum_update_setters_derive_impl(inputs).unwrap_or_else(|e| e.to_compile_error().into())
88}
89fn enum_update_setters_derive_impl(inputs: TokenStream) -> syn::Result<TokenStream> {
90 let parsed = syn::parse(inputs)?;
91 let receiver = EnumPatch::from_item_struct(&parsed)?;
92 let construction = receiver.to_construction();
93 Ok(construction.generate_setters().into())
94}