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///     value_two: u32
33/// }
34/// ```
35/// will generate
36/// ```
37/// pub enum TimeSeriesDataUpdate {
38///     Time(u32),
39///     ValueOne(u32),
40///     ValueTwo(u32),
41///     RecordOne(u32, u32), // <- represents multiple changes
42/// }
43/// ```
44///
45/// ### `skip_default`
46/// Specifies that a default variant group should not be generated for a field.
47/// ```ignore
48/// # use enum_update_derive::EnumUpdate;
49/// #[derive(EnumUpdate)]
50/// pub struct TimeSeriesData {
51///     time: u32,
52///     value_one: u32,
53///     #[skip_default]
54///     cached_data
55/// }
56/// ```
57/// will generate
58/// ```
59/// pub enum TimeSeriesDataUpdate {
60///     Time(u32),
61///     ValueOne(u32)
62/// }
63/// ```
64///
65/// ### `rename_default`
66/// Renames the default variant group generated for a field.
67/// ```ignore
68/// #[derive(EnumUpdate)]
69/// pub struct TimeSeriesData {
70///     time: u32,
71///     value_one: u32,
72///     #[rename_default(new_name)]
73///     original_name: u32
74/// }
75/// ```
76/// will generate
77/// ```
78/// pub enum TimeSeriesDataUpdate {
79///     Time(u32),
80///     ValueOne(u32),
81///     NewName(u32), // <-- corresponds to original_name
82/// }
83/// ```
84///
85/// ### `enum_update`
86/// Passes on any provided attributes to the generated enum.
87/// ```ignore
88/// #[derive(EnumUpdate)]
89/// #[enum_update(derive(Debug))]
90/// pub struct State {
91///     value: u32
92/// }
93/// ```
94/// will generate
95/// ```
96/// #[derive(Debug)]
97/// pub enum StateUpdate {
98///     Value(u32)
99/// }
100/// ```
101#[proc_macro_derive(
102    EnumUpdate,
103    attributes(variant_group, skip_default, rename_default, enum_update)
104)]
105pub fn enum_update_derive(inputs: TokenStream) -> TokenStream {
106    let parsed = syn::parse(inputs).unwrap();
107    let receiver = EnumPatch::from_item_struct(&parsed).unwrap();
108    let construction = receiver.to_construction();
109    let mut output = construction.generate_enum();
110    output.append_all(construction.generate_enum_patch_impl());
111    output.into()
112}
113
114/// Generates setter methods that also return enum updates.
115///
116/// Must be used together with [`EnumUpdate`].
117/// See the README.md for more examples.
118#[proc_macro_derive(
119    EnumUpdateSetters,
120    attributes(variant_group, skip_default, rename_default, enum_update)
121)]
122pub fn enum_update_setters_derive(inputs: TokenStream) -> TokenStream {
123    let parsed = syn::parse(inputs).unwrap();
124    let receiver = EnumPatch::from_item_struct(&parsed).unwrap();
125    let construction = receiver.to_construction();
126    construction.generate_setters().into()
127}