Change builder list API
The new API is (roughly) as discussed in https://gitlab.torproject.org/tpo/core/arti/-/issues/451 This is quite a large commit and it is not convenient to split it up. It contains the following changes: * Redo the list builder and accessor macros implemnetation, including docs and tests. * Change uses of define_list_config_builder. In each case: - Move the docs about the default value to the containing field. - Remove the other docs (which were just recapitulations, and are now not needed since the ListBuilder is no longer public). - Rewmove or replace `pub` in the define_list_builder_helper call, so that the builder is no longer public. - Change the main macro call site to use define_list_builder_helper. - Add a call to define_list_builder_accessors. * Make the module `list_builder` pub so that we have somewhere to put the overview documentation. * Consequential changes: - Change `outer.inner().replace(X)` to `outer.set_inner(X)` - Consequential changes to imports (`use` statements).
This commit is contained in:
parent
71911d2921
commit
4bca912715
|
@ -396,8 +396,8 @@ mod test {
|
|||
.clone();
|
||||
|
||||
let mut bld = TorClientConfig::builder();
|
||||
bld.tor_network().authorities().replace(vec![auth]);
|
||||
bld.tor_network().fallback_caches().replace(vec![fallback]);
|
||||
bld.tor_network().set_authorities(vec![auth]);
|
||||
bld.tor_network().set_fallback_caches(vec![fallback]);
|
||||
bld.storage()
|
||||
.cache_dir(CfgPath::new("/var/tmp/foo".to_owned()))
|
||||
.state_dir(CfgPath::new("/var/tmp/bar".to_owned()));
|
||||
|
|
|
@ -235,11 +235,8 @@ mod test {
|
|||
let mut bld = ArtiConfig::builder();
|
||||
bld.proxy().socks_port(Some(9999));
|
||||
bld.logging().console("warn");
|
||||
bld.tor().tor_network().authorities().replace(vec![auth]);
|
||||
bld.tor()
|
||||
.tor_network()
|
||||
.fallback_caches()
|
||||
.replace(vec![fallback]);
|
||||
bld.tor().tor_network().set_authorities(vec![auth]);
|
||||
bld.tor().tor_network().set_fallback_caches(vec![fallback]);
|
||||
bld.tor()
|
||||
.storage()
|
||||
.cache_dir(CfgPath::new("/var/tmp/foo".to_owned()))
|
||||
|
@ -272,8 +269,7 @@ mod test {
|
|||
bld.tor().preemptive_circuits().disable_at_threshold(12);
|
||||
bld.tor()
|
||||
.preemptive_circuits()
|
||||
.initial_predicted_ports()
|
||||
.replace(vec![80, 443]);
|
||||
.set_initial_predicted_ports(vec![80, 443]);
|
||||
bld.tor()
|
||||
.preemptive_circuits()
|
||||
.prediction_lifetime(Duration::from_secs(3600))
|
||||
|
|
|
@ -5,7 +5,8 @@ use derive_builder::Builder;
|
|||
use serde::Deserialize;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use tor_config::{define_list_config_builder, CfgPath, ConfigBuildError};
|
||||
use tor_config::{define_list_builder_accessors, define_list_builder_helper};
|
||||
use tor_config::{CfgPath, ConfigBuildError};
|
||||
use tracing::Subscriber;
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
|
@ -37,9 +38,11 @@ pub struct LoggingConfig {
|
|||
journald: Option<String>,
|
||||
|
||||
/// Configuration for one or more logfiles.
|
||||
///
|
||||
/// The default is not to log to any files.
|
||||
#[serde(default)]
|
||||
#[builder_field_attr(serde(default))]
|
||||
#[builder(sub_builder)]
|
||||
#[builder(sub_builder, setter(custom))]
|
||||
files: LogfileListConfig,
|
||||
}
|
||||
|
||||
|
@ -65,17 +68,20 @@ impl LoggingConfig {
|
|||
/// Local type alias, mostly helpful for derive_builder to DTRT
|
||||
type LogfileListConfig = Vec<LogfileConfig>;
|
||||
|
||||
define_list_config_builder! {
|
||||
/// List of logfiles to use, being built as part of the configuration.
|
||||
///
|
||||
/// The default is not to log to any files.
|
||||
pub struct LogfileListConfigBuilder {
|
||||
define_list_builder_helper! {
|
||||
struct LogfileListConfigBuilder {
|
||||
files: [LogfileConfigBuilder],
|
||||
}
|
||||
built: LogfileListConfig = files;
|
||||
default = vec![];
|
||||
}
|
||||
|
||||
define_list_builder_accessors! {
|
||||
struct LoggingConfigBuilder {
|
||||
pub files: [LogfileConfigBuilder],
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration information for an (optionally rotating) logfile.
|
||||
#[derive(Deserialize, Debug, Builder, Clone, Eq, PartialEq)]
|
||||
#[builder(derive(Deserialize))]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! Most types in this module are re-exported by `arti-client`.
|
||||
|
||||
use tor_basic_utils::define_accessor_trait;
|
||||
use tor_config::{define_list_config_builder, ConfigBuildError};
|
||||
use tor_config::{define_list_builder_accessors, define_list_builder_helper, ConfigBuildError};
|
||||
use tor_guardmgr::fallback::FallbackList;
|
||||
|
||||
use derive_builder::Builder;
|
||||
|
@ -113,7 +113,9 @@ pub struct PreemptiveCircuitConfig {
|
|||
///
|
||||
/// This value cannot be changed on a running Arti client, because doing so
|
||||
/// would be meaningless.
|
||||
#[builder(sub_builder)]
|
||||
///
|
||||
/// The default is `[80, 443]`.
|
||||
#[builder(sub_builder, setter(custom))]
|
||||
pub(crate) initial_predicted_ports: PredictedPortsList,
|
||||
|
||||
/// After we see the client request a connection to a new port, how long
|
||||
|
@ -185,11 +187,8 @@ fn default_preemptive_threshold() -> usize {
|
|||
/// Built list of configured preemptive ports
|
||||
type PredictedPortsList = Vec<u16>;
|
||||
|
||||
define_list_config_builder! {
|
||||
/// List of preemptive ports, being built as part of the configuration.
|
||||
///
|
||||
/// The default is `[80, 443]`.
|
||||
pub struct PredictedPortsListBuilder {
|
||||
define_list_builder_helper! {
|
||||
struct PredictedPortsListBuilder {
|
||||
pub(crate) ports: [u16],
|
||||
}
|
||||
built: PredictedPortsList = ports;
|
||||
|
@ -197,6 +196,12 @@ define_list_config_builder! {
|
|||
item_build: |&port| Ok(port);
|
||||
}
|
||||
|
||||
define_list_builder_accessors! {
|
||||
struct PreemptiveCircuitConfigBuilder {
|
||||
pub initial_predicted_ports: [u16],
|
||||
}
|
||||
}
|
||||
|
||||
/// Return default target ports
|
||||
fn default_preemptive_ports() -> Vec<u16> {
|
||||
vec![80, 443]
|
||||
|
|
|
@ -95,7 +95,7 @@ mod test {
|
|||
#[test]
|
||||
fn predicts_starting_ports() {
|
||||
let mut cfg = PreemptiveCircuitConfig::builder();
|
||||
cfg.initial_predicted_ports().replace(vec![]);
|
||||
cfg.set_initial_predicted_ports(vec![]);
|
||||
cfg.prediction_lifetime(Duration::from_secs(2));
|
||||
let predictor = PreemptiveCircuitPredictor::new(cfg.build().unwrap());
|
||||
|
||||
|
@ -108,7 +108,7 @@ mod test {
|
|||
);
|
||||
|
||||
let mut cfg = PreemptiveCircuitConfig::builder();
|
||||
cfg.initial_predicted_ports().replace(vec![80]);
|
||||
cfg.set_initial_predicted_ports(vec![80]);
|
||||
cfg.prediction_lifetime(Duration::from_secs(2));
|
||||
let predictor = PreemptiveCircuitPredictor::new(cfg.build().unwrap());
|
||||
|
||||
|
@ -131,7 +131,7 @@ mod test {
|
|||
#[test]
|
||||
fn predicts_used_ports() {
|
||||
let mut cfg = PreemptiveCircuitConfig::builder();
|
||||
cfg.initial_predicted_ports().replace(vec![]);
|
||||
cfg.set_initial_predicted_ports(vec![]);
|
||||
cfg.prediction_lifetime(Duration::from_secs(2));
|
||||
let mut predictor = PreemptiveCircuitPredictor::new(cfg.build().unwrap());
|
||||
|
||||
|
@ -164,7 +164,7 @@ mod test {
|
|||
#[test]
|
||||
fn does_not_predict_old_ports() {
|
||||
let mut cfg = PreemptiveCircuitConfig::builder();
|
||||
cfg.initial_predicted_ports().replace(vec![]);
|
||||
cfg.set_initial_predicted_ports(vec![]);
|
||||
cfg.prediction_lifetime(Duration::from_secs(2));
|
||||
let mut predictor = PreemptiveCircuitPredictor::new(cfg.build().unwrap());
|
||||
let more_than_an_hour_ago = Instant::now() - Duration::from_secs(60 * 60 + 1);
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
#![deny(clippy::unwrap_used)]
|
||||
|
||||
mod err;
|
||||
mod list_builder;
|
||||
pub mod list_builder;
|
||||
mod mut_cfg;
|
||||
mod path;
|
||||
|
||||
|
|
|
@ -1,86 +1,179 @@
|
|||
//! Config list builder for lists
|
||||
//! Lists in builders
|
||||
//!
|
||||
//! Use [`define_list_builder_helper`] and [`define_list_builder_accessors`] together when
|
||||
//! a configuration (or other struct with a builder)
|
||||
//! wants to contain a `Vec` of config sub-entries.
|
||||
//!
|
||||
//! ### How to use these macros
|
||||
//!
|
||||
//! * For each kind of list, define a `ThingList` type alias for the validated form,
|
||||
//! and call [`define_list_builder_helper`] to define a `ThingListBuilder` helper
|
||||
//! type. (Different lists with the same Rust type, but which ought to have a different
|
||||
//! default, are differnet "kinds" and should each have a separately named type alias.)
|
||||
//!
|
||||
// An alternative design would be declare the field on `Outer` as `Vec<Thing>`, and to provide
|
||||
// a `VecBuilder`. But:
|
||||
//
|
||||
// (i) the `.build()` method would have to be from a trait (because it would be `VecBuilder<Item>`
|
||||
// which would have to contain some `ItemBuilder`, and for the benefit of `VecBuilder::build()`).
|
||||
// Although derive_builder` does not provide that trait now, this problem is not insuperable,
|
||||
// but it would mean us inventing a `Buildable` trait and a macro to generate it, or forking
|
||||
// derive_builder further.
|
||||
//
|
||||
// (ii) `VecBuilder<Item>::build()` would have to have the same default list for every
|
||||
// type Item (an empty list). So places where the default list is not empty would need special
|
||||
// handling. The special handling would look quite like what we have here.
|
||||
//
|
||||
//! * For each struct field containing a list, in a struct deriving `Builder`,
|
||||
//! decorate the field with `#[builder(sub_builder, setter(custom))]`
|
||||
//! to (i) get `derive_builder` call the appropriate build method,
|
||||
//! (ii) suppress the `derive_builder`-generated setter.
|
||||
//!
|
||||
// `ThingLisgtBuiler` exixsts for two reasons:
|
||||
//
|
||||
// * derive_builder wants to call simply `build` on the builder struct field, and will
|
||||
// generate code for attaching the field name to any error which occurs. We could
|
||||
// override the per-field build expression, but it would be quite a lot fo typing and
|
||||
// would recapitulate the field name three times.
|
||||
//
|
||||
// * The field accessors (which must be generated by a different macro_rules macros, at least
|
||||
// unless we soup up derive_builder some more) might need to do defaulting, too. if
|
||||
// the builder field is its own type, that can be a method on that type.
|
||||
//
|
||||
//! * For each struct containing lists, call [`define_list_builder_accessors`]
|
||||
//! to define the accessor methods.
|
||||
//!
|
||||
//! ### Example - list of structs with builders
|
||||
//!
|
||||
//! ```
|
||||
//! use derive_builder::Builder;
|
||||
//! use serde::Deserialize;
|
||||
//! use tor_config::{define_list_builder_helper, define_list_builder_accessors, ConfigBuildError};
|
||||
//!
|
||||
//! #[derive(Builder, Debug, Eq, PartialEq)]
|
||||
//! #[builder(build_fn(error = "ConfigBuildError"))]
|
||||
//! #[builder(derive(Deserialize))]
|
||||
//! pub struct Thing { value: i32 }
|
||||
//!
|
||||
//! #[derive(Builder, Debug, Eq, PartialEq)]
|
||||
//! #[builder(build_fn(error = "ConfigBuildError"))]
|
||||
//! #[builder(derive(Deserialize))]
|
||||
//! pub struct Outer {
|
||||
//! /// List of things, being built as part of the configuration
|
||||
//! #[builder(sub_builder, setter(custom))]
|
||||
//! things: ThingList,
|
||||
//! }
|
||||
//!
|
||||
//! define_list_builder_accessors! {
|
||||
//! struct OuterBuilder {
|
||||
//! pub things: [ThingBuilder],
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! /// Type alias for use by list builder macrology
|
||||
//! type ThingList = Vec<Thing>;
|
||||
//!
|
||||
//! define_list_builder_helper! {
|
||||
//! pub(crate) struct ThingListBuilder {
|
||||
//! pub(crate) things: [ThingBuilder],
|
||||
//! }
|
||||
//! built: ThingList = things;
|
||||
//! default = vec![];
|
||||
//! }
|
||||
//!
|
||||
//! let mut builder = OuterBuilder::default();
|
||||
//! builder.things().push(ThingBuilder::default().value(42).clone());
|
||||
//! assert_eq!{ builder.build().unwrap().things, &[Thing { value: 42 }] }
|
||||
//!
|
||||
//! builder.set_things(vec![ThingBuilder::default().value(38).clone()]);
|
||||
//! assert_eq!{ builder.build().unwrap().things, &[Thing { value: 38 }] }
|
||||
//! ```
|
||||
//!
|
||||
//! ### Example - list of trivial values
|
||||
//!
|
||||
//! ```
|
||||
//! use derive_builder::Builder;
|
||||
//! use serde::Deserialize;
|
||||
//! use tor_config::{define_list_builder_helper, define_list_builder_accessors, ConfigBuildError};
|
||||
//!
|
||||
//! #[derive(Builder, Debug, Eq, PartialEq)]
|
||||
//! #[builder(build_fn(error = "ConfigBuildError"))]
|
||||
//! #[builder(derive(Deserialize))]
|
||||
//! pub struct Outer {
|
||||
//! /// List of values, being built as part of the configuration
|
||||
//! #[builder(sub_builder, setter(custom))]
|
||||
//! values: ValueList,
|
||||
//! }
|
||||
//!
|
||||
//! define_list_builder_accessors! {
|
||||
//! struct OuterBuilder {
|
||||
//! pub values: [u32],
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! /// Type alias for use by list builder macrology
|
||||
//! pub type ValueList = Vec<u32>;
|
||||
//!
|
||||
//! define_list_builder_helper! {
|
||||
//! pub(crate) struct ValueListBuilder {
|
||||
//! pub(crate) values: [u32],
|
||||
//! }
|
||||
//! built: ValueList = values;
|
||||
//! default = vec![27];
|
||||
//! item_build: |&value| Ok(value);
|
||||
//! }
|
||||
//!
|
||||
//! let mut builder = OuterBuilder::default();
|
||||
//! assert_eq!{ builder.build().unwrap().values, &[27] }
|
||||
//!
|
||||
//! builder.values().push(12);
|
||||
//! assert_eq!{ builder.build().unwrap().values, &[27, 12] }
|
||||
//! ```
|
||||
|
||||
/// Define a list builder struct and implement the conventional methods
|
||||
/// Define a list builder struct for use with [`define_list_builder_accessors`]
|
||||
///
|
||||
/// The macro-generated builder struct contains `Option<Vec<ThingBuilder>>`, to allow it to
|
||||
/// Generates an builder struct that can be used with derive_builder
|
||||
/// and [`define_list_builder_accessors`] to configure a list of some kind.
|
||||
///
|
||||
/// **See the [`list_builder` module documentation](crate::list_builder) for an overview.**
|
||||
///
|
||||
/// ### Generated struct
|
||||
///
|
||||
/// This macro-generated builder struct contains `Option<Vec<ThingBuilder>>`, to allow it to
|
||||
/// distinguish "never set" from "has been adjusted or set, possibly to the empty list".
|
||||
///
|
||||
/// `#[derive(Default, Clone, Deserialize)]` will be applied, but you can specify other attributes
|
||||
/// too. You should supply a doc comment for the builder struct, as shown in the example.
|
||||
/// The doc comment should state the default value.
|
||||
/// This struct is not exposed as part of the API for setting the configuration.
|
||||
/// Generally the visibility (`$vis`) should be private,
|
||||
/// but sometimes `pub(crate)` or `pub` is necessary,
|
||||
/// for example if the list is to be included in a struct in another module or crate.
|
||||
/// Usually `$field_vis` should be the same as `$vis`.
|
||||
///
|
||||
/// `#[derive(Default, Clone, Deserialize)]` will be applied to the generated builder,
|
||||
/// but you can specify other attributes too.
|
||||
/// There is no need to supply any documentation; this is an internal struct and
|
||||
/// the macro will supply a suitable (generic) doc comment.
|
||||
/// Documentation for the semantics and default value should be applied
|
||||
/// to the field(s) in the containing struct(s).
|
||||
///
|
||||
/// `#[serde(transparent)]` will be applied to the generated `ThingBuilder` struct,
|
||||
/// so that it deserializes just like `Option<Vec<Thing>>`.
|
||||
///
|
||||
/// ### Input to the macro
|
||||
///
|
||||
/// For the input syntax, refer to the docs autogenerated from the macro's matcher.
|
||||
///
|
||||
/// The `built` clause specifies the type of the built value, and how to construct it.
|
||||
/// In the expression part, `things` (the field name) will be the resolved `Vec<Thing>`
|
||||
/// and should be consumed by the expression.
|
||||
/// If the built value is simply a `Vec`, you can just write `built: things;`.
|
||||
/// In the expression part, `things` (the field name) will be the default-resolved `Vec<Thing>`;
|
||||
/// it should be consumed by the expression.
|
||||
/// If the built value is simply a `Vec`, you can just write `built: ThingList = things;`.
|
||||
///
|
||||
/// The `default` clause must provide an expression evaluating to a `Vec<ThingBuilder>`.
|
||||
///
|
||||
/// The `item_build` clause, if supplied, provides a closure with type
|
||||
/// `FnMut(&ThingBuilder) -> Result<Thing, ConfigBuildErro>`; the default is to call
|
||||
/// `thing_builder.build()`.
|
||||
///
|
||||
/// ### Example - list of structs with builders
|
||||
///
|
||||
/// ```
|
||||
/// use derive_builder::Builder;
|
||||
/// use serde::Deserialize;
|
||||
/// use tor_config::{define_list_config_builder, ConfigBuildError};
|
||||
///
|
||||
/// #[derive(Builder, Debug, Eq, PartialEq)]
|
||||
/// #[builder(build_fn(error = "ConfigBuildError"))]
|
||||
/// #[builder(derive(Deserialize))]
|
||||
/// pub struct Thing { value: i32 }
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// pub struct ThingList { things: Vec<Thing> }
|
||||
///
|
||||
/// define_list_config_builder! {
|
||||
/// /// List of things, being built as part of the configuration
|
||||
/// pub struct ThingListBuilder {
|
||||
/// pub(crate) things: [ThingBuilder],
|
||||
/// }
|
||||
/// built: ThingList = ThingList { things };
|
||||
/// default = vec![];
|
||||
/// }
|
||||
///
|
||||
/// let mut thinglist = ThingListBuilder::default();
|
||||
/// thinglist.append(ThingBuilder::default().value(42).clone());
|
||||
/// assert_eq!{ thinglist.build().unwrap().things, &[Thing { value: 42 }] }
|
||||
///
|
||||
/// thinglist.replace(vec![ThingBuilder::default().value(38).clone()]);
|
||||
/// assert_eq!{ thinglist.build().unwrap().things, &[Thing { value: 38 }] }
|
||||
/// ```
|
||||
///
|
||||
/// ### Example - list of trivial values
|
||||
///
|
||||
/// ```
|
||||
/// use derive_builder::Builder;
|
||||
/// use serde::Deserialize;
|
||||
/// use tor_config::{define_list_config_builder, ConfigBuildError};
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// pub struct ValueList { values: Vec<u32> }
|
||||
///
|
||||
/// define_list_config_builder! {
|
||||
/// /// List of values, being built as part of the configuration
|
||||
/// pub struct ValueListBuilder {
|
||||
/// pub(crate) values: [u32],
|
||||
/// }
|
||||
/// built: ValueList = ValueList { values };
|
||||
/// default = vec![27];
|
||||
/// item_build: |&value| Ok(value);
|
||||
/// }
|
||||
///
|
||||
/// let mut valuelist = ValueListBuilder::default();
|
||||
/// assert_eq!{ valuelist.build().unwrap().values, &[27] }
|
||||
///
|
||||
/// valuelist.append(12);
|
||||
/// assert_eq!{ valuelist.build().unwrap().values, &[27, 12] }
|
||||
/// ```
|
||||
|
||||
/// `FnMut(&ThingBuilder) -> Result<Thing, ConfigBuildError>`;
|
||||
/// the default is to call `thing_builder.build()`.
|
||||
#[macro_export]
|
||||
macro_rules! define_list_config_builder {
|
||||
macro_rules! define_list_builder_helper {
|
||||
{
|
||||
$(#[ $docs_and_attrs:meta ])*
|
||||
$vis:vis struct $ListBuilder:ident {
|
||||
|
@ -90,43 +183,18 @@ macro_rules! define_list_config_builder {
|
|||
default = $default:expr;
|
||||
$( item_build: $item_build:expr; )?
|
||||
} => {
|
||||
$(#[ $docs_and_attrs ])*
|
||||
#[derive(Default, Clone, $crate::serde::Deserialize)]
|
||||
#[serde(transparent)]
|
||||
/// Wrapper struct to help derive_builder find the right types and methods
|
||||
///
|
||||
/// This is a builder pattern struct which will be resolved
|
||||
/// during configuration resolution, via the `build` method.
|
||||
/// This struct is not part of the configuration API.
|
||||
/// Refer to the containing structures for information on how to build the config.
|
||||
$vis struct $ListBuilder {
|
||||
/// The list, as overridden
|
||||
$field_vis $things: Option<Vec<$EntryBuilder>>,
|
||||
}
|
||||
|
||||
impl $ListBuilder {
|
||||
/// Add one item to the end of the list.
|
||||
///
|
||||
/// If the list hasn't been set or adjusted yet, it is initialised to the default.
|
||||
/// Then `item` is added.
|
||||
$vis fn append(&mut self, item: $EntryBuilder) -> &mut Self {
|
||||
self.$things
|
||||
.get_or_insert_with(Self::default_list)
|
||||
.push(item);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the list to the supplied one, discarding any previous settings.
|
||||
///
|
||||
/// After `replace` has been called, the default list will no longer be used.
|
||||
$vis fn replace(&mut self, list: impl IntoIterator<Item = $EntryBuilder>) -> &mut Self {
|
||||
self.$things = Some(list.into_iter().collect());
|
||||
self
|
||||
}
|
||||
|
||||
/// Checks whether any calls have been made to set or adjust the list.
|
||||
///
|
||||
/// If `append` or `replace` have been called, this will return `true`.
|
||||
$vis fn is_unmodified_default(&self) -> bool {
|
||||
self.$things.is_none()
|
||||
}
|
||||
|
||||
/// Resolve this list to a list of built items.
|
||||
///
|
||||
/// If the value is still the [`Default`],
|
||||
|
@ -159,37 +227,131 @@ macro_rules! define_list_config_builder {
|
|||
fn default_list() -> Vec<$EntryBuilder> {
|
||||
$default
|
||||
}
|
||||
|
||||
/// Resolve the list to the default if necessary and then return `&mut Vec`
|
||||
$vis fn access(&mut self) -> &mut Vec<$EntryBuilder> {
|
||||
self.$things.get_or_insert_with(Self::default_list)
|
||||
}
|
||||
|
||||
/// Resolve the list to the default if necessary and then return `&mut Vec`
|
||||
$vis fn access_opt(&self) -> &Option<Vec<$EntryBuilder>> {
|
||||
&self.$things
|
||||
}
|
||||
|
||||
/// Resolve the list to the default if necessary and then return `&mut Vec`
|
||||
$vis fn access_opt_mut(&mut self) -> &mut Option<Vec<$EntryBuilder>> {
|
||||
&mut self.$things
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Define accessor methods for a configuration item which is a list
|
||||
///
|
||||
/// **See the [`list_builder` module documentation](crate::list_builder) for an overview.**
|
||||
///
|
||||
/// Generates the following methods for each specified field:
|
||||
///
|
||||
/// ```skip
|
||||
/// impl $OuterBuilder {
|
||||
/// pub fn $things(&mut self) -> &mut Vec<$EntryBuilder> { .. }
|
||||
/// pub fn set_$things(&mut self, list: Vec<$EntryBuilder>) { .. }
|
||||
/// pub fn opt_$things(&self) -> &Option<Vec<$EntryBuilder>> { .. }
|
||||
/// pub fn opt_$things_mut>](&mut self) -> &mut Option<Vec<$EntryBuilder>> { .. }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Each `$EntryBuilder` should have been defined by [`define_list_builder_helper`];
|
||||
/// the method bodies from this macro rely on facilities which will beprovided by that macro.
|
||||
///
|
||||
/// You can call `define_list_builder_accessors` once for a particular `$OuterBuilder`,
|
||||
/// with any number of fields with possibly different entry (`$EntryBuilder`) types.
|
||||
#[macro_export]
|
||||
macro_rules! define_list_builder_accessors {
|
||||
{
|
||||
struct $OuterBuilder:ty {
|
||||
$(
|
||||
$vis:vis $things:ident: [$EntryBuilder:ty],
|
||||
)*
|
||||
}
|
||||
} => {
|
||||
impl $OuterBuilder { $( $crate::paste!{
|
||||
/// Access the being-built list (resolving default)
|
||||
///
|
||||
/// If the field has not yet been set or accessed, the default list will be
|
||||
/// constructed and a mutable reference to the now-defaulted list of builders
|
||||
/// will be returend.
|
||||
$vis fn $things(&mut self) -> &mut Vec<$EntryBuilder> {
|
||||
self.$things.access()
|
||||
}
|
||||
|
||||
/// Set the whole list (overriding the default)
|
||||
$vis fn [<set_ $things>](&mut self, list: Vec<$EntryBuilder>) {
|
||||
*self.$things.access_opt_mut() = Some(list)
|
||||
}
|
||||
|
||||
/// Inspect the being-built list (iwth default unresolved)
|
||||
///
|
||||
/// If the list has not yet been set, or accessed, `&None` is returned.
|
||||
$vis fn [<opt_ $things>](&self) -> &Option<Vec<$EntryBuilder>> {
|
||||
self.$things.access_opt()
|
||||
}
|
||||
|
||||
/// Mutably access the being-built list (iwth default unresolved)
|
||||
///
|
||||
/// If the list has not yet been set, or accessed, `&mut None` is returned.
|
||||
$vis fn [<opt_ $things _mut>](&mut self) -> &mut Option<Vec<$EntryBuilder>> {
|
||||
self.$things.access_opt_mut()
|
||||
}
|
||||
} )* }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use derive_builder::Builder;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[test]
|
||||
fn nonempty_default() {
|
||||
define_list_config_builder! {
|
||||
struct ListBuilder {
|
||||
chars: [char],
|
||||
#[derive(Eq, PartialEq, Builder, Deserialize)]
|
||||
struct Outer {
|
||||
#[builder(sub_builder, setter(custom))]
|
||||
list: List,
|
||||
}
|
||||
|
||||
define_list_builder_accessors! {
|
||||
struct OuterBuilder {
|
||||
list: [char],
|
||||
}
|
||||
built: List = chars;
|
||||
default = vec!['a'];
|
||||
item_build: |&c| Ok(c);
|
||||
}
|
||||
|
||||
type List = Vec<char>;
|
||||
|
||||
let mut b = ListBuilder::default();
|
||||
assert!(b.is_unmodified_default());
|
||||
assert_eq! { (&b).build().expect("build failed"), ['a'] };
|
||||
|
||||
b.append('b');
|
||||
assert!(!b.is_unmodified_default());
|
||||
assert_eq! { (&b).build().expect("build failed"), ['a', 'b'] };
|
||||
|
||||
for mut b in IntoIterator::into_iter([b, ListBuilder::default()]) {
|
||||
b.replace(vec!['x', 'y']);
|
||||
assert!(!b.is_unmodified_default());
|
||||
assert_eq! { (&b).build().expect("build failed"), ['x', 'y'] };
|
||||
define_list_builder_helper! {
|
||||
struct ListBuilder {
|
||||
list: [char],
|
||||
}
|
||||
built: List = list;
|
||||
default = vec!['a'];
|
||||
item_build: |&c| Ok(c);
|
||||
}
|
||||
|
||||
let mut b = OuterBuilder::default();
|
||||
assert!(b.opt_list().is_none());
|
||||
assert_eq! { (&b).build().expect("build failed").list, ['a'] };
|
||||
|
||||
b.list().push('b');
|
||||
assert!(b.opt_list().is_some());
|
||||
assert_eq! { (&b).build().expect("build failed").list, ['a', 'b'] };
|
||||
|
||||
for mut b in [b.clone(), OuterBuilder::default()] {
|
||||
b.set_list(vec!['x', 'y']);
|
||||
assert!(b.opt_list().is_some());
|
||||
assert_eq! { (&b).build().expect("build failed").list, ['x', 'y'] };
|
||||
}
|
||||
|
||||
*b.opt_list_mut() = None;
|
||||
assert_eq! { (&b).build().expect("build failed").list, ['a'] };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use derive_builder::Builder;
|
||||
use serde::Deserialize;
|
||||
use tor_config::{define_list_config_builder, ConfigBuildError};
|
||||
use tor_config::{define_list_builder_helper, ConfigBuildError};
|
||||
use tor_llcrypto::pk::rsa::RsaIdentity;
|
||||
|
||||
/// A single authority that signs a consensus directory.
|
||||
|
@ -44,12 +44,8 @@ impl Authority {
|
|||
/// Authority list, built
|
||||
pub(crate) type AuthorityList = Vec<Authority>;
|
||||
|
||||
define_list_config_builder! {
|
||||
/// List of authorities, being built as part of the configuration.
|
||||
///
|
||||
/// The default is to use a set of compiled-in authorities,
|
||||
/// whose identities and public keys are shipped as part of the Arti source code.
|
||||
pub struct AuthorityListBuilder {
|
||||
define_list_builder_helper! {
|
||||
pub(crate) struct AuthorityListBuilder {
|
||||
authorities: [AuthorityBuilder],
|
||||
}
|
||||
built: AuthorityList = authorities;
|
||||
|
|
|
@ -8,11 +8,12 @@
|
|||
//! The types in this module are re-exported from `arti-client`: any changes
|
||||
//! here must be reflected in the version of `arti-client`.
|
||||
|
||||
use crate::authority::{Authority, AuthorityList};
|
||||
use crate::authority::{Authority, AuthorityBuilder, AuthorityList, AuthorityListBuilder};
|
||||
use crate::retry::{DownloadSchedule, DownloadScheduleBuilder};
|
||||
use crate::storage::DynStore;
|
||||
use crate::{AuthorityListBuilder, Result};
|
||||
use tor_config::ConfigBuildError;
|
||||
use crate::Result;
|
||||
use tor_config::{define_list_builder_accessors, ConfigBuildError};
|
||||
use tor_guardmgr::fallback::FallbackDirBuilder;
|
||||
use tor_guardmgr::fallback::FallbackListBuilder;
|
||||
use tor_netdoc::doc::netstatus;
|
||||
|
||||
|
@ -41,11 +42,11 @@ pub struct NetworkConfig {
|
|||
///
|
||||
/// This section can be changed in a running Arti client. Doing so will
|
||||
/// affect future download attempts only.
|
||||
#[builder(sub_builder)]
|
||||
///
|
||||
/// The default is to use a set of compiled-in fallback directories,
|
||||
/// whose addresses and public keys are shipped as part of the Arti source code.
|
||||
#[serde(default)]
|
||||
#[serde(rename = "fallback_caches")]
|
||||
#[builder_field_attr(serde(rename = "fallback_caches"))]
|
||||
#[builder(setter(name = "fallback_caches"))]
|
||||
#[builder(sub_builder, setter(custom))]
|
||||
pub(crate) fallback_caches: tor_guardmgr::fallback::FallbackList,
|
||||
|
||||
/// List of directory authorities which we expect to sign consensus
|
||||
|
@ -55,10 +56,20 @@ pub struct NetworkConfig {
|
|||
/// with Arti.)
|
||||
///
|
||||
/// This section cannot be changed in a running Arti client.
|
||||
#[builder(sub_builder)]
|
||||
///
|
||||
/// The default is to use a set of compiled-in authorities,
|
||||
/// whose identities and public keys are shipped as part of the Arti source code.
|
||||
#[builder(sub_builder, setter(custom))]
|
||||
pub(crate) authorities: AuthorityList,
|
||||
}
|
||||
|
||||
define_list_builder_accessors! {
|
||||
struct NetworkConfigBuilder {
|
||||
pub fallback_caches: [FallbackDirBuilder],
|
||||
pub authorities: [AuthorityBuilder],
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NetworkConfig {
|
||||
fn default() -> Self {
|
||||
NetworkConfig {
|
||||
|
@ -87,7 +98,7 @@ impl NetworkConfig {
|
|||
impl NetworkConfigBuilder {
|
||||
/// Check that this builder will give a reasonable network.
|
||||
fn validate(&self) -> std::result::Result<(), ConfigBuildError> {
|
||||
if !self.authorities.is_unmodified_default() && self.fallback_caches.is_unmodified_default() {
|
||||
if self.opt_authorities().is_some() && self.opt_fallback_caches().is_none() {
|
||||
return Err(ConfigBuildError::Inconsistent {
|
||||
fields: vec!["authorities".to_owned(), "fallbacks".to_owned()],
|
||||
problem: "Non-default authorities are use, but the fallback list is not overridden"
|
||||
|
@ -310,7 +321,7 @@ mod test {
|
|||
|
||||
// with any authorities set, the fallback list _must_ be set
|
||||
// or the build fails.
|
||||
bld.authorities().replace(vec![
|
||||
bld.set_authorities(vec![
|
||||
Authority::builder()
|
||||
.name("Hello")
|
||||
.v3ident([b'?'; 20].into())
|
||||
|
@ -322,7 +333,7 @@ mod test {
|
|||
]);
|
||||
assert!(bld.build().is_err());
|
||||
|
||||
bld.fallback_caches().replace(vec![FallbackDir::builder()
|
||||
bld.set_fallback_caches(vec![FallbackDir::builder()
|
||||
.rsa_identity([b'x'; 20].into())
|
||||
.ed_identity([b'y'; 32].into())
|
||||
.orport("127.0.0.1:99".parse().unwrap())
|
||||
|
|
|
@ -92,7 +92,7 @@ use std::time::Duration;
|
|||
use std::{collections::HashMap, sync::Weak};
|
||||
use std::{fmt::Debug, time::SystemTime};
|
||||
|
||||
pub use authority::{Authority, AuthorityBuilder, AuthorityListBuilder};
|
||||
pub use authority::{Authority, AuthorityBuilder};
|
||||
pub use config::{
|
||||
DirMgrConfig, DownloadScheduleConfig, DownloadScheduleConfigBuilder, NetworkConfig,
|
||||
NetworkConfigBuilder,
|
||||
|
|
|
@ -1011,9 +1011,9 @@ mod test {
|
|||
impl DirRcv {
|
||||
fn new(now: SystemTime, authorities: Option<Vec<AuthorityBuilder>>) -> Self {
|
||||
let mut netcfg = crate::NetworkConfig::builder();
|
||||
netcfg.fallback_caches().replace(vec![]);
|
||||
netcfg.set_fallback_caches(vec![]);
|
||||
if let Some(a) = authorities {
|
||||
netcfg.authorities().replace(a);
|
||||
netcfg.set_authorities(a);
|
||||
}
|
||||
let cfg = DirMgrConfig {
|
||||
cache_path: "/we_will_never_use_this/".into(),
|
||||
|
|
|
@ -8,7 +8,7 @@ use super::{DirStatus, FallbackDir, FallbackDirBuilder};
|
|||
use crate::fallback::default_fallbacks;
|
||||
use crate::{ids::FallbackId, PickGuardError};
|
||||
use serde::Deserialize;
|
||||
use tor_config::define_list_config_builder;
|
||||
use tor_config::define_list_builder_helper;
|
||||
|
||||
/// A list of fallback directories.
|
||||
///
|
||||
|
@ -30,15 +30,8 @@ impl<T: IntoIterator<Item = FallbackDir>> From<T> for FallbackList {
|
|||
}
|
||||
}
|
||||
|
||||
define_list_config_builder! {
|
||||
/// List of fallback directories, being built as part of the configuration.
|
||||
///
|
||||
/// Fallback directories (represented by [`FallbackDir`]) are used by Tor
|
||||
/// clients when they don't already have enough other directory information to
|
||||
/// contact the network.
|
||||
///
|
||||
/// The default is to use a set of compiled-in fallback directories,
|
||||
/// whose addresses and public keys are shipped as part of the Arti source code.
|
||||
define_list_builder_helper! {
|
||||
// pub because tor-dirmgr needs it for NetworkConfig.fallback_caches
|
||||
pub struct FallbackListBuilder {
|
||||
pub(crate) fallbacks: [FallbackDirBuilder],
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue