cuprated/config/macros.rs
1use toml_edit::TableLike;
2
3/// A macro for config structs defined in `cuprated`. This macro generates a function that
4/// can insert toml comments created from doc comments on fields.
5///
6/// # Attributes
7/// - `#[flatten = true]`: lets the writer know that the field is flattened into the parent struct.
8/// - `#[child = true]`: writes the doc comments for all fields in the child struct.
9/// - `#[inline = true]`: inlines the struct into `{}` instead of having a separate `[]` header.
10/// - `#[comment_out = true]`: comments out the field.
11///
12/// # Documentation
13/// Consider using the following style when adding documentation:
14///
15/// ```rust
16/// struct Config {
17/// /// BRIEF DESCRIPTION.
18/// ///
19/// /// (optional) LONGER DESCRIPTION.
20// ///
21/// /// Type | (optional) FIELD TYPE
22/// /// Valid values | EXPRESSION REPRESENTING VALID VALUES
23/// /// Examples | (optional) A FEW EXAMPLE VALUES
24/// field: (),
25/// }
26/// ```
27///
28/// For example:
29/// ```rust
30/// struct Config {
31/// /// Enable/disable fast sync.
32/// ///
33/// /// Fast sync skips verification of old blocks by
34/// /// comparing block hashes to a built-in hash file,
35/// /// disabling this will significantly increase sync time.
36/// /// New blocks are still fully validated.
37/// ///
38/// /// Type | boolean
39/// /// Valid values | true, false
40/// fast_sync: bool,
41/// }
42/// ```
43///
44/// Language for types:
45///
46/// | Rust type | Wording used in user-book |
47/// |--------------|---------------------------|
48/// | bool | boolean
49/// | u{8-64} | Number
50/// | i{8-64} | Signed number
51/// | f{32,64} | Floating point number
52/// | str, String | String
53/// | enum, struct | `DataStructureName` (e.g. `Duration`) or $DESCRIPTION (e.g. `IP address`)
54///
55/// If some fields are redundant or unnecessary, do not add them.
56///
57/// # Field documentation length
58/// In order to prevent wrapping/scrollbars in the user book and in editors,
59/// add newlines when a documentation line crosses ~70 characters, around this long:
60///
61/// `----------------------------------------------------------------------`
62macro_rules! config_struct {
63 (
64 $(#[$meta:meta])*
65 pub struct $name:ident {
66 $(
67 $(#[flatten = $flat:literal])?
68 $(#[child = $child:literal])?
69 $(#[inline = $inline:literal])?
70 $(#[comment_out = $comment_out:literal])?
71 $(#[doc = $doc:expr])*
72 $(##[$field_meta:meta])*
73 pub $field:ident: $field_ty:ty,
74 )*
75 }
76 ) => {
77 $(#[$meta])*
78 pub struct $name {
79 $(
80 $(#[doc = $doc])*
81 $(#[$field_meta])*
82 pub $field: $field_ty,
83 )*
84 }
85
86 impl $name {
87 #[allow(unused_labels, clippy::allow_attributes)]
88 pub fn write_docs(doc: &mut dyn ::toml_edit::TableLike) {
89 $(
90
91 'write_field: {
92 let key_str = &stringify!($field);
93
94 let mut field_prefix = [ $(
95 format!("##{}\n", $doc),
96 )*].concat();
97
98 $(
99 if $comment_out {
100 field_prefix.push('#');
101 }
102 )?
103
104 $(
105 if $flat {
106 <$field_ty>::write_docs(doc);
107 break 'write_field;
108 }
109 )?
110
111 $(
112 if $child {
113 <$field_ty>::write_docs(doc.get_key_value_mut(&key_str).unwrap().1.as_table_like_mut().unwrap());
114 }
115 )?
116
117 if let Some(table) = doc.entry(&key_str).or_insert_with(|| panic!()).as_table_mut() {
118 $(
119 if $inline {
120 let mut table = table.clone().into_inline_table();
121 doc.insert(&key_str, ::toml_edit::Item::Value(::toml_edit::Value::InlineTable(table)));
122 doc.key_mut(&key_str).unwrap().leaf_decor_mut().set_prefix(field_prefix);
123 break 'write_field;
124 }
125 )?
126 table.decor_mut().set_prefix(format!("\n{}", field_prefix));
127 }else {
128 doc.key_mut(&key_str).unwrap().leaf_decor_mut().set_prefix(field_prefix);
129 }
130 }
131 )*
132 }
133 }
134 };
135}
136
137pub(crate) use config_struct;