Skip to main content

tor_config/
derive.rs

1//! Derive-deftly macro for deriving configuration objects.
2//!
3//! The macro defined here makes a configuration object
4//! able to participate in the arti configuration system by giving
5//! it a Builder type implementing the appropriate serde traits.
6//!
7//! It is more ergonomic and less error-prone for our purposes than
8//! `derive_builder`.
9//!
10//! ## Basic usage:
11//!
12//! ```
13//! use derive_deftly::Deftly;
14//! use tor_config::derive::prelude::*;
15//!
16//! #[derive(Deftly, Clone, Debug, PartialEq)]
17//! #[derive_deftly(TorConfig)]
18//! pub struct ExampleConfig {
19//!     #[deftly(tor_config(default))]
20//!     owner_uid: Option<u32>,
21//!
22//!     #[deftly(tor_config(default = r#" "~".to_string() "#))]
23//!     path: String,
24//! }
25//! ```
26//! For topic-specific information, see one of the following:
27//!
28//! * [How to declare a configuration type](doc_howto)
29//! * [Code generated by the tor_config macro](doc_generated_code)
30//! * [Reference: Attributes supported by the tor_config macro](doc_ref_attrs)
31//! * [Differences from derive_builder](doc_differences)
32//! * [Types with magic handling](doc_magic_types)
33
34/// How to declare a configuration type
35///
36/// ## Getting started
37///
38/// Every configuration type should implement at least `Clone` and `Debug`;
39/// it should almost[^partialeq-notest] always implement `PartialEq` too.
40/// In addition to these, you should use `derive(Deftly)` and `derive_deftly(TorConfig)`
41/// to use this macro.
42///
43/// You can start out by copying this template:
44///
45/// ```
46/// use derive_deftly::Deftly;
47/// use tor_config::derive::prelude::*;
48///
49/// #[derive(Deftly, Clone, Debug, PartialEq)]
50/// #[derive_deftly(TorConfig)]
51/// pub struct XyzzyConfig {
52///     // ...
53/// }
54/// ```
55///
56/// ## Declaring fields
57///
58/// At this point, you start declaring the fields that should appear in the configuration.
59/// You declare them as struct fields (as usual);
60/// but to avoid mistakes, you need to specify the default behavior for each field.
61/// You typically do this in one of the following ways:
62///
63/// ```
64/// # use derive_deftly::Deftly;
65/// # use tor_config::derive::prelude::*;
66/// # fn some_function() -> u32 { 7 }
67/// # #[derive(Deftly, Clone, Debug, PartialEq)]
68/// # #[derive_deftly(TorConfig)]
69/// # pub struct Foo {
70///
71/// // If the user doesn't set this field, we set it by calling some_function().
72/// #[deftly(tor_config(default="some_function()"))]
73/// value1: u32,
74///
75/// // If the user doesn't set this field, we set it by calling Default::default().
76/// #[deftly(tor_config(default))]
77/// value2: String,
78///
79/// // This field has no default!  It's an error if the user doesn't set this.
80/// // (See warnings on no_default below.)
81/// #[deftly(tor_config(no_default))]
82/// value3: u16,
83/// # }
84/// ```
85///
86/// Notes:
87/// - There is no "default" behavior for the unset fields: you need to say which one you want.
88///   This requirement is meant to avoid programming errors.
89/// - Try to avoid using `no_default` on any configuration element unless you truly want the user
90///   to specify it in their configuration file every time this section exists.
91///   It's okay to use `no_default`
92///   on something like the address of a fallback directory
93///   (where each one needs to be fully specified)
94///   or the nickname of an onion service
95///   (which needs to be specified for every onion service that exists).
96/// - If you use `no_default`, you will need to use [`no_default_trait`] on the structure
97///   as a whole.
98///
99/// ## Other things you can do
100///
101/// There are many other attributes you can set on struct and fields
102/// to control their behavior.
103/// See [the reference](doc_ref_attrs) for more information.
104///
105/// <!-- TODO: Write a cookbook for common patterns. -->
106///
107/// [^partialeq-notest]: If you decide not to implement `PartialEq` for some reason,
108///    you will need to use the [`no_test_default`] attribute to suppress a test that requires it.
109///    (I do not really know why you would do this.  Just implement `PartialEq`, or
110///    edit this documentation to explain why people would sometimes not want to implement it.)
111///
112/// [`no_default_trait`]: crate::derive::doc_ref_attrs#tmeta:no_default_trait
113/// [`no_test_default`]: crate::derive::doc_ref_attrs#tmeta:no_test_default
114pub mod doc_howto {}
115
116/// Code generated by the tor_config macro
117///
118/// > Here we describe the code generated by the `derive_deftly(TorConfig)` macro.
119/// > Note that this is the _default_ behavior;
120/// > particular [attributes](doc_ref_attrs) not described here will override it.
121///
122/// <!-- TODO: Add "See: X" notes links to the options that override each thing? -->
123///
124/// The `tor_config` macro generates a Builder struct, with a name formed by appending
125/// `Builder` to the name of the configuration struct.
126/// That is, if the configuration struct is `MyConfig`,
127/// the macro generates `MyConfigBuilder`.
128///
129/// The builder struct has the same visibility as the configuration struct.
130/// The builder struct has,
131/// for every ordinary field[^ordinary] of type T in the configuration struct,
132/// a field with the same name and type `Option<T>`.
133/// For every [sub-builder] field in the configuration struct of type `T`,
134/// it has a field with the same name and the type `TBuilder`.
135/// These fields are private.
136///
137/// The builder struct implements [`serde::Serialize`] and [`serde::Deserialize`].
138/// Every field is marked with `#[serde(default)]` to allow it to be absent
139/// in the toml configuration.
140///
141/// The builder struct implements [`derive_deftly::Deftly`].
142///
143/// The builder struct derives `Default`, `Clone`, and `Debug`.
144/// It also has a `new()` method that calls `Default::default()`.
145///
146/// The builder struct implements
147/// [`ExtendBuilder`](crate::extend_builder::ExtendBuilder)
148/// and [`Flattenable`](crate::Flattenable).
149///
150/// The _configuration struct_ receives a generated "builder" method,
151/// of type `fn () -> MyConfigBuilder`.
152/// This function calls the builder's `Default::default()` method.
153///
154/// For every ordinary[^ordinary] field of type T in the configuration struct,
155/// the builder has a **setter method** with the same name,
156/// of type `fn (&mut self, value: T) -> &mut Self`.
157/// The setter method sets the corresponding field in `self` to `Some(value)`,
158/// and returns `self``.
159///
160/// For every [sub-builder] field of type SubCfg in the configuration struct,
161/// the builder has an accessor method with the same name,
162/// returning `&mut SubCfgBuilder`.
163///
164/// The builder has a **build method**, with the name `build`,
165/// of type `fn (&self) -> Result<MyConfig, ConfigBuildError>`.
166/// It has the same visibility as the builder struct.
167/// For every field in the builder of value `Some(x)`,
168/// it sets the corresponding field in the configuration object to `x`.
169/// For every field in the builder of value `None`,
170/// it sets the corresponding field in the configuration object to its default,
171/// or returns an error,
172/// depending on the attributes set on the field.
173/// For every field in the builder with a [sub-builder],
174/// it invokes the build method on that sub-builder,
175/// and sets the corresponding field in the configuration object to its result.
176///
177/// A new `#[cfg(test)]` module is generated, with tests for the builder behavior.
178/// This module is called `test_my_config_builder`, with `my_config` replaced with the
179/// snake-case name of your actual configuration type.
180///
181/// [^ordinary]: For the purpose of this documentation,
182///     a field is "ordinary" if it does not have a [sub-builder].
183///
184///
185/// [sub-builder]: crate::derive::doc_ref_attrs#fmeta:sub_builder
186pub mod doc_generated_code {}
187
188/// Reference: Attributes supported by the tor_config macro
189///
190/// * [Top-level attributes](crate::derive::doc_ref_attrs#tmeta)
191/// * [Field-level attributes](crate::derive::doc_ref_attrs#fmeta)
192///
193/// <div id="tmeta">
194///
195/// ## Top-level attributes
196///
197/// </div>
198///
199/// These attributes can be provided at the top-level, right after
200/// `derive_deftly(TorConfig)` and before `pub struct FooConfig`.
201///
202/// <div id="tmeta:no_serialize_trait">
203///
204/// ### `deftly(tor_config(no_serialize_trait))`  — Don't derive Serialize for the builder struct
205///
206/// </div>
207///
208/// By default, the generated Builder will derive [`serde::Serialize`].
209/// This attribute suppresses that behavior.
210///
211///
212/// <div id="tmeta:no_deserialize_trait">
213///
214/// ### `deftly(tor_config(no_deserialize_trait))` — Don't derive Deserialize for the builder struct
215///
216/// </div>
217///
218/// By default, the generated Builder will implement [`serde::Deserialize`].
219/// This attribute suppresses that behavior.
220///
221/// Using this option will prevent your type from participating directly
222/// in the Arti configuration system.
223///
224///
225/// <div id="tmeta:no_flattenable_trait">
226///
227/// ### `deftly(tor_config(no_flattenable_trait))`  — Don't derive Flattenable for the builder struct
228///
229/// </div>
230///
231/// By default, the generated Builder will derive [`Flattenable`](crate::Flattenable).
232/// This attribute suppresses that behavior.
233///
234/// <div id="tmeta:no_extendbuilder_trait">
235///
236/// ### `deftly(tor_config(no_extendbuilder_trait))`  — Don't derive ExtendBuilder for the builder struct
237///
238/// </div>
239///
240/// By default, the generated Builder will derive [`ExtendBuilder`].
241/// This attribute suppresses that behavior.
242///
243/// <div id="tmeta:no_default_trait">
244///
245/// ### `deftly(tor_config(no_default_trait))` — Don't derive Default for the config struct
246///
247/// </div>
248///
249/// By default, the macro will derive [`Default`] on the configuration type
250/// by creating a default builder, and constructing the configuration type with it.
251///
252/// <div id="tmeta:no_test_default">
253///
254/// ### `deftly(tor_config(no_test_default))` — Don't test Default for the config struct
255///
256/// </div>
257///
258/// By default, the macro will implement a test to make sure that its generated `Default`
259/// implementation produces the same result as deserializing an empty configuration builder,
260/// and building it.
261/// This attribute prevents that test from being generated.
262///
263/// The test is also omitted when [`no_default_trait`] or [`no_deserialize_trait`] is given.
264///
265/// > Note: You must specify this option if the configuration type has any generic parameters.
266/// > Otherwise, it's best to avoid this attribute.
267/// >
268/// > TODO: We should remove this limitation if we can.
269///
270/// <div id="tmeta:no_builder_trait">
271///
272/// ### `deftly(tor_config(no_builder_trait))` — Don't derive Builder for the builder struct
273///
274/// </div>
275///
276/// By default, the builder will implement [`tor_config::load::Builder`](crate::load::Builder).
277/// This attribute suppresses that behavior.
278///
279/// > This attribute's name ends with `_trait` to remind the caller that the Builder struct itself
280/// > will still be implemented.
281///
282/// <div id="tmeta:no_buildable_trait">
283///
284/// ### `deftly(tor_config(no_buildable_trait))` — Don't derive Buildable for the config struct
285///
286/// </div>
287///
288/// By default, the configuration struct will implement
289/// [`tor_config::load::Buildable`](crate::load::Buildable).
290/// This attribute suppresses that behavior.
291///
292/// <div id="tmeta:attr">
293///
294/// ### `deftly(tor_config(attr = ".."))` — Apply an attribute to the builder struct
295///
296/// </div>
297///
298/// This attribute passes its contents through to a new attribute on the derived builder struct.
299/// For example, you can make the builder derive `PartialOrd` by saying
300///
301/// ```no_compile
302/// #[deftly(tor_config(attr= "derive(PartialOrd)"))]
303/// ```
304///
305/// (See also [`attr`](crate::derive::doc_ref_attrs#fmeta:attr) for fields.)
306///
307/// <div id="tmeta:pre_build">
308///
309/// ### `deftly(tor_config(pre_build = ".."))` — Call a function before building
310///
311/// </div>
312///
313/// This attribute makes the generated `build()` method call a validation function on itself
314/// **before** it builds the configuration.  The function must take `&FooBuilder`
315/// as an argument, and return `Result<(),ConfigBuildError>`.  If the function
316/// returns an error, then the build method fails with that error.
317///
318/// Example:
319/// ```
320/// # use derive_deftly::Deftly;
321/// # use tor_config::{derive::prelude::*, ConfigBuildError};
322/// #[derive(Clone,Debug,PartialEq,Deftly)]
323/// #[derive_deftly(TorConfig)]
324/// #[deftly(tor_config(pre_build="Self::must_be_odd"))]
325/// pub struct FavoriteOddNumber {
326///     #[deftly(tor_config(default="23"))]
327///     my_favorite: u32,
328/// }
329///
330/// impl FavoriteOddNumberBuilder {
331///     fn must_be_odd(&self) -> Result<(), ConfigBuildError> {
332///         let Some(fav) = self.my_favorite else { return Ok(()); };
333///         if fav % 2 != 1 {
334///             return Err(ConfigBuildError::Invalid {
335///                 field: "my_favorite".to_string(),
336///                 problem: format!("{fav} was not an odd number")
337///             })
338///         }
339///         Ok(())
340///     }
341/// }
342/// ```
343///
344/// See also [`post_build`].
345///
346/// <div id="tmeta:post_build">
347///
348/// ### `deftly(tor_config(post_build = ".."))` — Call a function after building
349///
350/// </div>
351///
352/// This attribute makes the generated `build()` method call a validation function
353/// on the configuration **after** it is built.
354/// The function must take the the configuration
355/// _by value_ as an argument,
356/// and `Result<`(the configuration)`,ConfigBuildError>`.  If the function
357/// returns an error, then the build method fails with that error.
358///
359/// Example:
360/// ```
361/// # use derive_deftly::Deftly;
362/// # use tor_config::{derive::prelude::*, ConfigBuildError};
363/// #[derive(Clone,Debug,PartialEq,Deftly)]
364/// #[derive_deftly(TorConfig)]
365/// #[deftly(tor_config(post_build="FavoriteEvenNumber::must_be_even"))]
366/// pub struct FavoriteEvenNumber {
367///     #[deftly(tor_config(default="86"))]
368///     my_favorite: u32,
369/// }
370///
371/// impl FavoriteEvenNumber {
372///     fn must_be_even(self) -> Result<Self, ConfigBuildError> {
373///         if self.my_favorite % 2 != 0 {
374///             return Err(ConfigBuildError::Invalid {
375///                 field: "my_favorite".to_string(),
376///                 problem: format!("{} was not an even number", self.my_favorite)
377///             })
378///         }
379///         Ok(self)
380///     }
381/// }
382/// ```
383///
384/// > Note:
385/// > You can also use this attribute to clean up or normalize the the configuration object.
386///
387/// <div id="tmeta:vis">
388///
389/// ### `deftly(tor_config(vis = ".."))` — Change visibility of the builder
390///
391/// </div>
392///
393/// By default, the builder struct is generated with the same visibility as the
394/// configuration struct.
395/// You can use this attribute to change its visibility.
396///
397///
398/// <div id="tmeta:build_fn_name">
399///
400/// ### `deftly(tor_config(build_fn(name = "..")))` — Change name of the build method
401///
402/// </div>
403///
404/// By default, the generated build method is called `build`.
405/// You can use this attribute to change its name.
406///
407/// <div id="tmeta:build_fn_vis">
408///
409/// ### `deftly(tor_config(build_fn(vis = "..")))` — Change visibility of the build method
410///
411/// </div>
412///
413/// By default, the `build()` method has the same visibility as the builder struct.
414/// You can use this attribute to change its visibility.
415///
416/// See also:
417/// * [`deftly(tor_config(vis = ".."))`](crate::derive::doc_ref_attrs#tmeta:vis)
418///
419/// <div id="tmeta:build_fn_error">
420///
421/// ### `deftly(tor_config(build_fn(error = "..")))` — Change return error type of the build method.
422///
423/// </div>
424///
425/// By default, the `build()` method returns [`ConfigBuildError`
426/// on failure.  You can change the error type with this attribute.
427///
428/// You will probably need to use this attribute along with [`build_fn(missing_field)`],
429/// if any of your fields are mandatory.
430///
431/// <div id="tmeta:build_fn_missing_field">
432///
433/// ### `deftly(tor_config(build_fn(missing_field = "..")))` — Code to generate a missing field error.
434///
435/// </div>
436///
437/// By default, when a required field is not set, the `build()` method returns
438/// `Err(E::MissingField { field: "field_name".to_string() })`,
439/// where `E` is [`ConfigBuildError`] or the type configured with [`build_fn(error)`].
440/// You can use this attribute to override this behavior.
441/// Its value should be an expression evaluating to a closure of type
442/// `FnOnce(&str) -> E`.
443///
444/// > For compatibility with `derive_builder`'s version of `build_fn(error)``, you can say:
445/// > ```no_compile
446/// > #[build_fn(error="SomeError",
447/// >            missing_field=
448/// >     r#"|fname| derive_builder::UninitializedFieldError(
449/// >                                  fname.to_string()
450/// >                ).into()"
451/// > )]
452/// > ```
453///
454/// <div id="fmeta">
455///
456/// ## Field-level attributes
457///
458/// </div>
459///
460/// <div id="fmeta:default_default">
461///
462/// ### `deftly(tor_config(default)))` — Use Default::default() when no value is provided
463///
464/// </div>
465///
466/// When this attribute is provided, if the given field is absent in the builder,
467/// the `build()` method will set its value to `Default::default()`.
468///
469/// For each field, you must specify exactly one of
470/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
471///
472/// <div id="fmeta:default_equals">
473///
474/// ### `deftly(tor_config(default = "..")))` — Use a given value when no value is provided
475///
476/// </div>
477///
478/// When this attribute is provided, if the given field is absent in the builder,
479/// the `build()` method will set its value to the value of the provided expression.
480/// The expression may invoke a function, but cannot use `self`.
481///
482/// For each field, you must specify exactly one of
483/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
484///
485///
486/// <div id="fmeta:no_default">
487///
488/// ### `deftly(tor_config(no_default))` — Do not provide a default for this field.
489///
490/// </div>
491///
492/// When this attribute is provided, if the given field is absent in the builder,
493/// the `build()` method will fail with an error.
494///
495/// For each field, you must specify exactly one of
496/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
497///
498/// > When you set this attribute on a field, you must also set the top-level
499/// > [`no_default_trait`] attribute,
500/// > since there will not be a meaningful value for the configuration struct.
501/// >
502/// > Don't use this option on any config struct that's always present with a multiplicity of one,
503/// > or else the empty configuration will become invalid.
504///
505/// <div id="fmeta:build">
506///
507/// ### `deftly(tor_config(build = ".."))` — Call a function to build this field.
508///
509/// </div>
510///
511/// When this attribute is provided, you can completely override the way that this field is constructed.
512/// The expression must evaluate to a function taking `&Builder` as an argument,
513/// and returning the type of the field.
514///
515/// For each field, you must specify exactly one of
516/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
517///
518/// > Be careful with this attribute: it can lead to counterintuitive behavior for the end user.
519///
520/// Example:
521///
522/// ```
523/// # use derive_deftly::Deftly;
524/// # use tor_config::{derive::prelude::*, ConfigBuildError};
525/// #[derive(Clone,Debug,PartialEq,Deftly)]
526/// #[derive_deftly(TorConfig)]
527/// pub struct LowercaseExample {
528///     #[deftly(tor_config(build="Self::build_lc"))]
529///     lc: String,
530/// }
531/// impl LowercaseExampleBuilder {
532///     fn build_lc(&self) -> String {
533///         let s = self.lc.as_ref().map(String::as_str).unwrap_or("");
534///         s.to_lowercase()
535///     }
536/// }
537/// ```
538///
539/// <div id="fmeta:try_build">
540///
541/// ### `deftly(tor_config(try_build = ".."))` — Call a fallible function to build this field.
542///
543/// </div>
544///
545/// When this attribute is provided, you can completely override the way that this field is constructed.
546/// The expression must evaluate to a function taking `&Builder` as an argument,
547/// and returning `Result<T, ConfigBuildError>`, where `T` is the type of the field.
548///
549/// For each field, you must specify exactly one of
550/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
551///
552/// > Be careful with this attribute: it can lead to counterintuitive behavior for the end user.
553///
554/// Example:
555///
556/// ```
557/// # use derive_deftly::Deftly;
558/// # use tor_config::{derive::prelude::*, ConfigBuildError};
559/// #[derive(Clone,Debug,PartialEq,Deftly)]
560/// #[derive_deftly(TorConfig)]
561/// pub struct SqrtExample {
562///     #[deftly(tor_config(try_build="Self::build_sqrt"))]
563///     val: f64,
564/// }
565/// impl SqrtExampleBuilder {
566///     fn build_sqrt(&self) -> Result<f64, ConfigBuildError> {
567///         let v = self.val.unwrap_or(0.0).sqrt();
568///         if v.is_nan() {
569///             return Err(ConfigBuildError::Invalid {
570///                 field: "val".to_string(),
571///                 problem: format!("{v} was negative")
572///             })
573///         }
574///         Ok(v)
575///     }
576/// }
577/// ```
578///
579/// <div id="fmeta:sub_builder">
580///
581/// ### `deftly(tor_config(sub_builder))` — Declare a field to contain a nested configuration
582///
583/// </div>
584///
585/// This attribute is what allows configuration structures to nest.
586/// When you set this attribute on a field of type `InnerCfg`,
587/// the builder structure will contain a field of type `InnerCfgBuilder`.
588/// In order to construct the field, the `build()` method will call
589/// `InnerCfgBuilder::build()`.
590///
591/// For each field, you must specify exactly one of
592/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
593///
594/// <div id="fmeta:sub_builder_build_fn">
595///
596/// ### `deftly(tor_config(sub_builder(build_fn = "...")))` — Call a different function on this sub-builder
597///
598/// </div>
599///
600/// By default, when [`sub_builder`] is in use,
601/// the `build()` method is used to generate the inner configuration object.
602/// This attribute changes the name of the function that is called on the inner builder.
603///
604/// <div id="fmeta:no_sub_builder">
605///
606/// ### `deftly(tor_config(no_sub_builder))` — Allow a Buildable field _without_ a sub_builder.
607///
608/// </div>
609///
610/// By default, the `TorConfig` macro inserts code to checks whether each field
611/// implements [`Buildable`], and causes a compile-time error if any such field
612/// does not have an explicit [`sub_builder`], [`build`], [`try_build`],
613/// or [`no_magic`] declaration.
614/// This attribute overrides this check, and allows you to have a field
615/// implementing [`Buildable`] without using the `sub_builder` pattern.
616///
617///
618/// <div id="fmeta:list">
619///
620/// ### `deftly(tor_config(list))` — Declare a field to contain a nested list of items.
621///
622/// </div>
623///
624/// This attribute should be used on every field containing a `Vec`,
625/// `BTreeSet`, `HashSet`, or similar.
626/// It causes the an appropriate [list-builder](crate::list_builder)
627/// and set of accessors to be generated.
628///
629/// When using this attribute, you must also provide a [`default =`] producing a `Vec`
630/// of the builder type, and either [`list(element(build))`] or [`list(element(clone))`].
631///
632/// Examples:
633///
634/// ```no_compile
635/// // The builder and the constructed list will both contain u32.
636/// #[deftly(tor_config(list(element(clone)), default = "vec![7]"))]
637/// integers: Vec<u32>,
638///
639/// // The builder will contain a Vec<MyTypeBuilder>;.
640/// #[deftly(tor_config(list(), (element(build)), default = "vec![]"))]
641/// objects: Vec<MyType>
642/// ```
643///
644/// <div id="fmeta:list_listtype">
645///
646/// ### `deftly(tor_config(list(listtype = ...)))`
647///
648/// </div>
649///
650/// Usually, the name of the list type alias and builder object  based on the struct and the field name.
651/// You can provide a different name for the list type alias using this attribute, as in
652/// `listtype = "TypeName"`.
653/// The list builder will then be constructed with the list type name, suffixed with `Builder`.
654///
655///  <!-- TODO:
656///    We could support a third option, where we give an explicit closure to build elements.
657///    We could support an option where the types in the builder vec are listed explicitly.
658/// -->
659///
660/// <div id="fmeta:list_element_build">
661///
662/// ### `deftly(tor_config(list(element(build)))` — Declare that the list builder contains sub-builders.
663///
664/// </div>
665///
666/// Used along with [`list`],
667/// and indicates the elements of the built list should be constructed via
668/// builders themselves.  When this attribute is used, the builder structure
669/// will contain a Vec of builders for the list's elements.
670///
671/// If this attribute is given a value, it will be used as the name of the
672/// "build" method for the list elements.
673///
674/// <div id="fmeta:list_element_clone">
675///
676/// ### `deftly(tor_config(list(element(clone)))` — Declare that the list builder objects should be cloned directly.
677///
678/// </div>
679///
680/// Used along with [`list`],
681/// and indicates the elements of the built list should be cloned directly
682/// from those in the builder.  When this attribute is used, the builder structure
683/// will contain a Vec whose elements are the same type as those of the genated list.
684///
685/// <div id="fmeta:map">
686///
687/// ### `deftly(tor_config(map))` — Use a map-builder pattern.
688///
689/// </div>
690///
691/// This attribute should be used on every field containing a `HashMap` or `BTreeMap`
692/// whose key is a `String`, and whose value type is a [`Buildable`].
693/// It causes the template to generate a map builder type and corresponding accessor functions.
694/// The map builder behaves like a map from String to the builder type.
695///
696/// If a value is provided for this attribute, it is used as the name of the
697/// map type alias, and suffixed with `Builder` to get the name for the builder type.
698/// Otherwise, the map type alias is derived from the name of the struct and the field.
699///
700/// The [`default =`] attribute is mandatory with this attribute.
701///
702/// For more information on the generated code, see
703/// [`define_map_builder`](crate::define_map_builder).
704///
705/// <div id="fmeta:map_maptype">
706///
707/// ### `deftly(tor_config(list(maptype = ...)))`
708///
709/// </div>
710///
711/// Usually, the name of the map type alias and builder object  based on the struct and the field name.
712/// You can provide a different name for the map type alias using this attribute, as in
713/// `maptype = "TypeName"`.
714/// The map builder will then be constructed with the map type name, suffixed with `Builder`.
715///
716/// <div id = "fmeta:setter_name">
717///
718/// ### `deftly(tor_config(setter(name = "..")))` — Change the name of the setter function
719///
720/// </div>
721///
722/// By default, the setter function for a field has the same name as its field.
723/// You can provide a different name in this attribute.
724///
725/// <div id="fmeta:setter_vis">
726///
727/// ### `deftly(tor_config(setter(vis = "..")))` — Change the visibility of the setter function
728///
729/// </div>
730///
731/// By default, the setter function for a field has the same visibility as the builder type.
732/// You can provide a different visibility in this attribute.
733///
734/// <div id="fmeta:setter_skip">
735///
736/// ### `deftly(tor_config(setter(skip)))` — Do not generate a setter function
737///
738/// </div>
739///
740/// By default, the builder generates a setter function for every field.
741/// You can tell it not to do so for a single field by providing this attribute.
742///
743/// <div id="fmeta:setter_into">
744///
745/// ### `deftly(tor_config(setter(into)))` — Have the setter function accept `impl Into<T>`
746///
747/// </div>
748///
749/// By default, the setter function expects an argument of type `T`,
750/// where `T` is the same type of the field.
751/// When this option is provided, the setter instead expects an argument of type `impl Into<T>`,
752/// and calls [`Into::into`] on it to set the field.
753///
754/// <div id="fmeta:setter_try_into">
755///
756/// ### `deftly(tor_config(setter(try_into)))` — Have the setter function accept `impl TryInto<T>`
757///
758/// </div>
759///
760/// By default, the setter function expects an argument of type `T`,
761/// where `T` is the same type of the field.
762/// When this option is provided, the setter instead expects an argument of type `impl TryInto<T>`,
763/// and calls [`TryInto::try_into`] on it to set the field.
764/// If `try_into` returns an error, the setter function returns that error.
765///
766/// <div id="fmeta:setter_strip_option">
767///
768/// ### `deftly(tor_config(setter(strip_option)))` — Have the setter for `Option<T>` accept `T`
769///
770/// </div>
771///
772/// This attribute requires that the field itself have type `Option<T>` for some `T`.
773/// Instead of taking `Option<T>` as an argument, the setter now accepts `T`.
774///
775/// <!-- TODO -- Do we still want this, given that option magic should take care of it for us,
776/// and will do a better job? -->
777///
778/// <div id="fmeta:field_ty">
779///
780/// ### `deftly(tor_config(field(ty = "..")))` — Change the type of a field in the builder
781///
782/// </div>
783///
784/// By default, for every field of type `T` in the configuration,
785/// the builder has a field of type `Option<T>`.
786/// This attribute changes the type of the field in the builder to the provided type.
787///
788/// > This attribute has no effect on the generated setter or builder code.
789/// > Therefore, you will typically need to use it along with
790/// > the [`setter(skip)`], [`build`], and [`extend_with`] field attributes.
791///
792/// Example:
793///
794/// ```
795/// # #![allow(unexpected_cfgs)]
796/// # use derive_deftly::Deftly;
797/// # use tor_config::{derive::prelude::*, ConfigBuildError};
798/// #[derive(Clone,Debug,PartialEq)]
799/// pub struct ParsedValue {
800///    // ...
801/// }
802/// impl std::str::FromStr for ParsedValue {
803///     type Err = String;
804///     fn from_str(s: &str) -> Result<Self, Self::Err> {
805///         // ...
806/// #       unimplemented!()
807///     }
808/// }
809///
810/// #[derive(Clone,Debug,PartialEq,Deftly)]
811/// #[derive_deftly(TorConfig)]
812/// pub struct MyConfig {
813///     #[deftly(tor_config(
814///         try_build = r#"Self::try_build_behavior"#,
815///         field(ty = "Option<String>"),
816///         setter(skip)
817///     ))]
818///     behavior: ParsedValue,
819/// }
820///
821/// impl MyConfigBuilder {
822///     pub fn behavior(&mut self, s: impl AsRef<str>) -> &mut Self {
823///         self.behavior = Some(s.as_ref().to_string());
824///         self
825///     }
826///     fn try_build_behavior(&self) -> Result<ParsedValue, ConfigBuildError> {
827///         self.behavior
828///             .as_ref()
829///             .map(String::as_str)
830///             .unwrap_or("Leave the macro processor. Take the cannoli.")
831///             .parse()
832///             .map_err(|problem| ConfigBuildError::Invalid {
833///                 field: "behavior".to_string(),
834///                 problem,
835///             })
836///     }
837/// }
838/// ```
839///
840/// <div id="fmeta:field_vis">
841///
842/// ### `deftly(tor_config(field(vis = "..")))` — Change the visibility of a field in the builder
843///
844/// </div>
845///
846/// By default, fields in the builder are private.
847/// This attribute changes their visibility to the one provided.
848///
849///
850/// <div id="fmeta:skip">
851///
852/// ### `deftly(tor_config(skip))` — Do not generate the field in the builder
853///
854/// </div>
855///
856/// If this attribute is present, no field is generated in the builder for this field.
857/// Implies [`setter(skip)`].  Requires [`build`].
858///
859/// <div id="fmeta:attr">
860///
861/// ### `deftly(tor_config(attr = "..")))` — Apply an attribute to the field in the builder
862///
863/// </div>
864///
865/// Any attribute provided here is applied to the declared field in the builder.
866///
867/// Example:
868/// ```no_compile
869/// #[deftly(tor_config(attr = "allow(deprecated)"))]
870/// x: SomeDeprecatedType,
871/// ```
872///
873/// See also the [`cfg`](crate::derive::doc_ref_attrs#fmeta:cfg) and [`serde`] attributes.
874///
875/// <div id="fmeta:serde">
876///
877/// ### `deftly(tor_config(serde = "..")))` — Apply a serde attribute to the field in the builder
878///
879/// </div>
880///
881/// Any serde attribute provided here is applied to the declared field in the builder.
882///
883/// Example:
884/// ```no_compile
885/// #[deftly(tor_config(serde = r#"alias = "old_name_of_field" "#))]
886/// current_name_of_field: String,
887/// ```
888///
889/// Attributes applied with `serde` apply after any specified with
890/// [`attr`](crate::derive::doc_ref_attrs#fmeta:attr) instead.
891///
892/// > This is a convenience attribute; you could just use
893/// > [`attr`](crate::derive::doc_ref_attrs#fmeta:attr) instead.
894///
895/// <!-- TODO: write up a list of recommended serde attributes -->
896///
897/// <div id="fmeta:extend_with">
898///
899/// ### `deftly(tor_config(extend_with = ""))` — Change the ExtendBuilder behavior for a field.
900///
901/// </div>
902///
903/// Unless you specify [`no_extendbuilder_trait`], the builder type will
904/// implement [`ExtendBuilder`],
905/// and will need a way to replace or extend every field in the builder with
906/// the value from another builder.
907/// This attribute lets you override the default behavior for a single field.
908/// It expects an expression that evaluates to type
909/// `FnOnce(&mut T, T, `[`ExtendStrategy`]`)`,
910/// where `T` is the type of the field in the builder.
911///
912/// <div id="fmeta:cfg">
913///
914/// ### `deftly(tor_config(cfg = "..")))` — Mark a field as conditionally present
915///
916/// </div>
917///
918/// This option causes a field in the builder to be conditionally present or absent at compile time,
919/// similar to the ordinary [`cfg`] attribute.
920/// However, unlike with the ordinary `cfg` attribute,
921/// if the user provides any configuration values for this field when it is disabled,
922/// the generated `build()` code will emit a warning via [`tracing`] at runtime telling them
923/// what feature they would need to turn on.
924///
925/// If an error is more appropriate than a warning, additionally use
926/// [`cfg_reject`].
927///
928/// > Note that you _cannot_ use this along with a regular [`cfg`] attribute,
929/// > since a regular [`cfg`] attribute would suppress the field altogether.
930/// > Therefore, the field will still be present in the configuration struct
931/// > even when the `cfg` condition is false.
932/// > To work around this limitation, it's conventional to arrange for the type of the field
933/// > to be `()` when the `cfg` condition is false.
934///
935/// The `tor_config(cfg_desc)` attribute is mandatory to use along with `cfg`.
936/// It should contain a short prepositional phrase
937/// describing how the program needs to be built with
938/// in order to make this feature present.
939/// Examples might be "with RPC support" or "for Windows".
940///
941///
942/// Example:
943/// ```
944/// # #![allow(unexpected_cfgs)]
945/// # use derive_deftly::Deftly;
946/// # use tor_config::{derive::prelude::*, ConfigBuildError};
947/// #[cfg(feature = "rpc")]
948/// pub type RpcOptionType = String;
949///
950/// #[cfg(not(feature = "rpc"))]
951/// type RpcOptionType = ();
952///
953/// #[derive(Clone,Debug,PartialEq,Deftly)]
954/// #[derive_deftly(TorConfig)]
955/// pub struct OnionSoupConfig {
956///     #[deftly(tor_config(cfg = r#" feature="rpc" "#, cfg_desc = "with RPC support"))]
957///     #[deftly(tor_config(default))]
958///     rpc_option: RpcOptionType,
959/// }
960/// ```
961///
962/// <!-- TODO: This is a warning now, since it is in general only a warning
963///      to use an option that is not recognized.
964///      We may want to provide a variant that produces an error instead. -->
965///
966/// <div id="fmeta:cfg_reject">
967///
968/// ### `deftly(tor_config(cfg_reject))` — Reject the configuration when a feature is missing.
969///
970/// </div>
971///
972/// Used alongside [`tor_config(cfg)`](#fmeta:cfg); see also that attribute's documentation.
973///
974/// Usually, `tor_config(cfg)` causes a warning if values are provided
975/// for a compiled-out configuration option.
976/// When this attribute is present, then `tor_config(cfg)` causes an error instead.
977///
978/// <div id="fmeta:cfg_desc">
979///
980/// ### `deftly(tor_config(cfg_desc = "..")))` — Description of when a field is present.
981///
982/// </div>
983///
984/// Used along with [`tor_config(cfg)`](#fmeta:cfg); see that attribute's documentation.
985///
986/// <div id="fmeta:no_magic">
987///
988/// ### `deftly(tor_config(no_magic)))` — Disable magic handling based on a field's type
989///
990/// </div>
991///
992/// This attribute disables [type-based magic behavior](crate::derive::doc_magic_types)
993/// for the current field.
994///
995/// [`build_fn(error)`]:  crate::derive::doc_ref_attrs#tmeta:build_fn_error
996/// [`build_fn(missing_field)`]:  crate::derive::doc_ref_attrs#tmeta:build_fn_missing_field
997/// [`build`]: crate::derive::doc_ref_attrs#fmeta:build
998/// [`Buildable`]: crate::load::Buildable
999/// [`ConfigBuildError`]: crate::ConfigBuildError
1000/// [`cfg_reject`]: crate::derive::doc_ref_attrs#fmeta:cfg_reject
1001/// [`default =`]: crate::derive::doc_ref_attrs#fmeta:default_equals
1002/// [`default`]: crate::derive::doc_ref_attrs#fmeta:default_default
1003/// [`extend_with`]: crate::derive::doc_ref_attrs#fmeta:extend_with
1004/// [`ExtendBuilder`]: crate::extend_builder::ExtendBuilder
1005/// [`ExtendStrategy`]: crate::extend_builder::ExtendStrategy
1006/// [`list`]: crate::derive::doc_ref_attrs#fmeta:list
1007/// [`list(listtype)`]: crate::derive::doc_ref_attrs#fmeta:list_listtype
1008/// [`list(element(build))`]:  crate::derive::doc_ref_attrs#fmeta:list_element_build
1009/// [`list(element(clone))`]:  crate::derive::doc_ref_attrs#fmeta:list_element_clone
1010/// [`no_default`]: crate::derive::doc_ref_attrs#fmeta:no_default
1011/// [`no_default_trait`]: crate::derive::doc_ref_attrs#tmeta:no_default_trait
1012/// [`no_deserialize_trait`]: crate::derive::doc_ref_attrs#tmeta:no_deserialize_trait
1013/// [`no_extendbuilder_trait`]: crate::derive::doc_ref_attrs#tmeta:no_extendbuilder_trait
1014/// [`no_flattenable_trait`]: crate::derive::doc_ref_attrs#tmeta:no_flattenable_trait
1015/// [`no_magic`]: crate::derive::doc_ref_attrs#fmeta:no_default
1016/// [`post_build`]: crate::derive::doc_ref_attrs#tmeta:post_build
1017/// [`serde`]:  crate::derive::doc_ref_attrs#fmeta:serde
1018/// [`setter(skip)`]: crate::derive::doc_ref_attrs#fmeta:setter_skip
1019/// [`sub_builder`]: crate::derive::doc_ref_attrs#fmeta:sub_builder
1020/// [`try_build`]: crate::derive::doc_ref_attrs#fmeta:try_build
1021pub mod doc_ref_attrs {}
1022
1023/// Differences from `derive_builder`
1024///
1025/// * Not all derive_builder attributes have been cloned: only the ones that we used.
1026/// * Attributes have been adjusted where possible to be easier to use.
1027/// * It is not necessary to use `impl_standard_builder!`
1028/// * The appropriate `serde` attributes are automatically provided on the builder.
1029/// * Every field must have some default behavior specified, or must have the `no_default` option given.
1030///   (With `derive_builder`, `no_default` is the default, which can result in confusing test failures.)
1031/// * Sub-builders are supported.
1032/// * The `cfg` attribute can be used to warn when the user
1033///   tries to provide a value for an compiled-out field.
1034/// * There is (limited) support for generics.
1035/// * The generated documentation is a little better.
1036/// * `validate` has been renamed to `pre_build`.
1037/// * There is `post_build` attribute to replace the pattern where we would rename the build function,
1038///   make it private, and wrap it.
1039/// * A top-level `build_fn` does not override the build function on sub-builders.
1040/// * The list builder and map builder patterns are supported via attributes; you don't need separate
1041///   macros for them.
1042/// * Builders automatically derive `ExtendBuilder`, `Flattenable`, and `Builder`.
1043/// * The configuration type automatically derives `Buildable`.
1044/// * Visibility is set more reasonably.
1045/// * For many types, we automatically generate setters or serde code that conforms
1046///   to our standards.
1047pub mod doc_differences {}
1048
1049/// # Types with "magic" handling
1050///
1051/// The `derive_deftly(TorConfig)` macro currently has automatic "magic"
1052/// handling for a few types, and a few other types where it can "magically"
1053/// detect that you forgot to use a certain option that you probably wanted.
1054///
1055/// To override the magic handling for a field, use the [`tor_config(no_magic)`]
1056/// attribute on that field.
1057///
1058/// These types are handled on a best-effort basis by matching their names.
1059/// If you define a field to have another type that is an alias one of these,
1060/// the macro won't be able to handle it.
1061/// To prevent this case, we use [`assert_not_impl`]
1062/// to insure that you will get a compile-time error if you use one of these
1063/// types under a different name without specifying [`tor_config(no_magic)`].
1064///
1065/// The types with magic handling are:
1066///
1067/// ## `String`
1068///
1069/// The setter for each [`String`] field takes `impl `[`StringOrStr`] as its argument.
1070/// This trait is implemented by `String` and `&str`.
1071///
1072/// > Earlier we had considered having it take `AsRef<str>`, but this is too general
1073/// > and can lead to unwanted surprises.
1074///
1075/// ## `NonZero<T>`
1076///
1077/// The setter for a [`NonZero`]`<T>` field takes
1078/// `impl `[`PossiblyBoundsChecked`]`<T>` as its argument.
1079/// This trait is implemented by `T` and by [`NonZero`]`<T>`.
1080///
1081/// When the build() function is called, it returns an error if the provided
1082/// value was zero.
1083///
1084/// ## `Duration`
1085///
1086/// The serde implementations for a [`Duration`](std::time::Duration) field
1087/// use [`humantime_serde`] to accept and generate human-readable strings.
1088///
1089/// ## `Option`
1090///
1091/// For an `Option<T>` field, the setter accepts both `T` and `Option<T>`.
1092/// It does so by requiring that the argument implement traits as follows:
1093///
1094/// | Field type           | Setter arg trait                     | Implemented by |
1095/// | -------------------- | ------------------------------------ | -------------- |
1096/// | `Option<String>`     | [`OptionStringOrStr`]                | `String, &str, Option<String>, Option<&str>` |
1097/// | `Option<NonZero<T>>` | [`OptionPossiblyBoundsChecked`]`<T>` | `T, NonZero<T>, Option<T>, Option<NonZero<T>> `|
1098/// | `Option<T>`          | [`PossiblyOption`]`<T>`              | `T, Option<T>` |
1099///
1100/// ## `impl Buildable`
1101///
1102/// Any type that implements buildable must either use a the [`sub_builder`] attribute,
1103/// or opt out of it with [`no_sub_builder`] or [`no_magic`].
1104///
1105/// ## `Vec`, `HashSet`, `BTreeSet`
1106///
1107/// These types require you to either use the [`list`] attribute,
1108/// or to opt out of it with [`no_sub_builder`] or [`no_magic`].
1109///
1110/// ## `HashMap<String, impl Buildable>`, `BTreeMap<String, impl Buildable>`
1111///
1112/// These types require you to either use the [`map`] attribute,
1113/// or to opt out of it with [`no_sub_builder`] or [`no_magic`].
1114///
1115/// ## `Option<Duration>`
1116///
1117/// This type will cause a compile-time error unless you set [`no_magic`],
1118/// since there is not actually a way to
1119/// set a None in toml (other than omitting the value).
1120///
1121/// > (TODO: Doesn't) that logic apply to _all_ Option types?
1122///
1123/// ## Container of `Duration`.
1124///
1125/// These are currently disallowed unless you provide [`no_magic`],
1126/// and will cause a compile-time error,
1127/// since we cannot apply our regular serde magic.
1128///
1129/// [`StringOrStr`]: crate::setter_traits::StringOrStr
1130/// [`OptionStringOrStr`]: crate::setter_traits::OptionStringOrStr
1131/// [`PossiblyBoundsChecked`]: crate::setter_traits::PossiblyBoundsChecked
1132/// [`OptionPossiblyBoundsChecked`]: crate::setter_traits::OptionPossiblyBoundsChecked
1133/// [`PossiblyOption`]: crate::setter_traits::PossiblyOption
1134/// [`NonZero`]: std::num::NonZero
1135/// [`tor_config(no_magic)`]: crate::derive::doc_ref_attrs#fmeta:no_magic
1136/// [`list`]: crate::derive::doc_ref_attrs#fmeta:list
1137/// [`map`]: crate::derive::doc_ref_attrs#fmeta:map
1138/// [`sub_builder`]: crate::derive::doc_ref_attrs#fmeta:sub_builder
1139/// [`no_sub_builder`]: crate::derive::doc_ref_attrs#fmeta:no_sub_builder
1140/// [`no_magic`]: crate::derive::doc_ref_attrs#fmeta:no_magic
1141pub mod doc_magic_types {}
1142
1143// TODO:
1144// - Can I replace cfg() with a single FeatureNotSupported type, or a family of such types?
1145//   (See #2298.)
1146// - derive-deftly#109 would let us have better syntax for tmeta:attr, fmeta:attr, and fmeta:serde.
1147// - We must decide before merging whether we actually _want_ to always accept T
1148//   for setters on `NonZero<T>`.  There are some places in our code where we do this now:
1149//   so if we were to stop doing so, we'd be breaking backward compat in the `arti` crate.
1150//   But that doesn't  mean we need to continue to do so everywhere.
1151//   (See #2296)
1152
1153use derive_deftly::define_derive_deftly;
1154
1155/// Values used by the tor_config derive_deftly template.
1156#[doc(hidden)]
1157pub mod exports {
1158    pub use super::{
1159        ShouldBeCaughtAsSerdeSpecialCase, ShouldBeCaughtAsSpecialCase, ShouldNotBeUsed,
1160        ShouldUseListBuilder, ShouldUseMapBuilder, assert_not_impl, bld_magic_check_type,
1161        bld_magic_cvt, bld_magic_setter_arg_type, bld_magic_setter_cvt, bld_magic_setter_docs,
1162        bld_magic_type, list_element, normalize_and_invoke, strip_option,
1163    };
1164    pub use crate::flatten::derive_deftly_template_Flattenable;
1165    pub use crate::{
1166        ConfigBuildError, define_list_builder_accessors, define_list_builder_helper,
1167        define_map_builder,
1168        extend_builder::{ExtendBuilder, ExtendStrategy},
1169        impl_standard_builder,
1170        load::Buildable as BuildableTrait,
1171        load::Builder as BuilderTrait,
1172    };
1173    pub use derive_deftly::Deftly;
1174    pub use figment;
1175    pub use humantime_serde;
1176    pub use serde::{Deserialize, Deserializer, Serialize, Serializer};
1177    pub use serde_value;
1178    pub use std::{
1179        clone::Clone,
1180        convert::{AsRef, Into, TryInto},
1181        default::Default,
1182        fmt::Debug,
1183        option::Option,
1184        result::Result,
1185    };
1186    pub use tracing;
1187    pub use void;
1188}
1189
1190/// Module to import in order to use the tor_config template.
1191pub mod prelude {
1192    pub use super::derive_deftly_template_TorConfig;
1193}
1194
1195/// Helper to implement `strip_option`: Takes a single argument whose type is an Option<T>,
1196/// and yields T.
1197#[doc(hidden)]
1198#[macro_export]
1199macro_rules! strip_option {
1200    { $($($(::)? std::)? option::)? Option $(::)? < $t:ty >  } => { $t };
1201    { $t:ty } => { compile_error!{"'strip_option' only works on a type that is an Option<X>"} }
1202}
1203pub use strip_option;
1204
1205/// Helper: Takes a @command name, a {type}, and a list of arguments.
1206/// Determines which macro corresponds to the type,
1207/// and invokes that macro with arguments: @command {type} args.
1208///
1209/// The macros corresponding to types are [`string_typemagic`] for `String`,
1210/// [`nonzero_typemagic`] for `NonZero*`,
1211/// and [`no_typemagic`] for everything else.
1212///
1213/// Recognized @commands are:
1214///  - `@build_type {ty}` - The type that should be used as `T` for the builder field's `Option<T>`.
1215///  - `@setter_arg_type {ty}` - The type that the setter should take as an argument.
1216///  - `@setter_cvt {ty} {e}`- Code to run inside the setter to convert {e} into a `@build_type {ty}`
1217///  - `@build_field {ty} {e} {name}` - Code to convert `@build_type {ty}` into {ty}.  Uses the
1218///    field name `{fname}` to generate errors.
1219///  - `@check_type {ty}` - Make sure that it is not a bug for this type to have reached this position.
1220///    Give a compile-time error if it is.
1221///  - `@setter_docs {ty}` - A string to add to the setter documentation.
1222#[doc(hidden)]
1223#[macro_export]
1224macro_rules! normalize_and_invoke {
1225    // HEY YOU! DON'T ADD OR REMOVE ANY TYPES WITHOUT READING THE COMMENT BELOW!
1226    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1227        < $( $($(::)? std::)? num:: )? NonZero $(::)? < $t:ty > >
1228    } $($args:tt)*}                                                                   => { $crate::derive::opt_nz_typemagic!    { @$cmd {$t} $($args)* } };
1229    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1230        < $( $($(::)? std::)? num:: )? NonZeroU8 >
1231    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u8} $($args)* } };
1232    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1233        < $( $($(::)? std::)? num:: )? NonZeroU16 >
1234    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u16} $($args)* } };
1235    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1236        < $( $($(::)? std::)? num:: )? NonZeroU32 >
1237    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u32} $($args)* } };
1238    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1239        < $( $($(::)? std::)? num:: )? NonZeroU64 >
1240    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u64} $($args)* } };
1241    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1242        < $( $($(::)? std::)? num:: )? NonZeroU128 >
1243    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u128} $($args)* } };
1244    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1245        < $( $($(::)? std::)? string:: )? String >
1246    } $($args:tt)*}                                                                    => { $crate::derive::opt_str_typemagic!  { @$cmd $($args)* } };
1247    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
1248        < $t:ty >
1249    } $($args:tt)*}                                                                    =>   {$crate::derive::opt_other_typemagic!{@$cmd {$t}  $($args)* } };
1250    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZero $(::)? < $t:ty >}  $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {$t}   $($args)* } };
1251    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU8}                 $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u8}   $($args)* } };
1252    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU16}                $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u16}  $($args)*  } };
1253    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU32}                $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u32}  $($args)*  } };
1254    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU64}                $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u64}  $($args)*  } };
1255    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU128}               $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u128} $($args)*  } };
1256    { @$cmd:ident {$( $($(::)? std::)? string:: )? String}                 $($args:tt)*} => { $crate::derive::string_typemagic! { @$cmd $($args)* } };
1257    { @$cmd:ident {$($t:tt)+}                                              $($args:tt)*} => { $crate::derive::no_typemagic!     { @$cmd {$($t)+} $($args)* } };
1258    // HEY YOU! DON'T ADD OR REMOVE TYPES WITHOUT READING THIS COMMENT!
1259    //
1260    // 1. You need to make sure that every type handled by this macro implements
1261    //    `ShouldBeCaughtAsASpecialCase`.
1262    // 2. Make sure to document the behavior in `doc_magic_types` above.
1263}
1264pub use normalize_and_invoke;
1265
1266/// Implement type magic for types that aren't at all special.
1267///
1268/// See [`normalize_and_invoke`] for details.
1269#[doc(hidden)]
1270#[macro_export]
1271macro_rules! no_typemagic {
1272    { @build_type {$t:ty} } => { $t };
1273    { @setter_arg_type {$t:ty}} => { $t };
1274    { @setter_cvt {$t:ty} {$e:expr} } => { $e };
1275    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => { $e.clone() };
1276    { @check_type {$t:ty} } => {
1277        $crate::derive::exports::assert_not_impl!(
1278            [type_was_not_correctly_identified_as_a_TorConfig_special_case]
1279            $t: $crate::derive::ShouldBeCaughtAsSpecialCase
1280        );
1281    };
1282    { @setter_docs {$t:ty} } => { "" };
1283}
1284pub use no_typemagic;
1285
1286/// Implement type magic for `String`.
1287///
1288/// See [`normalize_and_invoke`] for details.
1289#[doc(hidden)]
1290#[macro_export]
1291macro_rules! string_typemagic {
1292    { @build_type } => { String };
1293    { @setter_arg_type } => { impl $crate::setter_traits::StringOrStr };
1294    { @setter_cvt {$e:expr} } => { $e.to_string() };
1295    { @build_field {$e:expr} {$fname:expr}} => { $e.clone() };
1296    { @check_type } => {};
1297    { @setter_docs } => {
1298        "\nFor convenience, this function accepts both `String` and `&str`.\n"
1299    };
1300}
1301pub use string_typemagic;
1302
1303/// Implement type magic for `NonZero*`.
1304///
1305/// See [`normalize_and_invoke`] for details.
1306#[doc(hidden)]
1307#[macro_export]
1308macro_rules! nonzero_typemagic {
1309    { @build_type {$t:ty} } => { $t };
1310    { @setter_arg_type {$t:ty} } => { impl $crate::setter_traits::PossiblyBoundsChecked<$t> };
1311    { @setter_cvt {$t:ty} {$e:expr} } => { $e.to_unchecked() };
1312    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => {
1313        $e.map(|v|
1314            v.try_into().map_err(|_| $crate::ConfigBuildError::Invalid {
1315                field: $fname.to_string(),
1316                problem: "value not allowed to be zero".to_string()
1317        })).transpose()?
1318    };
1319    { @check_type {$t:ty} } => {};
1320    { @setter_docs {$t:ty} } => {
1321        concat!("\nFor convenience, this function accepts both `",
1322            stringify!($t), "` and `NonZero<", stringify!($t), ">`.\n" )
1323    };
1324}
1325pub use nonzero_typemagic;
1326
1327/// Implement type magic for `Option<NonZero*>`
1328///
1329/// See [`normalize_and_invoke`] for details.
1330#[doc(hidden)]
1331#[macro_export]
1332macro_rules! opt_nz_typemagic {
1333    { @build_type {$t:ty} } => { Option<$t> };
1334    { @setter_arg_type {$t:ty} } => { impl $crate::setter_traits::OptionPossiblyBoundsChecked<$t> };
1335    { @setter_cvt {$t:ty} {$e:expr} } => { $e.to_option_unchecked() };
1336    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => {
1337        match $e {
1338            Some(Some(v)) => match v.try_into() {
1339                Ok(n) => Some(Some(n)),
1340                Err(_) => return Err( $crate::ConfigBuildError::Invalid {
1341                    field: $fname.to_string(),
1342                    problem: "value not allowed to be zero".to_string()
1343                })
1344            }
1345            Some(None) => Some(None),
1346            None => None,
1347        }
1348    };
1349    { @check_type {$t:ty} } => {};
1350    { @setter_docs {$t:ty} } => {
1351        concat!("\nFor convenience, this function accepts `",
1352            stringify!($t), "`, `NonZero<", stringify!($t), ">`, `Option<", stringify!($t),
1353            ">`, and `Option<NonZero<", stringify!($t), ">`.\n")
1354    };
1355}
1356pub use opt_nz_typemagic;
1357
1358/// Implement type magic for `Option<String>`
1359///
1360/// See [`normalize_and_invoke`] for details.
1361#[doc(hidden)]
1362#[macro_export]
1363macro_rules! opt_str_typemagic {
1364    { @build_type } => { Option<String> };
1365    { @setter_arg_type  } => { impl $crate::setter_traits::OptionStringOrStr };
1366    { @setter_cvt {$e:expr} } => { $e.to_option_string() };
1367    { @build_field {$e:expr} {$fname:expr}} => { $e.clone() };
1368    { @check_type } => {};
1369    { @setter_docs } => {
1370        "\nFor convenience, this function accepts `String`, `&str`, \
1371                 `Option<String>`, and `Option<&str>`.\n"
1372    };
1373}
1374pub use opt_str_typemagic;
1375
1376/// Implement type magic for `Option<T>`
1377///
1378/// See [`normalize_and_invoke`] for details.
1379#[doc(hidden)]
1380#[macro_export]
1381macro_rules! opt_other_typemagic {
1382    { @build_type {$t:ty} } => { Option<$t> };
1383    { @setter_arg_type {$t:ty} } => { impl $crate::setter_traits::PossiblyOption<$t> };
1384    { @setter_cvt {$t:ty} {$e:expr} } => { $e.to_option() };
1385    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => { $e.clone() };
1386    { @check_type {$t:ty} } => {
1387        $crate::derive::exports::assert_not_impl!(
1388            [type_was_not_correctly_identified_as_a_TorConfig_Option_special_case]
1389            $t: $crate::derive::ShouldBeCaughtAsSpecialCase
1390        );
1391    };
1392    { @setter_docs {$t:ty} } => {
1393        concat!("\nFor convenience, this function accepts both `", stringify!($t),
1394              "` and `Option<", stringify!($T), ">`\n.")
1395    };
1396}
1397pub use opt_other_typemagic;
1398
1399/// Helper: Expand to the type `T` that a field of type `{$t}`
1400/// should have in the builder struct's Option<T>.
1401#[doc(hidden)]
1402#[macro_export]
1403macro_rules! bld_magic_type {
1404    { $($t:tt)+ } => { $crate::derive::normalize_and_invoke!{ @build_type {$($t)+} } };
1405}
1406pub use bld_magic_type;
1407
1408/// Helper: Expand to the type `T` that a setter should take for a field of type `{$t}`
1409#[doc(hidden)]
1410#[macro_export]
1411macro_rules! bld_magic_setter_arg_type {
1412    { $($t:tt)+ } => { $crate::derive::normalize_and_invoke!{ @setter_arg_type {$($t)+} } };
1413}
1414pub use bld_magic_setter_arg_type;
1415
1416/// Helper: Expand to the code that should be used to convert `{e}` into the type
1417/// `bld_magic_type!{$t}`.
1418#[doc(hidden)]
1419#[macro_export]
1420macro_rules! bld_magic_setter_cvt {
1421    { {$e:expr} {$($t:tt)+}} => { $crate::derive::normalize_and_invoke!{ @setter_cvt {$($t)+} {$e} } };
1422}
1423pub use bld_magic_setter_cvt;
1424
1425/// Helper: Expand to the code that should be used to convert `{e}` from type
1426/// `bld_magic_type!{$t}` into $t.  Uses the field name `{fname} to generate errors.
1427#[doc(hidden)]
1428#[macro_export]
1429macro_rules! bld_magic_cvt {
1430    { {$e:expr} {$fname:expr} {$($t:tt)+}} => { $crate::derive::normalize_and_invoke!{ @build_field {$($t)+} {$e} {$fname} } };
1431}
1432pub use bld_magic_cvt;
1433
1434/// Helper: Expand to the code that will make sure that the type `{t}`
1435/// can be handled correctly by these macros.
1436/// The code will cause a compile-time error on failure.
1437#[doc(hidden)]
1438#[macro_export]
1439macro_rules! bld_magic_check_type {
1440    { {$($t:tt)+}} => { $crate::derive::normalize_and_invoke!{ @check_type {$($t)+} } };
1441}
1442pub use bld_magic_check_type;
1443
1444/// Helper: Expand to a documentation string describing any type-based magic for
1445/// the setter for this type.
1446#[doc(hidden)]
1447#[macro_export]
1448macro_rules! bld_magic_setter_docs {
1449    { {$($t:tt)+} } => { $crate::derive::normalize_and_invoke!{ @setter_docs {$($t)+} } };
1450}
1451pub use bld_magic_setter_docs;
1452
1453/// Helper for sealing traits below.
1454mod seal {
1455    /// Used to seal ShouldBeCaughtAsSpecialCase.
1456    pub trait SealSpecialCase {}
1457    /// Used to seal ShouldBeCaughtAsSerdeSpecialCase.
1458    pub trait SealSerdeSpecialCase {}
1459    /// Used to seal ShouldUseListBuilder.
1460    pub trait SealUseListBuilder {}
1461    /// Used to seal ShouldUseMapBuilder
1462    pub trait SealUseMapBuilder {}
1463    /// Used to seal ShouldNotBeUsed
1464    pub trait SealShouldNotBeUsed {}
1465}
1466
1467/// Implement each `trait` for every comma-separated type in `types`, with an empty body.
1468macro_rules! impl_many {
1469    { $($ty:ty),+ : $trait:ty } =>
1470    {
1471        $( impl $trait for $ty {} )+
1472    };
1473    { $($ty:ty),+ : $trait:ty , $($more:tt)+} =>
1474    {
1475        impl_many!{ $($ty),+ : $trait }
1476        impl_many!{ $($ty),+ : $($more)+ }
1477    };
1478}
1479
1480/// A trait implemented by all the types that `normalize_and_invoke` does anything magic for.
1481///
1482/// We use this trait to detect cases that normalize_and_invoke should have handled, but didn't--
1483/// probably because the type was an alias.
1484pub trait ShouldBeCaughtAsSpecialCase: seal::SealSpecialCase {}
1485impl_many! {
1486    std::num::NonZero<u8>, std::num::NonZero<u16>,
1487    std::num::NonZero<u32>, std::num::NonZero<u64>,
1488    std::num::NonZero<u128>, String
1489    : seal::SealSpecialCase, ShouldBeCaughtAsSpecialCase
1490}
1491impl<T> seal::SealSpecialCase for Option<T> {}
1492impl<T> ShouldBeCaughtAsSpecialCase for Option<T> {}
1493
1494/// A trait implemented by all the types that should receive automatic serde magic handling.
1495///
1496/// We use this trait to detect cases that the tor_config derive macro should have caught,
1497/// but didn't-- probably because the type was an alias.
1498pub trait ShouldBeCaughtAsSerdeSpecialCase: seal::SealSerdeSpecialCase {}
1499impl_many! {
1500    std::time::Duration
1501    : seal::SealSerdeSpecialCase, ShouldBeCaughtAsSerdeSpecialCase
1502}
1503
1504/// A trait implemented by the types for which we should recommend the use of a
1505/// list builder.
1506pub trait ShouldUseListBuilder: seal::SealUseListBuilder {
1507    /// The element type of this list.
1508    type Element;
1509}
1510impl<T> seal::SealUseListBuilder for Vec<T> {}
1511impl<T> seal::SealUseListBuilder for std::collections::HashSet<T> {}
1512impl<T> seal::SealUseListBuilder for std::collections::BTreeSet<T> {}
1513impl<T> ShouldUseListBuilder for Vec<T> {
1514    type Element = T;
1515}
1516impl<T> ShouldUseListBuilder for std::collections::HashSet<T> {
1517    type Element = T;
1518}
1519impl<T> ShouldUseListBuilder for std::collections::BTreeSet<T> {
1520    type Element = T;
1521}
1522
1523/// Helper to implement `list_builder`: find the element type for a list-like object.
1524#[doc(hidden)]
1525#[macro_export]
1526macro_rules! list_element {
1527    { $($($(::)? std::)? vec::)? Vec $(::)? < $t:ty > } => { $t };
1528    { $($($(::)? std::)? collections::)? HashSet $(::)? < $t:ty > } => { $t };
1529    { $($($(::)? std::)? collections::)? BTreeSet $(::)? < $t:ty > } => { $t };
1530    { $t:ty } => { compile_error!{"'list_builder' only works on Vec, HashSet, or BTreeSet."} }
1531}
1532pub use list_element;
1533
1534/// A trait implemented by the types for which we should recommend the use of a
1535/// map builder.
1536pub trait ShouldUseMapBuilder: seal::SealUseMapBuilder {
1537    /// The corresponding type to use inside this map builder
1538    type BuilderMap;
1539}
1540impl<T> seal::SealUseMapBuilder for std::collections::HashMap<String, T> where
1541    T: crate::load::Buildable
1542{
1543}
1544impl<T> seal::SealUseMapBuilder for std::collections::BTreeMap<String, T> where
1545    T: crate::load::Buildable
1546{
1547}
1548impl<T> ShouldUseMapBuilder for std::collections::HashMap<String, T>
1549where
1550    T: crate::load::Buildable,
1551{
1552    type BuilderMap = std::collections::HashMap<String, T::Builder>;
1553}
1554impl<T> ShouldUseMapBuilder for std::collections::BTreeMap<String, T>
1555where
1556    T: crate::load::Buildable,
1557{
1558    type BuilderMap = std::collections::BTreeMap<String, T::Builder>;
1559}
1560
1561/// A trait implemented by types that we shouldn't actually use as fields in a configuration.
1562pub trait ShouldNotBeUsed: seal::SealShouldNotBeUsed {}
1563impl_many! {
1564    // This is unsuitable, since there is no actual way to set a value to `none` in Toml.
1565    // Use Duration with a default instead.
1566    Option<std::time::Duration>,
1567    Option<Option<std::time::Duration>>
1568    : seal::SealShouldNotBeUsed, ShouldNotBeUsed
1569}
1570/// Declare that types shouldn't be used in a collection (because they would want magic
1571/// serde handling, but that isn't implemented).
1572macro_rules! should_not_be_used_in_collection {
1573    { $($t:ty),* $(,)?} => {
1574        $(
1575        impl_many!{
1576            Vec<$t>,
1577            std::collections::BTreeSet<$t>,
1578            std::collections::HashSet<$t>
1579            : seal::SealShouldNotBeUsed, ShouldNotBeUsed
1580        }
1581        impl<K> seal::SealShouldNotBeUsed for std::collections::HashMap<K,$t> {}
1582        impl<K> ShouldNotBeUsed for std::collections::HashMap<K,$t> {}
1583        impl<K> seal::SealShouldNotBeUsed for std::collections::BTreeMap<K,$t> {}
1584        impl<K> ShouldNotBeUsed for std::collections::BTreeMap<K,$t> {}
1585        )*
1586    }
1587}
1588should_not_be_used_in_collection! {
1589    std::time::Duration,
1590}
1591
1592/// Give a compile time error if the type $t implements $trait.
1593///
1594/// Includes the identifier $rule in the error message, to help the user diagnose
1595/// the problem.  (This is the main difference between this macro and the one in
1596/// `static_assertions`.)
1597///
1598/// # Example (Succeeding.)
1599///
1600/// ```
1601/// // No error will occur; String is not Buildable.
1602/// tor_config::derive::assert_not_impl!{
1603///     [copy_is_forbidden_here] String : tor_config::load::Buildable
1604/// }
1605/// ```
1606///
1607/// ```compile_fail
1608/// // Compile-time error _is_ given; String implements Clone.
1609/// tor_config::derive::assert_not_impl!{
1610///     [clone_is_forbidden_here] String : Clone
1611/// }
1612/// ```
1613#[macro_export]
1614macro_rules! assert_not_impl {
1615    {[$rule:ident] $t:ty : $trait:path } => {
1616        const _ : () = {
1617            #[allow(dead_code, non_camel_case_types)]
1618            trait $rule<X> {
1619                fn item();
1620            }
1621            impl $rule<()> for $t { fn item() {}}
1622            struct Invalid;
1623            impl<T : $trait + ?Sized> $rule<Invalid> for T { fn item() {} }
1624            let _ = <$t as $rule<_>>::item;
1625        };
1626    }
1627}
1628pub use assert_not_impl;
1629
1630define_derive_deftly! {
1631    /// Define a builder type for a given type, with settings appropriate to participate in the Arti
1632    /// build system.
1633    ///
1634    /// See [module documentation](crate::derive) for more information and usage instructions.
1635    export TorConfig beta_deftly, for struct:
1636
1637    #[allow(unused_imports)]
1638    use $crate::derive::exports as $<__tor_config_exports__ $tname>;
1639
1640    // -------------------
1641    // Common definitions and aliases.
1642
1643    // Location of exports for this macro.
1644    ${define E {$crate::derive::exports}}
1645
1646    // Location of exports for this macro, as a string.
1647    //
1648    // TODO $crate: I would prefer to use ${concat $crate "::derive::exports"} instead,
1649    // but that won't work, since $crate gets expanded at the wrong time.
1650    // See
1651    // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/132#note_3288325
1652    // for discussion of the workaround used here.
1653    ${define EX ${concat "__tor_config_exports__" $tname}}
1654
1655    // Current field name as string.
1656    ${define FNAME { ${concat $fname} }}
1657
1658    // Name of the build method.
1659    ${define BLD_NAME {
1660        ${tmeta(tor_config(build_fn(name))) as ident, default build}
1661    } }
1662
1663    // -------------------
1664    // Definitions and aliases for defining the builder struct.
1665
1666    // True if the field type appears to be `std::time::Duration`
1667    //
1668    // (This can't be done with the regular "magic" macro system,
1669    // since it needs to be used in expansions that produce a field attribute.
1670    // macro_rules! macros can't appear in a field-attribute position.
1671    // There _are_ workarounds here, which I'll consider while
1672    // reafactoring the magic system.)
1673    ${defcond F_IS_DURATION
1674        any(approx_equal({$ftype}, {Duration}),
1675            approx_equal({$ftype}, {time::Duration}),
1676            approx_equal({$ftype}, {std::time::Duration}),
1677            approx_equal({$ftype}, {::std::time::Duration}))
1678    }
1679
1680    // True if the field type should receive magic handling with serde.
1681    ${defcond F_SERDE_MAGIC any(F_IS_DURATION)}
1682
1683    // Condition: True unless Serialize and Deserialize have both been disabled.
1684    ${defcond SERDE
1685        not(all(tmeta(tor_config(no_serialize_trait)),
1686                tmeta(tor_config(no_deserialize_trait))))
1687    }
1688
1689    // Expands to any attributes that should be applied to the current builder field
1690    // based on magic type behavior.
1691    ${define BLD_MAGIC_ATTRIBUTES
1692        ${if fmeta(tor_config(no_magic)) {
1693        } else if SERDE {
1694            ${select1
1695            F_IS_DURATION {
1696                ${if SERDE {
1697                    #[serde(with = ${concat $EX "::humantime_serde::option"})]
1698                }}
1699            }
1700            // HEY YOU! DON'T ADD ANY MORE MAGIC SERDE TYPES HERE WITHOUT READING THIS!
1701            // 1. You need to add the condition for your type to `F_SERDE_MAGIC`,
1702            //    and you need to make sure that your type implements
1703            //    `ShouldBeCaughtAsSerdeSpecialCase`.
1704            // 2. You need to document the behavior in `doc_magic_types`.
1705            else {
1706                ${if F_SERDE_MAGIC {
1707                    ${error "Type should receive magic handling with serde, but we failed to apply any."}
1708                }}
1709                // No magic needed.
1710            }}
1711        }}
1712    }
1713
1714    // For each list_builder field: the names of the list builder
1715    // type to define.
1716    ${define F_LST_BLD_TYPE {  $<
1717        ${fmeta(tor_config(list(listtype))) as ty,
1718            default ${paste $tname ${upper_camel_case $fname} List}
1719     } Builder>} }
1720
1721    // For each map_builder field: the names of the map builder
1722    // type to define.
1723    ${define F_MAP_TYPE { ${paste // See derive_deftly#138 for this $paste.
1724        ${fmeta(tor_config(map(maptype))) as ty,
1725            default ${paste $tname ${upper_camel_case $fname} Map}}
1726    }}}
1727    ${define F_MAP_BLD_TYPE { $< $F_MAP_TYPE Builder > }}
1728
1729    // Expands to $ftype of the current builder field, as modified by type magic.
1730    // (Most everybody should use $BLD_FTYPE instead.)
1731    ${define BLD_MAGIC_FTYPE {
1732        ${if fmeta(tor_config(no_magic)) {
1733            $ftype
1734        } else {
1735            $E::bld_magic_type!($ftype)
1736        }}
1737    }}
1738    // Expands to the type of the field within the builder.
1739    ${define BLD_FTYPE {
1740        ${if fmeta(tor_config(field(ty))) {
1741            ${fmeta(tor_config(field(ty))) as ty}
1742        } else if fmeta(tor_config(sub_builder)) {
1743            $< $ftype Builder >
1744        } else if fmeta(tor_config(list)) {
1745            $F_LST_BLD_TYPE
1746        } else if fmeta(tor_config(map)) {
1747            $F_MAP_BLD_TYPE
1748        } else {
1749            $E::Option<$BLD_MAGIC_FTYPE>
1750        }}
1751    }}
1752
1753    // Expands to the error type for this builder.
1754    ${define ERR
1755       ${tmeta(tor_config(build_fn(error))) as ty, default {$E::ConfigBuildError}}}
1756
1757    // If the current field is conditionally present, expands to the `cfg`
1758    // attribute we should apply to it.
1759    ${define IF_CFG {
1760        // TODO: Infelicity: It would be nice if this didn't have to take "cfg" as a string.
1761        // See https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
1762        ${if fmeta(tor_config(cfg)) {
1763            #[cfg( ${fmeta(tor_config(cfg)) as token_stream} )]
1764        }}
1765    }}
1766
1767    // Visibility for the builder type.
1768    //
1769    // TODO: d-d has no ` .. as vis`, which is what really want.
1770    // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/137
1771    // (also, below)
1772    ${define BLD_TVIS
1773        ${tmeta(tor_config(vis)) as token_stream, default $tvis}
1774    }
1775
1776    // Visibility for the current field in the builder type.
1777    ${define BLD_FVIS
1778        ${fmeta(tor_config(field(vis))) as token_stream, default {} }
1779    }
1780
1781    // True if we want to derive Flattenable for the builder type
1782    ${defcond DD_FLATTENABLE_ON_BUILDER
1783        all(not(tmeta(tor_config(no_deserialize_trait))),
1784            not(tmeta(tor_config(no_flattenable_trait)))
1785        )}
1786
1787    // Expands to the visibility for the current setter/accessor,
1788    // and for any types that we generate for it to expose.
1789    ${define SETTER_VIS {
1790        ${fmeta(tor_config(setter(vis))) as token_stream, default $BLD_TVIS}
1791    }}
1792
1793    // -------------------
1794    // Invoke checks for our type-handling macros.
1795
1796    $(
1797        ${if fmeta(tor_config(no_magic)) {
1798            // If we're disabling the magic, this is fine.
1799        } else {
1800            // Make sure that, for every other, it gets matched by the right case of
1801            // normalize_and_invoke.
1802            //
1803            // (We do this because our type checking in normalize_and_invoke is imperfect,
1804            // and can't detect aliases.)
1805            $E::bld_magic_check_type!({$ftype});
1806        }}
1807        ${if all(not(F_SERDE_MAGIC), not(fmeta(tor_config(no_magic))) ) {
1808            // If we don't get special handling from serde, make sure that the type doesn't actually
1809            // need it.
1810            //
1811            // (We do this because our type checking in F_IS_DURATION is imperfect and can't
1812            // detect)
1813            $E::assert_not_impl!(
1814                [type_was_not_correctly_identified_as_a_TorConfig_serde_special_case]
1815                $ftype: $E::ShouldBeCaughtAsSerdeSpecialCase
1816            );
1817        }}
1818    )
1819
1820    // -------------------
1821    // Check for types that don't make sense in a configuration.
1822    $(
1823        ${when not(fmeta(tor_config(no_magic)))}
1824
1825        $E::assert_not_impl!(
1826            [field_type_not_suitable_for_configuration]
1827            $ftype: $E::ShouldNotBeUsed
1828        );
1829    )
1830
1831    // -------------------
1832    // Check for missing invocations of sub_builder, list, or map.
1833    $(
1834        ${when not(any(
1835            fmeta(tor_config(sub_builder)),
1836            fmeta(tor_config(no_sub_builder)),
1837            fmeta(tor_config(no_magic)),
1838            fmeta(tor_config(build)),
1839            fmeta(tor_config(try_build)),
1840        ))}
1841        $E::assert_not_impl!(
1842            [missing_sub_builder_declaration_for_Buildable_field]
1843            $ftype: $E::BuildableTrait
1844        );
1845    )
1846
1847    $(
1848        ${when not(any(
1849            fmeta(tor_config(no_sub_builder)),
1850            fmeta(tor_config(no_magic)),
1851            fmeta(tor_config(list)),
1852        ))}
1853        $E::assert_not_impl!(
1854            [field_should_use_list_builder_or_opt_out]
1855            $ftype: $E::ShouldUseListBuilder
1856        );
1857    )
1858
1859    $(
1860        ${when not(any(
1861            fmeta(tor_config(no_sub_builder)),
1862            fmeta(tor_config(no_magic)),
1863            fmeta(tor_config(map)),
1864        ))}
1865        $E::assert_not_impl!(
1866            [field_should_use_map_builder_or_opt_out]
1867            $ftype: $E::ShouldUseMapBuilder
1868        );
1869    )
1870
1871    // -------------------
1872    // Define the builder type.
1873
1874    #[doc = ${concat "A builder to create an instance of [`" $tname "`].\n"}]
1875    #[derive($E::Default, $E::Clone, $E::Debug, $E::Deftly)]
1876    ${if not(tmeta(tor_config(no_deserialize_trait))) {
1877        #[derive($E::Deserialize)]
1878    }}
1879    ${if not(tmeta(tor_config(no_serialize_trait))) {
1880        #[derive($E::Serialize)]
1881    }}
1882    ${if DD_FLATTENABLE_ON_BUILDER {
1883        #[derive_deftly($E::Flattenable)]
1884    }}
1885    // TODO: drop requirement this be a string.
1886    // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
1887    ${ if tmeta(tor_config(attr)) {
1888        #[ ${tmeta(tor_config(attr)) as token_stream} ]
1889    }}
1890    #[allow(dead_code)]
1891    $BLD_TVIS struct $<$tname Builder><$tdefgens>
1892    where $twheres
1893    {
1894        $(
1895            ${when not(fmeta(tor_config(skip)))}
1896
1897            // TODO: drop requirement this be a string.
1898            // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
1899            ${if fmeta(tor_config(attr)) {
1900                #[${fmeta(tor_config(attr)) as token_stream}]
1901            }}
1902            ${if SERDE {
1903                #[serde(default)]
1904            }}
1905            // TODO: drop requirement this be a string.
1906            // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
1907            ${ if fmeta(tor_config(serde)) {
1908                #[ serde( ${fmeta(tor_config(serde)) as token_stream} )]
1909            }}
1910            #[doc = ${concat "In-progress value for " $fname ".\n\n"
1911                             "See [`" $tname "." $fname "`]("$tname "#structfield." $fname ")"}]
1912            $BLD_MAGIC_ATTRIBUTES
1913            $IF_CFG
1914            $BLD_FVIS ${fdefine $fname} $BLD_FTYPE,
1915
1916            ${if all(SERDE, fmeta(tor_config(cfg))) {
1917                /// Placeholder to catch attempts to use this field when
1918                /// disabled by configuration.
1919                ///
1920                /// (This uses `serde_value` to make sure that Deserialize+Serialize is not
1921                /// needlessly lossy.)
1922                #[cfg(not(${fmeta(tor_config(cfg)) as token_stream} ))]
1923                #[serde(default)]
1924                ${fdefine $fname} $E::Option<$E::serde_value::Value>,
1925            }}
1926        )
1927    }
1928
1929    // -------------------
1930    // Define any list-builder or map-builder types.
1931
1932    ${define BUILD_LIST_ELEMENT {
1933        ${select1
1934        fmeta(tor_config(list(element(build)))) {
1935            |v| v.${fmeta(tor_config(list(element(build)))) as ident, default build}()
1936        }
1937        fmeta(tor_config(list(element(clone)))) {
1938            |v| Ok(v.clone())
1939        }
1940        else {
1941            ${error "With list, must specify list(element(clone)) or list(element(build))"}
1942        }}
1943    }}
1944    ${define BLD_LIST_ELT_TYPE {
1945        ${select1
1946        fmeta(tor_config(list(element(build)))) {
1947            // TODO: Find a way to get the argument types for the setters be
1948            // nicer.
1949            //
1950            // It would be cool if we could paste "Builder" on to the end of the
1951            // output of $E::list_element, but that doesn't work.
1952            <<$ftype as $E::ShouldUseListBuilder>::Element as $E::BuildableTrait>::Builder
1953        }
1954        fmeta(tor_config(list(element(clone)))) {
1955            // We could use ShouldUseListBuilder::Element here, but the declared
1956            // argument types for the setters would be a bit nasty.
1957            $E::list_element!{ $ftype }
1958        }
1959        else {
1960            ${error "With list, must specify list(element(clone)) or list(element(build))"}
1961        }}
1962    }}
1963
1964    $(
1965        ${when fmeta(tor_config(list))}
1966
1967        $E::define_list_builder_helper! {
1968            #[doc = ${concat "Builder for the `" $ftype "` type.\n\n"}]
1969            $SETTER_VIS struct $F_LST_BLD_TYPE {
1970                $BLD_FVIS $fname: [
1971                    $BLD_LIST_ELT_TYPE
1972                ],
1973            }
1974            built: $ftype = $fname;
1975            default = ${fmeta(tor_config(default)) as expr};
1976            item_build: $BUILD_LIST_ELEMENT;
1977        }
1978    )
1979
1980    $(
1981        ${when fmeta(tor_config(map))}
1982
1983        $E::define_map_builder! {
1984            #[doc = ${concat "Builder for the `" $F_MAP_TYPE "` type.\n\n"}]
1985            $SETTER_VIS struct $F_MAP_BLD_TYPE =>
1986            $BLD_FVIS type $F_MAP_TYPE = {
1987                map: $ftype,
1988                builder_map: <$ftype as $E::ShouldUseMapBuilder>::BuilderMap,
1989            }
1990            defaults: ${fmeta(tor_config(default)) as expr};
1991        }
1992    )
1993
1994    // -------------------
1995    // Definitions to implement setter/accessor methods.
1996
1997    // Expands to the name of the setter/accessor for the current field.
1998    ${define SETTER_NAME { ${fmeta(tor_config(setter(name))) as ident, default $fname} }}
1999
2000    // Expands the declared type that the setter should take as its argument.
2001    ${define SETTER_INPUT_TYPE {
2002        ${select1
2003            fmeta(tor_config(setter(into))) {
2004                impl $E::Into<$ftype>
2005            }
2006            fmeta(tor_config(setter(try_into))) {
2007                SetterArg
2008            }
2009            fmeta(tor_config(setter(strip_option))) {
2010                $E::strip_option!{$ftype}
2011            }
2012            else {
2013                ${if fmeta(tor_config(no_magic)) {
2014                    $ftype
2015                } else {
2016                    $E::bld_magic_setter_arg_type!{$ftype}
2017                }
2018            }}
2019        }}}
2020
2021    // Expands to the generics (if any) that the setter should take.
2022    ${define SETTER_GENS {
2023        ${if fmeta(tor_config(setter(try_into))) {
2024            <SetterArg : $E::TryInto<$ftype>>
2025        } else {
2026        }}
2027    }}
2028
2029    // Expands to the expression that the setter should return.
2030    ${define SETTER_RETURN {
2031        ${if fmeta(tor_config(setter(try_into))) {
2032            Ok(self)
2033        } else {
2034            self
2035        }}
2036    }}
2037
2038    // Expands to the declared return type of the setter.
2039    ${define SETTER_RETURN_TYPE {
2040        ${if fmeta(tor_config(setter(try_into))) {
2041            $E::Result<&mut Self, SetterArg::Error>
2042        } else {
2043            &mut Self
2044        }}
2045    }}
2046
2047    // Expands to a string that we should add to the documentation
2048    // to explain the default value of the current field.
2049    ${define DFLT_DOC {
2050        ${select1
2051            fmeta(tor_config(sub_builder)) { "" }
2052            // TODO: perhaps we should document _something_ about build and try_build,
2053            // even though we can't document any default.
2054            fmeta(tor_config(build)) { "" }
2055            fmeta(tor_config(try_build)) { "" }
2056            fmeta(tor_config(default)) {
2057                ${concat "If no value is provided for `" $fname "`, "
2058                  "[`build`](Self::build) will use `"
2059                  ${fmeta(default) as str, default "Default::default()"}
2060                  "`."
2061            }}
2062            fmeta(tor_config(no_default)) {
2063                ${concat "If no value is provided for `" $fname "`, "
2064                  "[`build`](Self::build) will fail with an error."}
2065            }
2066            else {
2067                ${error "Every field must have default, no_default, try_build, build, or sub_builder."}
2068            }
2069        }
2070    }}
2071
2072    // Expands to a definition of the setter function for the current field.
2073    ${define SET_FN {
2074        #[doc = ${concat "Provide a value for `" $fname "`.\n\n"}]
2075        #[doc = $DFLT_DOC]
2076        ${if not(fmeta(tor_config(no_magic))) {
2077            #[doc = $E::bld_magic_setter_docs!{ { $ftype } } ]
2078        }}
2079        #[doc = ${concat "\n\n## " $fname "\n\n" }]
2080        ${fattrs doc}
2081        $IF_CFG
2082        $SETTER_VIS fn $SETTER_NAME $SETTER_GENS (&mut self, val: $SETTER_INPUT_TYPE) -> $SETTER_RETURN_TYPE {
2083            ${select1
2084                fmeta(tor_config(setter(into))) {
2085                    self.$fname = Some(val.into());
2086                }
2087                fmeta(tor_config(setter(try_into))) {
2088                    self.$fname = Some(val.try_into()?);
2089                }
2090                fmeta(tor_config(setter(strip_option))) {
2091                    self.$fname = Some(Some(val));
2092                }
2093                else {
2094                    ${if fmeta(tor_config(no_magic)) {
2095                        self.$fname = Some(val);
2096                    } else {
2097                        self.$fname = Some($E::bld_magic_setter_cvt!({val} {$ftype}));
2098                    }}
2099                }
2100            }
2101            $SETTER_RETURN
2102        }
2103    }}
2104
2105    ${define F_SUB_BUILDER_TYPE
2106        ${if fmeta(tor_config(map)) {
2107            $F_MAP_BLD_TYPE
2108        } else {
2109            $<$ftype Builder>
2110        }}
2111    }
2112
2113    // Expands to a declaration for the sub-builder accessor function for the current field.
2114    ${define ACCESS_SUBBUILDER_FN {
2115
2116        #[doc = ${concat "Return a mutable reference to the inner builder for `" $fname "`.\n\n"
2117                  "## " $fname "\n\n"
2118                }]
2119        ${fattrs doc}
2120        $IF_CFG
2121        $SETTER_VIS fn $fname(&mut self) -> &mut $F_SUB_BUILDER_TYPE {
2122            &mut self.$fname
2123        }
2124    }}
2125
2126    // -------------------
2127    // Define the setter/accessors methods.
2128
2129    #[allow(dead_code)]
2130    impl<$tgens> $<$ttype Builder>
2131    where $twheres {
2132        $(
2133            ${if any(fmeta(tor_config(setter(skip))),
2134                     fmeta(tor_config(skip)),
2135                     fmeta(tor_config(list))) {
2136                // generate nothing.
2137            } else if any(fmeta(tor_config(sub_builder)),
2138                          fmeta(tor_config(map))) {
2139                $ACCESS_SUBBUILDER_FN
2140            } else {
2141                $SET_FN
2142            }}
2143        )
2144    }
2145
2146    $(
2147        ${when fmeta(tor_config(list))}
2148
2149        $E::define_list_builder_accessors!{
2150            struct $<$tname Builder> {
2151                $SETTER_VIS $fname : [
2152                    $BLD_LIST_ELT_TYPE
2153                 ],
2154            }
2155        }
2156    )
2157
2158    // -------------------
2159    // Definitions and helpers for the build method.
2160
2161    // Expands to the name of the function to use to build the sub-builder for the current field.
2162    ${define SUB_BUILDER_BUILD_FN {
2163        ${fmeta(tor_config(sub_builder(build_fn))) as path, default build}
2164    }}
2165
2166    // Expands to an expression of type Option<$ftype> for the current field,
2167    // taking type-based magic into account.
2168    ${define BLD_MAGIC_CVT {
2169        ${if fmeta(tor_config(no_magic)) {
2170            self.$fname.clone()
2171        } else {
2172            $E::bld_magic_cvt!({self.$fname} {${concat $fname}} {$ftype})
2173        }}
2174    }}
2175
2176    // Expands to the closure we run on a missing field to get the error type.
2177    ${define BLD_MISSING_FIELD {
2178        ${tmeta(tor_config(missing_field)) as expr, default {
2179            |name_of_missing_field: &str| $ERR::MissingField { field: name_of_missing_field.into() }
2180        }}
2181    }}
2182
2183    // Expands to an expression for building the current field,
2184    // and returning an appropriate error if there was a problem.
2185    ${define BUILD_FIELD {
2186         ${select1
2187            any(fmeta(tor_config(sub_builder)),
2188                fmeta(tor_config(list)),
2189                fmeta(tor_config(map))) {
2190                self.$fname.$SUB_BUILDER_BUILD_FN().map_err(|e| e.within($FNAME))?
2191            }
2192            all(fmeta(tor_config(default)), not(any(fmeta(tor_config(list)),
2193                                                    fmeta(tor_config(map))))) {
2194                $BLD_MAGIC_CVT.unwrap_or_else(
2195                    || ${fmeta(tor_config(default)) as expr, default {Default::default()}})
2196            }
2197            fmeta(tor_config(build)) {
2198                (${fmeta(tor_config(build)) as expr})(self)
2199            }
2200            fmeta(tor_config(try_build)) {
2201                (${fmeta(tor_config(try_build)) as expr})(self)?
2202            }
2203            fmeta(tor_config(no_default)) {
2204                $BLD_MAGIC_CVT.ok_or_else(
2205                    || { ($BLD_MISSING_FIELD)(stringify!($fname)) }
2206                )?
2207            }
2208            else {
2209                ${error "Every field must have default, no_default, try_build, build, or sub_builder."}
2210            }
2211        }
2212    }}
2213
2214    // Expands to the visibility of the build method.
2215    ${define BLD_FN_VIS {
2216        ${tmeta(tor_config(build_fn(vis))) as token_stream, default $BLD_TVIS}
2217    }}
2218
2219    // -------------------
2220    // Define the build method and the new() method.
2221
2222    #[allow(dead_code)]
2223    impl<$tgens> $<$ttype Builder>
2224    where $twheres {
2225        /// Return a new builder object.
2226        $BLD_TVIS fn new() -> Self {
2227            Self::default()
2228        }
2229
2230        #[doc = ${concat
2231            "Try to construct a new [`" $tname "`] from the fields set in this builder.\n\n"
2232            "Return an error if any required field is missing, or is set to something invalid.\n"
2233        }]
2234        $BLD_FN_VIS fn $BLD_NAME(&self) -> $E::Result<$ttype, $ERR> {
2235            // Call pre_build as appropriate.
2236            ${if tmeta(tor_config(pre_build)) {
2237                let () = ${tmeta(tor_config(pre_build)) as path}(self)?;
2238            }}
2239
2240            // Warn if any configured-out option was provided.
2241            $(
2242                ${if fmeta(tor_config(cfg)) {
2243                    #[cfg(not( ${fmeta(tor_config(cfg)) as token_stream} ))]
2244                    if self.$fname.is_some() {
2245                        ${if fmeta(tor_config(cfg_reject)) {
2246                            return Err($E::ConfigBuildError::NoCompileTimeSupport {
2247                                field: stringify!($fname).to_string(),
2248                                problem: ${concat "The program was not built "
2249                                    ${fmeta(tor_config(cfg_desc)) as str}
2250                                }.to_string()
2251                            });
2252                        } else {
2253                            $E::tracing::warn!(
2254                                ${concat "Ignored configuration for '" $fname
2255                                "'. This option has no effect unless the program is built "
2256                                ${fmeta(tor_config(cfg_desc)) as str} "'"}
2257                            )
2258                        }}
2259                    }
2260                }}
2261            )
2262
2263            // Construct the configuration struct.
2264            let result = $tname {
2265                $(
2266                    $IF_CFG
2267                    $fname: $BUILD_FIELD ,
2268
2269                    ${if fmeta(tor_config(cfg)) {
2270                        #[cfg(not( ${fmeta(tor_config(cfg)) as token_stream} ))]
2271                        $fname: $E::Default::default(),
2272                    }}
2273                )
2274            };
2275
2276            // Call the post_build function to transform the result.
2277            ${if tmeta(tor_config(post_build)) {
2278                let result = ${tmeta(tor_config(post_build)) as path}(result)?;
2279            }}
2280
2281            Ok(result)
2282        }
2283    }
2284
2285    // -------------------
2286    // Add a builder() method to the configuration type.
2287    //
2288    // NOTE: This and some other code below is redundant with impl_standard_builder!().
2289    // I'm not using that trait here because complying with its input format is rather
2290    // baroque, and it's easier just to do it ourselves.
2291
2292    impl<$tgens> $ttype
2293    where $twheres {
2294        #[doc = ${concat "Return a new [`" $tname " Builder`] to construct an instance of this type."}]
2295        #[allow(dead_code)]
2296        $tvis fn builder() -> $<$ttype Builder> {
2297            $<$ttype Builder>::default()
2298        }
2299    }
2300
2301    // -------------------
2302    // Implement `$crate::load::Builder` for the Builder type.
2303
2304    ${if not(tmeta(tor_config(no_builder_trait))) {
2305        impl<$tgens> $E::BuilderTrait for $<$ttype Builder>
2306        where $twheres {
2307            type Built = $ttype;
2308            // We're writing it this way in case Builder::build() returns
2309            // a different Error type.
2310            #[allow(clippy::needless_question_mark)]
2311            fn build(&self) -> $E::Result<$ttype, $E::ConfigBuildError> {
2312                Ok($<$ttype Builder>::$BLD_NAME(self)?)
2313            }
2314        }
2315    }}
2316
2317    // -------------------
2318    // Implement $crate::extend_builder::ExtendBuiler on the builder type.
2319    // (We can't use derive_deftly_template_ExtendBuilder, since that macro was
2320    // written to apply to the configuration type and modify its builder. (!))
2321
2322    ${if not(tmeta(tor_config(no_extendbuilder_trait))) {
2323        impl<$tgens> $E::ExtendBuilder for $<$ttype Builder>
2324        where $twheres {
2325            #[allow(unused_variables)]
2326            fn extend_from(&mut self, other: Self, strategy: $E::ExtendStrategy) {
2327                ${for fields {
2328                    ${when not(fmeta(tor_config(skip)))}
2329
2330                    ${if fmeta(tor_config(cfg)) {
2331                        // For conditionally present features, it doesn't matter what we put
2332                        // in the field, so long as we make it set whenever _either_ config is set.
2333                        #[cfg(not( ${fmeta(tor_config(cfg)) as token_stream} ))]
2334                        if other.$fname.is_some() {
2335                            self.$fname = other.$fname;
2336                        }
2337
2338                        #[cfg( ${fmeta(tor_config(cfg)) as token_stream} )]
2339                    }}
2340                    {
2341                        ${if fmeta(tor_config(extend_with)) {
2342                            ${fmeta(tor_config(extend_with)) as expr}(&mut self.$fname, other.$fname, strategy);
2343                        } else if fmeta(tor_config(extend_with_replace)) {
2344                            if let Some(other_val) = other.$fname {
2345                                self.$fname = Some(other_val);
2346                            }
2347                        } else if any(fmeta(tor_config(sub_builder)),
2348                                fmeta(tor_config(list)),
2349                                fmeta(tor_config(map))) {
2350                            $E::ExtendBuilder::extend_from(&mut self.$fname, other.$fname, strategy);
2351                        } else {
2352                            if let Some(other_val) = other.$fname {
2353                                self.$fname = Some(other_val);
2354                            }
2355                        }}
2356                    }
2357                }}
2358            }
2359        }
2360    }}
2361
2362    // -------------------
2363    // Implement `$crate::load::Buildable` for the configuration type.
2364    ${if not(tmeta(tor_config(no_buildable_trait))) {
2365        impl<$tgens> $E::BuildableTrait for $ttype
2366        where $twheres {
2367            type Builder = $<$ttype Builder>;
2368
2369            fn builder() -> $<$ttype Builder> {
2370                $<$ttype Builder>::default()
2371            }
2372        }
2373    }}
2374
2375
2376    // -------------------
2377    // Implement `Default` for the configuration type, in terms of the Builder.
2378    // (Unless the no_default_trait attribute was present.)
2379    ${if not(tmeta(tor_config(no_default_trait))) {
2380        impl<$tgens> $E::Default for $ttype
2381        where $twheres {
2382            fn default() -> Self {
2383                // It's okay to use unwrap; one of the test cases verifies it.
2384                $<$ttype Builder>::default().$BLD_NAME().unwrap()
2385            }
2386        }
2387    }}
2388
2389    // ------------------
2390    // Test module for the builder.
2391    ${if not(any(
2392        tmeta(tor_config(no_default_trait)),
2393        tmeta(tor_config(no_deserialize_trait)),
2394        tmeta(tor_config(no_test_default))))
2395        {
2396        #[cfg(test)]
2397        mod $<test_ ${snake_case $tname} _builder> {
2398            #[test]
2399            // TODO: doesn't work on generics. Do we care?  If so, how should we fix?
2400            fn test_impl_default() {
2401                let def = super::$ttype::default();
2402                let empty_config = $E::figment::Figment::new();
2403                let builder: super::$<$ttype Builder> = empty_config.extract().unwrap();
2404                let from_empty = builder.$BLD_NAME().unwrap();
2405                assert_eq!(def, from_empty);
2406            }
2407        }
2408    }}
2409}
2410pub use derive_deftly_template_TorConfig;
2411
2412#[cfg(test)]
2413mod test {
2414    // @@ begin test lint list maintained by maint/add_warning @@
2415    #![allow(clippy::bool_assert_comparison)]
2416    #![allow(clippy::clone_on_copy)]
2417    #![allow(clippy::dbg_macro)]
2418    #![allow(clippy::mixed_attributes_style)]
2419    #![allow(clippy::print_stderr)]
2420    #![allow(clippy::print_stdout)]
2421    #![allow(clippy::single_char_pattern)]
2422    #![allow(clippy::unwrap_used)]
2423    #![allow(clippy::unchecked_time_subtraction)]
2424    #![allow(clippy::useless_vec)]
2425    #![allow(clippy::needless_pass_by_value)]
2426    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
2427
2428    use crate::ConfigBuildError;
2429    use assert_matches::assert_matches;
2430    use tracing_test::traced_test;
2431
2432    /// Separate module to put config structs and their builders in, so that they aren't
2433    /// able to pick up anything we don't deliberately import.
2434    mod t {
2435        use std::{
2436            collections::{BTreeSet, HashMap},
2437            num::{NonZero, NonZeroU8},
2438            time::Duration,
2439        };
2440
2441        // use crate::derive::prelude::*;
2442        use derive_deftly::Deftly;
2443
2444        #[derive(Deftly, Clone, Debug, PartialEq)]
2445        #[derive_deftly(TorConfig)]
2446        pub(super) struct Simple {
2447            #[deftly(tor_config(default))]
2448            pub(super) xyz: u32,
2449
2450            #[deftly(tor_config(default = "3"))]
2451            pub(super) abc: u16,
2452
2453            #[deftly(tor_config(build = "|_self| 6 * 7"))]
2454            pub(super) forty_two: u16,
2455
2456            #[deftly(tor_config(
2457                try_build = "|_self| Ok::<_,crate::ConfigBuildError>(6 * 7 + 1)"
2458            ))]
2459            pub(super) forty_three: u16,
2460        }
2461
2462        #[derive(Deftly, Clone, Debug, PartialEq)]
2463        #[derive_deftly(TorConfig)]
2464        #[deftly(tor_config(no_default_trait))]
2465        pub(super) struct FieldNoDefault {
2466            #[deftly(tor_config(default))]
2467            pub(super) has_default: u32,
2468            #[deftly(tor_config(no_default))]
2469            pub(super) has_no_default: u32,
2470        }
2471
2472        #[derive(Deftly, Clone, Debug, PartialEq)]
2473        #[derive_deftly(TorConfig)]
2474        #[deftly(tor_config(no_default_trait))]
2475        pub(super) struct Sub {
2476            #[deftly(tor_config(sub_builder))]
2477            pub(super) simple: Simple,
2478
2479            #[deftly(tor_config(sub_builder))]
2480            pub(super) fnd: FieldNoDefault,
2481
2482            #[deftly(tor_config(default))]
2483            pub(super) s: String,
2484        }
2485
2486        #[derive(Deftly, Clone, Debug, PartialEq)]
2487        #[derive_deftly(TorConfig)]
2488        pub(super) struct Magic {
2489            #[deftly(tor_config(default = "nz(7)"))]
2490            pub(super) nzu8: NonZeroU8,
2491
2492            #[deftly(tor_config(default = "nz(123)"))]
2493            pub(super) nzu8_2: NonZero<u8>,
2494
2495            #[deftly(tor_config(default))]
2496            pub(super) dur: Duration,
2497
2498            #[deftly(tor_config(default))]
2499            pub(super) s: String,
2500        }
2501
2502        fn nz(x: u8) -> NonZeroU8 {
2503            x.try_into().unwrap()
2504        }
2505
2506        #[derive(Deftly, Clone, Debug, PartialEq)]
2507        #[derive_deftly(TorConfig)]
2508        pub(super) struct CfgEnabled {
2509            // MSRV 1.88: Use "true" instead.
2510            #[deftly(tor_config(
2511                default,
2512                cfg = "all()",
2513                cfg_desc = "with eschaton immenentization"
2514            ))]
2515            pub(super) flower_power: u32,
2516            // MSRV 1.88: Use "true" instead.
2517            #[deftly(tor_config(
2518                default,
2519                cfg = "all()",
2520                cfg_reject,
2521                cfg_desc = "with eschaton immenentization"
2522            ))]
2523            pub(super) flower_power_err: u32,
2524        }
2525
2526        #[derive(Deftly, Clone, Debug, PartialEq)]
2527        #[derive_deftly(TorConfig)]
2528        pub(super) struct CfgDisabled {
2529            // MSRV 1.88: Use "false" instead.
2530            #[deftly(tor_config(
2531                default,
2532                cfg = "any()",
2533                cfg_desc = "with resublimated thiotimoline"
2534            ))]
2535            pub(super) time_travel: u32,
2536            #[deftly(tor_config(
2537                default,
2538                cfg = "any()",
2539                cfg_reject,
2540                cfg_desc = "with resublimated thiotimoline"
2541            ))]
2542            pub(super) time_travel_err: u32,
2543        }
2544
2545        #[derive(Deftly, Clone, Debug, PartialEq)]
2546        #[derive_deftly(TorConfig)]
2547        #[deftly(tor_config(
2548            pre_build = "Self::check_odd",
2549            post_build = "CfgValidating::check_even"
2550        ))]
2551        pub(super) struct CfgValidating {
2552            #[deftly(tor_config(default = "1"))]
2553            pub(super) odd: u32,
2554            #[deftly(tor_config(default))]
2555            pub(super) even: u32,
2556        }
2557        impl CfgValidatingBuilder {
2558            fn check_odd(&self) -> Result<(), crate::ConfigBuildError> {
2559                if let Some(v) = self.odd {
2560                    if v & 1 != 1 {
2561                        return Err(crate::ConfigBuildError::Invalid {
2562                            field: "odd".to_string(),
2563                            problem: "Not odd".to_string(),
2564                        });
2565                    }
2566                }
2567                Ok(())
2568            }
2569        }
2570        impl CfgValidating {
2571            fn check_even(self) -> Result<Self, crate::ConfigBuildError> {
2572                if self.even & 1 != 0 {
2573                    return Err(crate::ConfigBuildError::Invalid {
2574                        field: "even".to_string(),
2575                        problem: "Not even".to_string(),
2576                    });
2577                }
2578                Ok(self)
2579            }
2580        }
2581
2582        #[derive(Deftly, Clone, Debug, PartialEq)]
2583        #[derive_deftly(TorConfig)]
2584        #[deftly(tor_config(
2585            no_serialize_trait,
2586            no_test_default,
2587            no_extendbuilder_trait,
2588            no_flattenable_trait
2589        ))]
2590        pub(super) struct CfgGeneric<T, U>
2591        where
2592            T: Clone + std::fmt::Debug + PartialEq + Default,
2593            U: Clone + std::fmt::Debug + PartialEq + Default,
2594        {
2595            #[deftly(tor_config(default, no_magic))]
2596            pub(super) t: T,
2597            #[deftly(tor_config(default, no_magic))]
2598            pub(super) u: U,
2599        }
2600
2601        #[derive(Deftly, Clone, Debug, PartialEq)]
2602        #[derive_deftly(TorConfig)]
2603        pub(super) struct OptionsCfg {
2604            #[deftly(tor_config(default))]
2605            pub(super) a: Option<u32>,
2606            #[deftly(tor_config(default = "Some(123)"))]
2607            pub(super) b: Option<u32>,
2608            #[deftly(tor_config(default = "Some(nz(42))"))]
2609            pub(super) nz: Option<NonZeroU8>,
2610            #[deftly(tor_config(default))]
2611            pub(super) s: Option<String>,
2612            #[deftly(tor_config(default))]
2613            pub(super) other: Option<(u32, u32)>,
2614        }
2615
2616        #[derive(Deftly, Clone, Debug, PartialEq)]
2617        #[derive_deftly(TorConfig)]
2618        #[deftly(tor_config(attr = "derive(Eq,Ord,PartialOrd,PartialEq)"))]
2619        pub(super) struct AttribsCfg {
2620            #[deftly(tor_config(default))]
2621            #[deftly(tor_config(attr = r#"serde(alias = "fun_with_numbers")"#))]
2622            #[deftly(tor_config(serde = r#"alias = "its_fun_to_count""#))]
2623            pub(super) a: u32,
2624        }
2625
2626        #[derive(Deftly, Clone, Debug, PartialEq)]
2627        #[derive_deftly(TorConfig)]
2628        pub(super) struct SettersCfg {
2629            #[deftly(tor_config(default, setter(skip)))]
2630            pub(super) a: u32,
2631
2632            #[deftly(tor_config(default, setter(into)))]
2633            pub(super) b: u32,
2634
2635            #[deftly(tor_config(default, setter(try_into)))]
2636            pub(super) c: u32,
2637            #[deftly(tor_config(default, setter(strip_option)))]
2638            pub(super) d: Option<u32>,
2639            #[deftly(tor_config(default, setter(name = "set_the_e")))]
2640            pub(super) e: u32,
2641        }
2642        impl SettersCfgBuilder {
2643            // Custom setter.
2644            pub(super) fn a(&mut self, val: u32) {
2645                self.a = Some(val * 2);
2646            }
2647        }
2648
2649        #[derive(Deftly, Clone, Debug, PartialEq)]
2650        #[derive_deftly(TorConfig)]
2651        #[deftly(tor_config(no_serialize_trait, no_deserialize_trait))]
2652        pub(super) struct NoSerdeCfg {
2653            #[deftly(tor_config(default))]
2654            pub(super) ip: u128,
2655        }
2656
2657        #[derive(Deftly, Clone, Debug, PartialEq)]
2658        #[derive_deftly(TorConfig)]
2659        #[deftly(tor_config(build_fn(name = "build_this")))]
2660        pub(super) struct RenameBuild {
2661            #[deftly(tor_config(default))]
2662            pub(super) member: u16,
2663        }
2664
2665        #[derive(Deftly, Clone, Debug, PartialEq)]
2666        #[derive_deftly(TorConfig)]
2667        pub(super) struct RenameSubBuild {
2668            #[deftly(tor_config(sub_builder(build_fn = "build_this")))]
2669            pub(super) inner: RenameBuild,
2670        }
2671
2672        #[derive(Deftly, Clone, Debug, PartialEq)]
2673        #[derive_deftly(TorConfig)]
2674        pub(super) struct FullyCustom {
2675            #[deftly(tor_config(
2676                setter(skip),
2677                field(ty = "(u32, u32)", vis = "pub(super)"),
2678                build = r#"|this: &Self| format!("{} {}", this.value.0, this.value.1)"#,
2679                extend_with = r#"|mine: &mut (u32,u32), theirs: (u32,u32), _| *mine = theirs"#,
2680            ))]
2681            pub(super) value: String,
2682        }
2683        impl FullyCustomBuilder {
2684            pub(super) fn try_the_thing(&mut self, x: u64) {
2685                self.value = ((x >> 32) as u32, x as u32);
2686            }
2687        }
2688        #[derive(Deftly, Clone, Debug, PartialEq)]
2689        #[derive_deftly(TorConfig)]
2690        pub(super) struct FieldSkipCfg {
2691            #[deftly(tor_config(skip, build = r#"|_this: &Self| 25"#))]
2692            pub(super) value: u32,
2693        }
2694
2695        #[derive(Deftly, Clone, Debug, PartialEq)]
2696        #[derive_deftly(TorConfig)]
2697        pub(super) struct ListsCfg {
2698            #[deftly(tor_config(list(element(clone)), default = "vec![7]"))]
2699            pub(super) integers: Vec<u32>,
2700
2701            #[deftly(tor_config(
2702                list(listtype = "StringSet", element(clone)),
2703                default = "cats()"
2704            ))]
2705            pub(super) cats: BTreeSet<String>,
2706
2707            #[deftly(tor_config(list(element(build)), default = "vec![]"))]
2708            pub(super) simple: Vec<Simple>,
2709        }
2710
2711        fn cats() -> Vec<String> {
2712            ["Damiano", "Moonbeam", "Checkers", "Enigma"]
2713                .iter()
2714                .map(|s| s.to_string())
2715                .collect()
2716        }
2717
2718        #[derive(Deftly, Clone, Debug, PartialEq)]
2719        #[derive_deftly(TorConfig)]
2720        pub(super) struct MapCfg {
2721            #[deftly(tor_config(map, default = "default_map()"))]
2722            pub(super) map: HashMap<String, Simple>,
2723        }
2724        fn default_map() -> HashMap<String, SimpleBuilder> {
2725            let mut b = SimpleBuilder::new();
2726            b.abc(32);
2727            b.xyz(123);
2728            let mut m = HashMap::new();
2729            m.insert("pangolin".to_string(), b);
2730            m
2731        }
2732    }
2733
2734    #[test]
2735    fn test_simple_defaults() {
2736        let b = t::SimpleBuilder::new();
2737        let x = b.build().unwrap();
2738        assert_eq!(x.xyz, 0);
2739        assert_eq!(x.abc, 3);
2740        assert_eq!(x.forty_two, 42);
2741        assert_eq!(x.forty_three, 43);
2742    }
2743
2744    #[test]
2745    fn test_simple_setters() {
2746        let mut b = t::SimpleBuilder::new();
2747        let x = b.abc(7).xyz(77).forty_two(777).build().unwrap();
2748        assert_eq!(x.xyz, 77);
2749        assert_eq!(x.abc, 7);
2750        assert_eq!(x.forty_two, 42);
2751        assert_eq!(x.forty_three, 43);
2752    }
2753
2754    #[test]
2755    fn test_simple_serde() {
2756        let v = r#"
2757        xyz = 7
2758        "#;
2759        let b: t::SimpleBuilder = toml::from_str(v).unwrap();
2760        let x = b.build().unwrap();
2761        assert_eq!(x.xyz, 7);
2762        assert_eq!(x.abc, 3);
2763        assert_eq!(x.forty_two, 42);
2764        assert_eq!(x.forty_three, 43);
2765    }
2766
2767    #[test]
2768    fn test_field_no_default() {
2769        let e = t::FieldNoDefaultBuilder::new().build().unwrap_err();
2770        assert_matches!(
2771            e,
2772            ConfigBuildError::MissingField {
2773                field
2774            } if field == "has_no_default"
2775        );
2776        let v = t::FieldNoDefaultBuilder::new()
2777            .has_no_default(42)
2778            .build()
2779            .unwrap();
2780        assert_eq!(v.has_default, 0);
2781        assert_eq!(v.has_no_default, 42);
2782    }
2783
2784    #[test]
2785    fn test_subbuilder() {
2786        let e = t::SubBuilder::new().build().unwrap_err();
2787        assert_matches!(
2788            e,
2789            ConfigBuildError::MissingField {
2790                field
2791            } if field == "fnd.has_no_default"
2792        );
2793
2794        let mut b = t::SubBuilder::new();
2795        b.fnd().has_no_default(5).has_default(66);
2796        b.simple().abc(123);
2797        b.s("Hello");
2798        let v = b.build().unwrap();
2799        assert_eq!(v.fnd.has_no_default, 5);
2800        assert_eq!(v.fnd.has_default, 66);
2801        assert_eq!(v.simple.abc, 123);
2802        assert_eq!(v.simple.xyz, 0);
2803        assert_eq!(v.s, "Hello");
2804    }
2805
2806    #[test]
2807    fn test_subbuilder_serde() {
2808        let v = r#"
2809        s = "hello world"
2810        [fnd]
2811        has_no_default = 1234
2812        "#;
2813        let b: t::SubBuilder = toml::from_str(v).unwrap();
2814        let x = b.build().unwrap();
2815        assert_eq!(x.fnd.has_no_default, 1234);
2816        assert_eq!(x.fnd.has_default, 0);
2817        assert_eq!(x.s, "hello world");
2818    }
2819
2820    #[test]
2821    fn test_magic_nz() {
2822        let mut b = t::Magic::builder();
2823        b.nzu8(123);
2824        b.nzu8_2(1);
2825        let v = b.build().unwrap();
2826        assert_eq!(v.nzu8.get(), 123);
2827        assert_eq!(v.nzu8_2.get(), 1);
2828
2829        let e = t::MagicBuilder::new().nzu8(0).build().unwrap_err();
2830        let ConfigBuildError::Invalid { field, problem } = e else {
2831            panic!("Error not as expected ({e:?})");
2832        };
2833        assert_eq!(field, "nzu8");
2834        assert_eq!(problem, "value not allowed to be zero");
2835
2836        let e = t::MagicBuilder::new().nzu8_2(0).build().unwrap_err();
2837        let ConfigBuildError::Invalid { field, problem } = e else {
2838            panic!("Error not as expected ({e:?})");
2839        };
2840        assert_eq!(field, "nzu8_2");
2841        assert_eq!(problem, "value not allowed to be zero");
2842    }
2843
2844    #[test]
2845    fn test_magic_string() {
2846        let mut b = t::Magic::builder();
2847        b.s("hello"); // <-- note that this is not a String.
2848        let v = b.build().unwrap();
2849        assert_eq!(v.s, "hello");
2850
2851        #[allow(clippy::unnecessary_to_owned)]
2852        b.s("world".to_string());
2853        let v = b.build().unwrap();
2854        assert_eq!(v.s, "world");
2855    }
2856
2857    #[test]
2858    fn test_magic_duration() {
2859        let v = r#"
2860        dur = "1 hour"
2861        "#;
2862        let b: t::MagicBuilder = toml::from_str(v).unwrap();
2863        let x = b.build().unwrap();
2864        assert_eq!(x.dur, std::time::Duration::new(60 * 60, 0));
2865    }
2866
2867    #[test]
2868    #[traced_test]
2869    fn test_cfg_enabled() {
2870        let s = r#"
2871        flower_power = 12
2872        flower_power_err = 14
2873        "#;
2874        let b: t::CfgEnabledBuilder = toml::from_str(s).unwrap();
2875        let v = b.build().unwrap();
2876        assert_eq!(v.flower_power, 12);
2877        assert_eq!(v.flower_power_err, 14);
2878        assert!(!logs_contain("no effect"));
2879    }
2880
2881    #[test]
2882    #[traced_test]
2883    fn test_cfg_disabled() {
2884        let s = r#"
2885        time_travel = "hello world"
2886        "#;
2887        let b: t::CfgDisabledBuilder = toml::from_str(s).unwrap();
2888        let v = b.build().unwrap();
2889        assert_eq!(v.time_travel, 0);
2890        assert!(logs_contain(
2891            "Ignored configuration for 'time_travel'. \
2892            This option has no effect unless the program is built with resublimated thiotimoline"
2893        ));
2894
2895        let s = r#"
2896        time_travel_err = "hello world"
2897        "#;
2898        let b: t::CfgDisabledBuilder = toml::from_str(s).unwrap();
2899        let e = b.build().unwrap_err();
2900        assert_matches!(e, ConfigBuildError::NoCompileTimeSupport { .. });
2901    }
2902
2903    #[test]
2904    fn test_validating() {
2905        let err_notodd = t::CfgValidating::builder().odd(6).build().unwrap_err();
2906        assert_eq!(
2907            err_notodd.to_string(),
2908            "Value of odd was incorrect: Not odd"
2909        );
2910        let err_noteven = t::CfgValidating::builder().even(5).build().unwrap_err();
2911        assert_eq!(
2912            err_noteven.to_string(),
2913            "Value of even was incorrect: Not even"
2914        );
2915        let v = t::CfgValidating::builder().odd(5).even(6).build().unwrap();
2916        assert_eq!(v.odd, 5);
2917        assert_eq!(v.even, 6);
2918    }
2919
2920    #[test]
2921    fn test_generic() {
2922        let mut b = t::CfgGeneric::<String, Vec<u32>>::builder();
2923        b.t("This is a test".to_string());
2924        b.u(vec![1, 2, 3]);
2925        let v = b.build().unwrap();
2926        assert_eq!(v.t, "This is a test");
2927        assert_eq!(&v.u, &[1, 2, 3]);
2928    }
2929
2930    #[test]
2931    fn test_options_setters() {
2932        let mut b = t::OptionsCfg::builder();
2933        // Try with no-option inputs.
2934        b.a(32);
2935        b.s("hello");
2936        b.other((1, 2));
2937        b.nz(12);
2938        let c = b.build().unwrap();
2939        assert_eq!(c.a, Some(32));
2940        assert_eq!(c.b, Some(123));
2941
2942        assert_eq!(c.s, Some("hello".to_string()));
2943        assert_eq!(c.other, Some((1, 2)));
2944        assert_eq!(c.nz, Some(12.try_into().unwrap()));
2945
2946        // Try with option inputs.
2947        b.a(Some(12));
2948        b.b(None);
2949        b.s(Some("world"));
2950        b.other(Some((11, 22)));
2951        b.nz(Some(std::num::NonZeroU8::new(15).unwrap()));
2952        let c = b.build().unwrap();
2953        assert_eq!(c.a, Some(12));
2954        assert_eq!(c.b, None);
2955        assert_eq!(c.s, Some("world".to_string()));
2956        assert_eq!(c.other, Some((11, 22)));
2957        assert_eq!(c.nz, Some(15.try_into().unwrap()));
2958    }
2959
2960    #[test]
2961    fn test_attributes() {
2962        let s1 = "fun_with_numbers = 1982374";
2963        let s2 = "its_fun_to_count = 1982375";
2964        let b1: t::AttribsCfgBuilder = toml::from_str(s1).unwrap();
2965        let b2: t::AttribsCfgBuilder = toml::from_str(s2).unwrap();
2966        // Make sure that derive(PartialEq, Ord) happened.
2967        assert_eq!(b1, b1);
2968        assert_ne!(b1, b2);
2969        assert!(b1 < b2);
2970    }
2971
2972    #[test]
2973    fn test_setter_meta() {
2974        let mut b = t::SettersCfgBuilder::new();
2975        b.a(7);
2976        b.b(5_u8);
2977        assert!(b.c(1_u64 << 40).is_err());
2978        b.c(100_u64).unwrap();
2979        b.d(19);
2980        b.set_the_e(22);
2981        let v = b.build().unwrap();
2982        assert_eq!(v.a, 7 * 2);
2983        assert_eq!(v.b, 5_u32);
2984        assert_eq!(v.c, 100_u32);
2985        assert_eq!(v.d, Some(19));
2986        assert_eq!(v.e, 22);
2987    }
2988
2989    #[test]
2990    fn test_build_fn_rename() {
2991        let mut b = t::RenameBuild::builder();
2992        let v = b.member(6).build_this().unwrap();
2993        assert_eq!(v.member, 6);
2994
2995        let mut b = t::RenameSubBuild::builder();
2996        b.inner().member(5);
2997        let v = b.build().unwrap();
2998        assert_eq!(v.inner.member, 5);
2999    }
3000
3001    #[test]
3002    fn test_custom() {
3003        let mut b = t::FullyCustomBuilder::new();
3004        b.try_the_thing(0xF00B00B512345678);
3005        assert_eq!(b.value, (0xF00B00B5, 0x12345678));
3006        let v = b.build().unwrap();
3007
3008        assert_eq!(v.value, "4027252917 305419896");
3009    }
3010
3011    #[test]
3012    fn test_field_skip() {
3013        let c = t::FieldSkipCfg::builder().build().unwrap();
3014        assert_eq!(c.value, 25);
3015    }
3016
3017    #[test]
3018    fn test_list_builder() {
3019        let mut b = t::ListsCfgBuilder::new();
3020        b.set_integers(vec![12, 6, 3]);
3021        let c = b.build().unwrap();
3022        assert_eq!(&c.integers[..], &[12, 6, 3]);
3023        assert!(c.cats.contains("Moonbeam"));
3024        assert!(c.cats.contains("Damiano"));
3025        assert!(c.simple.is_empty());
3026
3027        let b = t::ListsCfgBuilder::new();
3028        let c = b.build().unwrap();
3029        assert_eq!(&c.integers[..], &[7]);
3030
3031        let mut b = t::ListsCfgBuilder::new();
3032        b.integers().push(22);
3033        b.cats().remove(0);
3034        b.cats().push("Frida".to_string());
3035        b.simple().push(t::SimpleBuilder::new());
3036        let c = b.build().unwrap();
3037        assert_eq!(&c.integers[..], &[7, 22]);
3038        assert!(c.cats.contains("Frida"));
3039        assert!(!c.cats.contains("Damiano"));
3040        assert_eq!(c.simple.len(), 1);
3041    }
3042
3043    #[test]
3044    fn test_list_builder_serde() {
3045        let s1 = r#"
3046            integers = [ 1,2,3 ]
3047        "#;
3048        let s2 = r#"
3049            cats = [ "Prof. Jiggly", "Jorts" ]
3050        "#;
3051        let s3 = r#"
3052            cats = [ "Jenny" ]
3053            [[simple]]
3054            xyz = 9
3055            abc = 12
3056            [[simple]]
3057            xyz = 16
3058        "#;
3059        let b1: t::ListsCfgBuilder = toml::from_str(s1).unwrap();
3060        let b2: t::ListsCfgBuilder = toml::from_str(s2).unwrap();
3061        let b3: t::ListsCfgBuilder = toml::from_str(s3).unwrap();
3062        let c1 = b1.build().unwrap();
3063        let c2 = b2.build().unwrap();
3064        let c3 = b3.build().unwrap();
3065
3066        assert_eq!(&c1.integers[..], &[1, 2, 3]);
3067        assert!(c1.cats.contains("Checkers"));
3068        assert!(!c1.cats.contains("Jorts"));
3069
3070        assert_eq!(&c2.integers[..], &[7]);
3071        assert_eq!(c2.cats.len(), 2);
3072        assert!(c2.cats.contains("Jorts"));
3073        assert!(!c2.cats.contains("Checkers"));
3074
3075        assert_eq!(c3.cats.len(), 1);
3076        assert_eq!(c3.simple.len(), 2);
3077        assert_eq!(c3.simple[0].xyz, 9);
3078        assert_eq!(c3.simple[0].abc, 12);
3079        assert_eq!(c3.simple[1].xyz, 16);
3080        assert_eq!(c3.simple[1].abc, 3);
3081    }
3082
3083    #[test]
3084    fn test_map_builder() {
3085        let mut b = t::MapCfg::builder();
3086        {
3087            let mut sb = t::Simple::builder();
3088            sb.xyz(11);
3089            b.map().insert("Hello".to_string(), sb);
3090        }
3091        {
3092            let mut sb = t::Simple::builder();
3093            sb.abc(33);
3094            b.map().insert("World".to_string(), sb);
3095        }
3096        let c = b.build().unwrap();
3097
3098        assert_eq!(c.map.len(), 3);
3099        assert_eq!(c.map.get("Hello").unwrap().xyz, 11);
3100        assert_eq!(c.map.get("Hello").unwrap().abc, 3);
3101        assert_eq!(c.map.get("World").unwrap().xyz, 0);
3102        assert_eq!(c.map.get("World").unwrap().abc, 33);
3103        assert_eq!(c.map.get("pangolin").unwrap().xyz, 123);
3104        assert_eq!(c.map.get("pangolin").unwrap().abc, 32);
3105    }
3106}