1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};

mod drv_config_table;
use drv_config_table::derive_config_table_expand;
pub(crate) mod matching;

/// Generates necessary trait implementations to use a struct as a configuration table.
///
/// By itself, `#[derive(ConfigTable)]` won't do anything, as it requires additional markers to describe how exactly the struct will serve as a configuration table. Those markers are expressed using `#[snec(...)]` attributes. The following "Snec-commands" are supported:
/// - `#[snec(entry(entry, "receiver"))]` (one per struct field) — generates an uninhabited type which implements `Entry` and a `Get` implementation for it. `entry` is the optional name for the type (generated by converting the field name to camel case if omitted). The `receiver` is also optional and is given in the form `receiver_fn -> receiver_type`, where `receiver_fn` is the function which is called when `get_handle` is called to get the receiver for the handle and `receiver_type` is a type annotation for the receiver. Generated `Entry` implementors are placed in a private module called `entries` unless specified otherwise using `#[snec(entry_module = "...")]`. ***The order of arguments can be reversed to only specify the receiver.***
/// - `#[snec]` (one per struct field) — alias of `#[snec(entry())]` (usage with no arguments, which fills in reasonable defaults).
/// - `#[snec(use_entry(entry, "receiver"))]` (one per struct field) — only adds a `Get` implementation for the specified entry identifier, without generating the type itself. `entry` is given as an absolute or relative path to the entry type, i.e. it's not necessary for it to be in scope.
/// - `#[snec(receiver = "...")]` (one per whole struct, attached to the struct itself) — sets the default receiver source for `#[snec(entry(...))]` for when it's not specified explicitly. If this attribute is not present, the receiver defaults to `EmptyReceiver`, which does nothing when notified.
/// - `#[snec(entry_module = "...")]` (one per whole struct, attached to the struct itself) - sets the module name in which the entry types generated by `#[snec(entry(...))]` will be placed. The default value is `entries`.
///
/// # Example
/// ```no_run
/// # /*
/// # use snec::{Entry, Receiver, EmptyReceiver, Handle};
/// # use snec_macros::ConfigTable;
/// #[derive(ConfigTable)]
/// #[snec(receiver = "MyReceiver::new -> MyReceiver")]
/// struct MyConfigTable {
///     #[snec]
///     field_with_a_receiver: String,
///     #[snec(entry("snec::EmptyReceiver::new -> EmptyReceiver"))]
///     field_without_a_receiver: i32,
/// }
/// struct MyReceiver;
/// impl MyReceiver {
///     fn new() -> Self {
///         MyReceiver // It's a unit struct, so we just construct it like this
///     }
/// }
/// impl Receiver<entries::FieldWithAReceiver> for MyReceiver {
///     fn receive(&mut self, new_value: &String) {
///         println!("Received a new value: {}", new_value);
///     }
/// }
/// # */
/// ```
/// The derive above creates the following definitions:
/// ```no_run
/// # /*
/// mod entries {
///     /// The entry identifier type for the `field_with_a_receiver` field in
///     /// the `MyConfigTable` config table.
///     enum FieldWithAReceiver {}
///     impl snec::Entry for FieldWithAReceiver {
///         type Data = String;
///         const NAME: &'static str = "field_with_a_receiver";
///     }
///     /// The entry identifier type for the `field_without_a_receiver` field in
///     /// the `MyConfigTable` config table.
///     enum FieldWithoutAReceiver {}
///     impl snec::Entry for FieldWithoutAReceiver {
///         type Data = String;
///         const NAME: &'static str = "field_without_a_receiver";
///     }
/// }
/// impl Get<FieldWithAReceiver> for MyConfigTable {
///     type Receiver = MyReceiver;
///     fn get_ref(&self) -> &String {
///         self.field
///     }
///     fn get_handle(&mut self) -> Handle<'_, '_, FieldWithAReceiver, MyReceiver> {
///         Handle::new(self, Self::receiver())
///     }
/// }
/// impl Get<FieldWithoutAReceiver> for MyConfigTable {
///     type Receiver = EmptyReceiver;
///     fn get_ref(&self) -> &i32 {
///         self.field
///     }
///     fn get_handle(&mut self) -> Handle<'_, '_, FieldWithoutAReceiver, EmptyReceiver> {
///         Handle::new(self, EmptyReceiver::new())
///     }
/// }
/// # */
/// ```
#[proc_macro_derive(ConfigTable, attributes(snec))]
pub fn derive_config_table(item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as DeriveInput);

    derive_config_table_expand(input)
        .unwrap_or_else(|err| err.to_compile_error())
        .into()
}