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
#![allow(clippy::clippy::large_enum_variant)] // nope use proc_macro::TokenStream; mod drv_config_table; use drv_config_table::derive_config_table_expand; /// 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(`*`EntryMarker`*`))]` (one per struct field) — generates an uninhabited type which implements `Entry` and a `Get` implementation for it. `EntryMarker` is the optional name for the marker type which defaults to the field's name converted to camel case. /// - `#[snec]` (one per struct field) — alias of `#[snec(entry)]`. /// - `#[snec(use_entry(`*`entry_marker`*`))]` (one per struct field) — only adds a `Get` implementation for the specified entry identifier, without generating the type itself. `entry_marker` 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({`*`receiver_expression`*`}: `*`ReceiverType`*`))]` (can be one per struct field and also one on whole struct) — sets the receiver used in `get_handle` implementations for one struct field or the default for the whole struct to be used with `#[snec(entry)]`. *`receiver_expression`* is any valid Rust expression used to create the receiver, executed in the context of the `Get` implementation on the config struct. The type, *`ReceiverType`* must be annotated explicitly. If this attribute is not present, the receiver defaults to `EmptyReceiver`, which does nothing when notified. /// - `#[snec(entry_module(`*`module_name`*`))]` (one on whole struct) — sets the module name in which the entry types generated by `#[snec(entry(...))]` will be placed to *`module_name`*. The default value is `entries`. /// - `#[snec(entry_module_visibility(`*`visibility`*`))]` (one on whole struct) — visibility specifier the generated module for entry marker types. Uses private visibility by default. /// - `#[snec(entry_module_attributes(...))]` (one on whole struct) — any Rust attributes applied to the generated module for entry marker types. Those attributes can be any valid Rust attributes, which include `///`-style and `/** */`-style documentation, but are *restricted to outer attributes*, i.e. `#[...]` and not `#![...]`. /// /// # Example /// ```no_run /// # /* /// #[derive(ConfigTable)] /// #[snec( /// receiver( /// // We just use the name of the struct as an expression, since it is a unit struct /// {MyReceiver}: MyReceiver /// ), /// entry_module_attributes( /// /// The module containing attributes for `MyConfigTable`. /// ), /// entry_module_visibility(pub), /// )] /// struct MyConfigTable { /// #[snec] /// field_with_a_receiver: String, /// #[snec( /// entry, /// receiver( /// {EmptyReceiver::new()}: EmptyReceiver /// ), /// )] /// field_without_a_receiver: i32, /// } /// struct MyReceiver; /// impl Receiver<entries::FieldWithAReceiver> for MyReceiver { /// fn receive(&mut self, new_value: &String) { /// println!("Received a new value: {}", new_value); /// } /// } /// # */ /// ``` #[proc_macro_derive(ConfigTable, attributes(snec))] #[inline] pub fn derive_config_table(input: TokenStream) -> TokenStream { derive_config_table_expand(input.into()) .unwrap_or_else(|err| err.to_compile_error()) .into() }