diff --git a/crates/tor-config/src/list_builder.rs b/crates/tor-config/src/list_builder.rs index 5f4bfbfe2..704c3e2f1 100644 --- a/crates/tor-config/src/list_builder.rs +++ b/crates/tor-config/src/list_builder.rs @@ -11,6 +11,9 @@ //! type. (Different lists with the same Rust type, but which ought to have a different //! default, are different "kinds" and should each have a separately named type alias.) //! +//! (Or, alternatively, with a hand-written builder type, make the builder field be +//! `Option>`.) +//! // An alternative design would be declare the field on `Outer` as `Vec`, and to provide // a `VecBuilder`. But: // @@ -359,11 +362,15 @@ macro_rules! define_list_builder_accessors { /// constructed and a mutable reference to the now-defaulted list of builders /// will be returned. $vis fn $things(&mut self) -> &mut Vec<$EntryBuilder> { + #[allow(unused_imports)] + use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _; self.$things.access() } /// Set the whole list (overriding the default) $vis fn [](&mut self, list: Vec<$EntryBuilder>) { + #[allow(unused_imports)] + use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _; *self.$things.access_opt_mut() = Some(list) } @@ -371,6 +378,8 @@ macro_rules! define_list_builder_accessors { /// /// If the list has not yet been set, or accessed, `&None` is returned. $vis fn [](&self) -> &Option> { + #[allow(unused_imports)] + use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _; self.$things.access_opt() } @@ -378,12 +387,66 @@ macro_rules! define_list_builder_accessors { /// /// If the list has not yet been set, or accessed, `&mut None` is returned. $vis fn [](&mut self) -> &mut Option> { + #[allow(unused_imports)] + use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _; self.$things.access_opt_mut() } } )* } } } +/// Extension trait, an alternative to `define_list_builder_helper` +/// +/// Useful for a handwritten `Builder` which wants to contain a list, +/// which is an `Option>`. +/// +/// # Example +/// +/// ``` +/// use tor_config::define_list_builder_accessors; +/// +/// #[derive(Default)] +/// struct WombatBuilder { +/// leg_lengths: Option>, +/// } +/// +/// define_list_builder_accessors! { +/// struct WombatBuilder { +/// leg_lengths: [u32], +/// } +/// } +/// +/// let mut wb = WombatBuilder::default(); +/// wb.leg_lengths().push(42); +/// +/// assert_eq!(wb.leg_lengths, Some(vec![42])); +/// ``` +/// +/// It is not necessary to `use` this trait anywhere in your code; +/// the macro `define_list_builder_accessors` arranges to have it in scope where it needs it. +pub trait DirectDefaultEmptyListBuilderAccessors { + /// Entry type + type T; + /// Get access to the `Vec`, defaulting it + fn access(&mut self) -> &mut Vec; + /// Get access to the `Option` + fn access_opt(&self) -> &Option>; + /// Get mutable access to the `Option` + fn access_opt_mut(&mut self) -> &mut Option>; +} +impl DirectDefaultEmptyListBuilderAccessors for Option> { + type T = T; + fn access(&mut self) -> &mut Vec { + self.get_or_insert_with(Vec::new) + } + fn access_opt(&self) -> &Option> { + self + } + fn access_opt_mut(&mut self) -> &mut Option> { + self + } +} + define_list_builder_helper! { /// List of `T`, a straightforward type, being built as part of the configuration ///