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() }