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
114
pub 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
/// [`Builder`](crate::load::Builder),
148
/// [`ConfigBuilder`](crate::load::ConfigBuilder),
149
/// [`ExtendBuilder`](crate::extend_builder::ExtendBuilder)
150
/// and [`Flattenable`](crate::Flattenable).
151
///
152
/// The _configuration struct_ receives a generated "builder" method,
153
/// of type `fn () -> MyConfigBuilder`.
154
/// This function calls the builder's `Default::default()` method.
155
///
156
/// For every ordinary[^ordinary] field of type T in the configuration struct,
157
/// the builder has a **setter method** with the same name,
158
/// of type `fn (&mut self, value: T) -> &mut Self`.
159
/// The setter method sets the corresponding field in `self` to `Some(value)`,
160
/// and returns `self``.
161
///
162
/// For every [sub-builder] field of type SubCfg in the configuration struct,
163
/// the builder has an accessor method with the same name,
164
/// returning `&mut SubCfgBuilder`.
165
///
166
/// The builder has a **build method**, with the name `build`,
167
/// of type `fn (&self) -> Result<MyConfig, ConfigBuildError>`.
168
/// It has the same visibility as the builder struct.
169
/// For every field in the builder of value `Some(x)`,
170
/// it sets the corresponding field in the configuration object to `x`.
171
/// For every field in the builder of value `None`,
172
/// it sets the corresponding field in the configuration object to its default,
173
/// or returns an error,
174
/// depending on the attributes set on the field.
175
/// For every field in the builder with a [sub-builder],
176
/// it invokes the build method on that sub-builder,
177
/// and sets the corresponding field in the configuration object to its result.
178
///
179
/// A new `#[cfg(test)]` module is generated, with tests for the builder behavior.
180
/// This module is called `test_my_config_builder`, with `my_config` replaced with the
181
/// snake-case name of your actual configuration type.
182
///
183
/// [^ordinary]: For the purpose of this documentation,
184
///     a field is "ordinary" if it does not have a [sub-builder].
185
///
186
///
187
/// [sub-builder]: crate::derive::doc_ref_attrs#fmeta:sub_builder
188
pub mod doc_generated_code {}
189

            
190
/// Reference: Attributes supported by the tor_config macro
191
///
192
/// * [Top-level attributes](crate::derive::doc_ref_attrs#tmeta)
193
/// * [Field-level attributes](crate::derive::doc_ref_attrs#fmeta)
194
///
195
/// <div id="tmeta">
196
///
197
/// ## Top-level attributes
198
///
199
/// </div>
200
///
201
/// These attributes can be provided at the top-level, right after
202
/// `derive_deftly(TorConfig)` and before `pub struct FooConfig`.
203
///
204
/// <div id="tmeta:no_serialize_trait">
205
///
206
/// ### `deftly(tor_config(no_serialize_trait))`  — Don't derive Serialize for the builder struct
207
///
208
/// </div>
209
///
210
/// By default, the generated Builder will derive [`serde::Serialize`].
211
/// This attribute suppresses that behavior.
212
///
213
///
214
/// <div id="tmeta:no_deserialize_trait">
215
///
216
/// ### `deftly(tor_config(no_deserialize_trait))` — Don't derive Deserialize for the builder struct
217
///
218
/// </div>
219
///
220
/// By default, the generated Builder will implement [`serde::Deserialize`].
221
/// This attribute suppresses that behavior.
222
///
223
/// Using this option will prevent your type from participating directly
224
/// in the Arti configuration system.
225
///
226
///
227
/// <div id="tmeta:no_flattenable_trait">
228
///
229
/// ### `deftly(tor_config(no_flattenable_trait))`  — Don't derive Flattenable for the builder struct
230
///
231
/// </div>
232
///
233
/// By default, the generated Builder will derive [`Flattenable`](crate::Flattenable).
234
/// This attribute suppresses that behavior.
235
///
236
/// <div id="tmeta:no_extendbuilder_trait">
237
///
238
/// ### `deftly(tor_config(no_extendbuilder_trait))`  — Don't derive ExtendBuilder for the builder struct
239
///
240
/// </div>
241
///
242
/// By default, the generated Builder will derive [`ExtendBuilder`].
243
/// This attribute suppresses that behavior.
244
///
245
/// <div id="tmeta:no_default_trait">
246
///
247
/// ### `deftly(tor_config(no_default_trait))` — Don't derive Default for the config struct
248
///
249
/// </div>
250
///
251
/// By default, the macro will derive [`Default`] on the configuration type
252
/// by creating a default builder, and constructing the configuration type with it.
253
///
254
/// <div id="tmeta:no_test_default">
255
///
256
/// ### `deftly(tor_config(no_test_default))` — Don't test Default for the config struct
257
///
258
/// </div>
259
///
260
/// By default, the macro will implement a test to make sure that its generated `Default`
261
/// implementation produces the same result as deserializing an empty configuration builder,
262
/// and building it.
263
/// This attribute prevents that test from being generated.
264
///
265
/// The test is also omitted when [`no_default_trait`] or [`no_deserialize_trait`] is given.
266
///
267
/// > Note: You must specify this option if the configuration type has any generic parameters.
268
/// > Otherwise, it's best to avoid this attribute.
269
/// >
270
/// > TODO: We should remove this limitation if we can.
271
///
272
/// <div id="tmeta:no_builder_trait">
273
///
274
/// ### `deftly(tor_config(no_builder_trait))` — Don't derive Builder for the builder struct
275
///
276
/// </div>
277
///
278
/// By default, the builder will implement [`tor_config::load::Builder`](crate::load::Builder).
279
/// This attribute suppresses that behavior.
280
///
281
/// > This attribute's name ends with `_trait` to remind the caller that the Builder struct itself
282
/// > will still be implemented.
283
///
284
/// <div id="tmeta:no_buildable_trait">
285
///
286
/// ### `deftly(tor_config(no_buildable_trait))` — Don't derive Buildable for the config struct
287
///
288
/// </div>
289
///
290
/// By default, the configuration struct will implement
291
/// [`tor_config::load::Buildable`](crate::load::Buildable).
292
/// This attribute suppresses that behavior.
293
///
294
/// <div id="tmeta:attr">
295
///
296
/// ### `deftly(tor_config(attr = ".."))` — Apply an attribute to the builder struct
297
///
298
/// </div>
299
///
300
/// This attribute passes its contents through to a new attribute on the derived builder struct.
301
/// For example, you can make the builder derive `PartialOrd` by saying
302
///
303
/// ```no_compile
304
/// #[deftly(tor_config(attr= "derive(PartialOrd)"))]
305
/// ```
306
///
307
/// (See also [`attr`](crate::derive::doc_ref_attrs#fmeta:attr) for fields.)
308
///
309
/// <div id="tmeta:pre_build">
310
///
311
/// ### `deftly(tor_config(pre_build = ".."))` — Call a function before building
312
///
313
/// </div>
314
///
315
/// This attribute makes the generated `build()` method call a validation function on itself
316
/// **before** it builds the configuration.  The function must take `&FooBuilder`
317
/// as an argument, and return `Result<(),ConfigBuildError>`.  If the function
318
/// returns an error, then the build method fails with that error.
319
///
320
/// Example:
321
/// ```
322
/// # use derive_deftly::Deftly;
323
/// # use tor_config::{derive::prelude::*, ConfigBuildError};
324
/// #[derive(Clone,Debug,PartialEq,Deftly)]
325
/// #[derive_deftly(TorConfig)]
326
/// #[deftly(tor_config(pre_build="Self::must_be_odd"))]
327
/// pub struct FavoriteOddNumber {
328
///     #[deftly(tor_config(default="23"))]
329
///     my_favorite: u32,
330
/// }
331
///
332
/// impl FavoriteOddNumberBuilder {
333
///     fn must_be_odd(&self) -> Result<(), ConfigBuildError> {
334
///         let Some(fav) = self.my_favorite else { return Ok(()); };
335
///         if fav % 2 != 1 {
336
///             return Err(ConfigBuildError::Invalid {
337
///                 field: "my_favorite".to_string(),
338
///                 problem: format!("{fav} was not an odd number")
339
///             })
340
///         }
341
///         Ok(())
342
///     }
343
/// }
344
/// ```
345
///
346
/// See also [`post_build`].
347
///
348
/// <div id="tmeta:post_build">
349
///
350
/// ### `deftly(tor_config(post_build = ".."))` — Call a function after building
351
///
352
/// </div>
353
///
354
/// This attribute makes the generated `build()` method call a validation function
355
/// on the configuration **after** it is built.
356
/// The function must take the configuration
357
/// _by value_ as an argument,
358
/// and `Result<`(the configuration)`,ConfigBuildError>`.  If the function
359
/// returns an error, then the build method fails with that error.
360
///
361
/// Example:
362
/// ```
363
/// # use derive_deftly::Deftly;
364
/// # use tor_config::{derive::prelude::*, ConfigBuildError};
365
/// #[derive(Clone,Debug,PartialEq,Deftly)]
366
/// #[derive_deftly(TorConfig)]
367
/// #[deftly(tor_config(post_build="FavoriteEvenNumber::must_be_even"))]
368
/// pub struct FavoriteEvenNumber {
369
///     #[deftly(tor_config(default="86"))]
370
///     my_favorite: u32,
371
/// }
372
///
373
/// impl FavoriteEvenNumber {
374
///     fn must_be_even(self) -> Result<Self, ConfigBuildError> {
375
///         if self.my_favorite % 2 != 0 {
376
///             return Err(ConfigBuildError::Invalid {
377
///                 field: "my_favorite".to_string(),
378
///                 problem: format!("{} was not an even number", self.my_favorite)
379
///             })
380
///         }
381
///         Ok(self)
382
///     }
383
/// }
384
/// ```
385
///
386
/// > Note:
387
/// > You can also use this attribute to clean up or normalize the configuration object.
388
///
389
/// <div id="tmeta:vis">
390
///
391
/// ### `deftly(tor_config(vis = ".."))` — Change visibility of the builder
392
///
393
/// </div>
394
///
395
/// By default, the builder struct is generated with the same visibility as the
396
/// configuration struct.
397
/// You can use this attribute to change its visibility.
398
///
399
///
400
/// <div id="tmeta:build_fn_name">
401
///
402
/// ### `deftly(tor_config(build_fn(name = "..")))` — Change name of the build method
403
///
404
/// </div>
405
///
406
/// By default, the generated build method is called `build`.
407
/// You can use this attribute to change its name.
408
///
409
/// <div id="tmeta:build_fn_vis">
410
///
411
/// ### `deftly(tor_config(build_fn(vis = "..")))` — Change visibility of the build method
412
///
413
/// </div>
414
///
415
/// By default, the `build()` method has the same visibility as the builder struct.
416
/// You can use this attribute to change its visibility.
417
///
418
/// See also:
419
/// * [`deftly(tor_config(vis = ".."))`](crate::derive::doc_ref_attrs#tmeta:vis)
420
///
421
/// <div id="tmeta:build_fn_error">
422
///
423
/// ### `deftly(tor_config(build_fn(error = "..")))` — Change return error type of the build method.
424
///
425
/// </div>
426
///
427
/// By default, the `build()` method returns [`ConfigBuildError`
428
/// on failure.  You can change the error type with this attribute.
429
///
430
/// You will probably need to use this attribute along with [`build_fn(missing_field)`],
431
/// if any of your fields are mandatory.
432
///
433
/// <div id="tmeta:build_fn_missing_field">
434
///
435
/// ### `deftly(tor_config(build_fn(missing_field = "..")))` — Code to generate a missing field error.
436
///
437
/// </div>
438
///
439
/// By default, when a required field is not set, the `build()` method returns
440
/// `Err(E::MissingField { field: "field_name".to_string() })`,
441
/// where `E` is [`ConfigBuildError`] or the type configured with [`build_fn(error)`].
442
/// You can use this attribute to override this behavior.
443
/// Its value should be an expression evaluating to a closure of type
444
/// `FnOnce(&str) -> E`.
445
///
446
/// > For compatibility with `derive_builder`'s version of `build_fn(error)``, you can say:
447
/// > ```no_compile
448
/// > #[build_fn(error="SomeError",
449
/// >            missing_field=
450
/// >     r#"|fname| derive_builder::UninitializedFieldError(
451
/// >                                  fname.to_string()
452
/// >                ).into()"
453
/// > )]
454
/// > ```
455
///
456
/// <div id="fmeta">
457
///
458
/// ## Field-level attributes
459
///
460
/// </div>
461
///
462
/// <div id="fmeta:default_default">
463
///
464
/// ### `deftly(tor_config(default)))` — Use Default::default() when no value is provided
465
///
466
/// </div>
467
///
468
/// When this attribute is provided, if the given field is absent in the builder,
469
/// the `build()` method will set its value to `Default::default()`.
470
///
471
/// For each field, you must specify exactly one of
472
/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
473
///
474
/// <div id="fmeta:default_equals">
475
///
476
/// ### `deftly(tor_config(default = "..")))` — Use a given value when no value is provided
477
///
478
/// </div>
479
///
480
/// When this attribute is provided, if the given field is absent in the builder,
481
/// the `build()` method will set its value to the value of the provided expression.
482
/// The expression may invoke a function, but cannot use `self`.
483
///
484
/// The type of the default must match the type of the field _in the builder_.
485
/// Usually this is the same type as in the built configuration, but for some
486
/// ["magic" types](crate::derive::doc_magic_types), the two can differ.
487
/// (If this is the case, we note the fact with the "magic" type's documentation.)
488
///
489
/// For each field, you must specify exactly one of
490
/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
491
///
492
///
493
/// <div id="fmeta:no_default">
494
///
495
/// ### `deftly(tor_config(no_default))` — Do not provide a default for this field.
496
///
497
/// </div>
498
///
499
/// When this attribute is provided, if the given field is absent in the builder,
500
/// the `build()` method will fail with an error.
501
///
502
/// For each field, you must specify exactly one of
503
/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
504
///
505
/// > When you set this attribute on a field, you must also set the top-level
506
/// > [`no_default_trait`] attribute,
507
/// > since there will not be a meaningful value for the configuration struct.
508
/// >
509
/// > Don't use this option on any config struct that's always present with a multiplicity of one,
510
/// > or else the empty configuration will become invalid.
511
///
512
/// <div id="fmeta:build">
513
///
514
/// ### `deftly(tor_config(build = ".."))` — Call a function to build this field.
515
///
516
/// </div>
517
///
518
/// When this attribute is provided, you can completely override the way that this field is constructed.
519
/// The expression must evaluate to a function taking `&Builder` as an argument,
520
/// and returning the type of the field.
521
///
522
/// For each field, you must specify exactly one of
523
/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
524
///
525
/// > Be careful with this attribute: it can lead to counterintuitive behavior for the end user.
526
///
527
/// Example:
528
///
529
/// ```
530
/// # use derive_deftly::Deftly;
531
/// # use tor_config::{derive::prelude::*, ConfigBuildError};
532
/// #[derive(Clone,Debug,PartialEq,Deftly)]
533
/// #[derive_deftly(TorConfig)]
534
/// pub struct LowercaseExample {
535
///     #[deftly(tor_config(build="Self::build_lc"))]
536
///     lc: String,
537
/// }
538
/// impl LowercaseExampleBuilder {
539
///     fn build_lc(&self) -> String {
540
///         let s = self.lc.as_ref().map(String::as_str).unwrap_or("");
541
///         s.to_lowercase()
542
///     }
543
/// }
544
/// ```
545
///
546
/// <div id="fmeta:try_build">
547
///
548
/// ### `deftly(tor_config(try_build = ".."))` — Call a fallible function to build this field.
549
///
550
/// </div>
551
///
552
/// When this attribute is provided, you can completely override the way that this field is constructed.
553
/// The expression must evaluate to a function taking `&Builder` as an argument,
554
/// and returning `Result<T, ConfigBuildError>`, where `T` is the type of the field.
555
///
556
/// For each field, you must specify exactly one of
557
/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
558
///
559
/// > Be careful with this attribute: it can lead to counterintuitive behavior for the end user.
560
///
561
/// Example:
562
///
563
/// ```
564
/// # use derive_deftly::Deftly;
565
/// # use tor_config::{derive::prelude::*, ConfigBuildError};
566
/// #[derive(Clone,Debug,PartialEq,Deftly)]
567
/// #[derive_deftly(TorConfig)]
568
/// pub struct SqrtExample {
569
///     #[deftly(tor_config(try_build="Self::build_sqrt"))]
570
///     val: f64,
571
/// }
572
/// impl SqrtExampleBuilder {
573
///     fn build_sqrt(&self) -> Result<f64, ConfigBuildError> {
574
///         let v = self.val.unwrap_or(0.0).sqrt();
575
///         if v.is_nan() {
576
///             return Err(ConfigBuildError::Invalid {
577
///                 field: "val".to_string(),
578
///                 problem: format!("{v} was negative")
579
///             })
580
///         }
581
///         Ok(v)
582
///     }
583
/// }
584
/// ```
585
///
586
/// <div id="fmeta:sub_builder">
587
///
588
/// ### `deftly(tor_config(sub_builder))` — Declare a field to contain a nested configuration
589
///
590
/// </div>
591
///
592
/// This attribute is what allows configuration structures to nest.
593
/// When you set this attribute on a field of type `InnerCfg`,
594
/// the builder structure will contain a field of type `InnerCfgBuilder`.
595
/// In order to construct the field, the `build()` method will call
596
/// `InnerCfgBuilder::build()`.
597
///
598
/// For each field, you must specify exactly one of
599
/// [`default`], [`default =`], [`no_default`], [`build`], [`try_build`], or [`sub_builder`].
600
///
601
/// <div id="fmeta:sub_builder_build_fn">
602
///
603
/// ### `deftly(tor_config(sub_builder(build_fn = "...")))` — Call a different function on this sub-builder
604
///
605
/// </div>
606
///
607
/// By default, when [`sub_builder`] is in use,
608
/// the `build()` method is used to generate the inner configuration object.
609
/// This attribute changes the name of the function that is called on the inner builder.
610
///
611
/// <div id="fmeta:no_sub_builder">
612
///
613
/// ### `deftly(tor_config(no_sub_builder))` — Allow a Buildable field _without_ a sub_builder.
614
///
615
/// </div>
616
///
617
/// By default, the `TorConfig` macro inserts code to checks whether each field
618
/// implements [`Buildable`], and causes a compile-time error if any such field
619
/// does not have an explicit [`sub_builder`], [`build`], [`try_build`],
620
/// or [`no_magic`] declaration.
621
/// This attribute overrides this check, and allows you to have a field
622
/// implementing [`Buildable`] without using the `sub_builder` pattern.
623
///
624
///
625
/// <div id="fmeta:list">
626
///
627
/// ### `deftly(tor_config(list))` — Declare a field to contain a nested list of items.
628
///
629
/// </div>
630
///
631
/// This attribute should be used on every field containing a `Vec`,
632
/// `BTreeSet`, `HashSet`, or similar.
633
/// It causes the an appropriate [list-builder](crate::list_builder)
634
/// and set of accessors to be generated.
635
///
636
/// When using this attribute, you must also provide a [`default =`] producing a `Vec`
637
/// of the builder type, and either [`list(element(build))`] or [`list(element(clone))`].
638
///
639
/// Examples:
640
///
641
/// ```no_compile
642
/// // The builder and the constructed list will both contain u32.
643
/// #[deftly(tor_config(list(element(clone)), default = "vec![7]"))]
644
/// integers: Vec<u32>,
645
///
646
/// // The builder will contain a Vec<MyTypeBuilder>;.
647
/// #[deftly(tor_config(list(), (element(build)), default = "vec![]"))]
648
/// objects: Vec<MyType>
649
/// ```
650
///
651
/// <div id="fmeta:list_listtype">
652
///
653
/// ### `deftly(tor_config(list(listtype = ...)))`
654
///
655
/// </div>
656
///
657
/// Usually, the name of the list type alias and builder object  based on the struct and the field name.
658
/// You can provide a different name for the list type alias using this attribute, as in
659
/// `listtype = "TypeName"`.
660
/// The list builder will then be constructed with the list type name, suffixed with `Builder`.
661
///
662
///  <!-- TODO:
663
///    We could support a third option, where we give an explicit closure to build elements.
664
///    We could support an option where the types in the builder vec are listed explicitly.
665
/// -->
666
///
667
/// <div id="fmeta:list_element_build">
668
///
669
/// ### `deftly(tor_config(list(element(build)))` — Declare that the list builder contains sub-builders.
670
///
671
/// </div>
672
///
673
/// Used along with [`list`],
674
/// and indicates the elements of the built list should be constructed via
675
/// builders themselves.  When this attribute is used, the builder structure
676
/// will contain a Vec of builders for the list's elements.
677
///
678
/// If this attribute is given a value, it will be used as the name of the
679
/// "build" method for the list elements.
680
///
681
/// <div id="fmeta:list_element_clone">
682
///
683
/// ### `deftly(tor_config(list(element(clone)))` — Declare that the list builder objects should be cloned directly.
684
///
685
/// </div>
686
///
687
/// Used along with [`list`],
688
/// and indicates the elements of the built list should be cloned directly
689
/// from those in the builder.  When this attribute is used, the builder structure
690
/// will contain a Vec whose elements are the same type as those of the genated list.
691
///
692
/// <div id="fmeta:map">
693
///
694
/// ### `deftly(tor_config(map))` — Use a map-builder pattern.
695
///
696
/// </div>
697
///
698
/// This attribute should be used on every field containing a `HashMap` or `BTreeMap`
699
/// whose key is a `String`, and whose value type is a [`Buildable`].
700
/// It causes the template to generate a map builder type and corresponding accessor functions.
701
/// The map builder behaves like a map from String to the builder type.
702
///
703
/// If a value is provided for this attribute, it is used as the name of the
704
/// map type alias, and suffixed with `Builder` to get the name for the builder type.
705
/// Otherwise, the map type alias is derived from the name of the struct and the field.
706
///
707
/// The [`default =`] attribute is mandatory with this attribute.
708
///
709
/// For more information on the generated code, see
710
/// [`define_map_builder`](crate::define_map_builder).
711
///
712
/// <div id="fmeta:map_maptype">
713
///
714
/// ### `deftly(tor_config(list(maptype = ...)))`
715
///
716
/// </div>
717
///
718
/// Usually, the name of the map type alias and builder object  based on the struct and the field name.
719
/// You can provide a different name for the map type alias using this attribute, as in
720
/// `maptype = "TypeName"`.
721
/// The map builder will then be constructed with the map type name, suffixed with `Builder`.
722
///
723
/// <div id = "fmeta:setter_name">
724
///
725
/// ### `deftly(tor_config(setter(name = "..")))` — Change the name of the setter function
726
///
727
/// </div>
728
///
729
/// By default, the setter function for a field has the same name as its field.
730
/// You can provide a different name in this attribute.
731
///
732
/// <div id="fmeta:setter_vis">
733
///
734
/// ### `deftly(tor_config(setter(vis = "..")))` — Change the visibility of the setter function
735
///
736
/// </div>
737
///
738
/// By default, the setter function for a field has the same visibility as the builder type.
739
/// You can provide a different visibility in this attribute.
740
///
741
/// <div id="fmeta:setter_skip">
742
///
743
/// ### `deftly(tor_config(setter(skip)))` — Do not generate a setter function
744
///
745
/// </div>
746
///
747
/// By default, the builder generates a setter function for every field.
748
/// You can tell it not to do so for a single field by providing this attribute.
749
///
750
/// <div id="fmeta:setter_into">
751
///
752
/// ### `deftly(tor_config(setter(into)))` — Have the setter function accept `impl Into<T>`
753
///
754
/// </div>
755
///
756
/// By default, the setter function expects an argument of type `T`,
757
/// where `T` is the same type of the field.
758
/// When this option is provided, the setter instead expects an argument of type `impl Into<T>`,
759
/// and calls [`Into::into`] on it to set the field.
760
///
761
/// <div id="fmeta:setter_try_into">
762
///
763
/// ### `deftly(tor_config(setter(try_into)))` — Have the setter function accept `impl TryInto<T>`
764
///
765
/// </div>
766
///
767
/// By default, the setter function expects an argument of type `T`,
768
/// where `T` is the same type of the field.
769
/// When this option is provided, the setter instead expects an argument of type `impl TryInto<T>`,
770
/// and calls [`TryInto::try_into`] on it to set the field.
771
/// If `try_into` returns an error, the setter function returns that error.
772
///
773
/// <div id="fmeta:setter_strip_option">
774
///
775
/// ### `deftly(tor_config(setter(strip_option)))` — Have the setter for `Option<T>` accept `T`
776
///
777
/// </div>
778
///
779
/// This attribute requires that the field itself have type `Option<T>` for some `T`.
780
/// Instead of taking `Option<T>` as an argument, the setter now accepts `T`.
781
///
782
/// <!-- TODO -- Do we still want this, given that option magic should take care of it for us,
783
/// and will do a better job? -->
784
///
785
/// <div id="fmeta:field_ty">
786
///
787
/// ### `deftly(tor_config(field(ty = "..")))` — Change the type of a field in the builder
788
///
789
/// </div>
790
///
791
/// By default, for every field of type `T` in the configuration,
792
/// the builder has a field of type `Option<T>`.
793
/// This attribute changes the type of the field in the builder to the provided type.
794
///
795
/// > This attribute has no effect on the generated setter or builder code.
796
/// > Therefore, you will typically need to use it along with
797
/// > the [`setter(skip)`], [`build`], and [`extend_with`] field attributes.
798
///
799
/// Example:
800
///
801
/// ```
802
/// # #![allow(unexpected_cfgs)]
803
/// # use derive_deftly::Deftly;
804
/// # use tor_config::{derive::prelude::*, ConfigBuildError};
805
/// #[derive(Clone,Debug,PartialEq)]
806
/// pub struct ParsedValue {
807
///    // ...
808
/// }
809
/// impl std::str::FromStr for ParsedValue {
810
///     type Err = String;
811
///     fn from_str(s: &str) -> Result<Self, Self::Err> {
812
///         // ...
813
/// #       unimplemented!()
814
///     }
815
/// }
816
///
817
/// #[derive(Clone,Debug,PartialEq,Deftly)]
818
/// #[derive_deftly(TorConfig)]
819
/// pub struct MyConfig {
820
///     #[deftly(tor_config(
821
///         try_build = r#"Self::try_build_behavior"#,
822
///         field(ty = "Option<String>"),
823
///         setter(skip)
824
///     ))]
825
///     behavior: ParsedValue,
826
/// }
827
///
828
/// impl MyConfigBuilder {
829
///     pub fn behavior(&mut self, s: impl AsRef<str>) -> &mut Self {
830
///         self.behavior = Some(s.as_ref().to_string());
831
///         self
832
///     }
833
///     fn try_build_behavior(&self) -> Result<ParsedValue, ConfigBuildError> {
834
///         self.behavior
835
///             .as_ref()
836
///             .map(String::as_str)
837
///             .unwrap_or("Leave the macro processor. Take the cannoli.")
838
///             .parse()
839
///             .map_err(|problem| ConfigBuildError::Invalid {
840
///                 field: "behavior".to_string(),
841
///                 problem,
842
///             })
843
///     }
844
/// }
845
/// ```
846
///
847
/// <div id="fmeta:apply_field_default">
848
///
849
/// ### `deftly(tor_config(apply_field_default = { FIELD_DEFAULT }))` — Apply a default for a specialized builder.
850
///
851
/// </div>
852
///
853
/// By default, the builder's generated [`apply_defaults()`] method
854
/// does nothing for fields with [`build`] or [`try_build`] attributes,
855
/// and recursively calls [`apply_defaults()`]
856
/// for [`sub_builder`] fields.
857
///
858
/// This attribute replaces that behavior for a single field.
859
/// FIELD_DEFAULT must be an expression that expands to a closure taking `&mut Self` as an argument.
860
/// It checks whether the field is set,
861
/// and sets it to a reasonable default otherwise.
862
/// It must return Result<(), E>, where E is some type implementing `Into<ConfigBuildError>`.
863
/// Within `FIELD_DEFAUlT`, `self` refers to the `Builder`.
864
/// The [`build`] or [`try_build`] functions for that field may assume
865
/// that the FIELD_DEFAULT has already been executed.
866
///
867
/// The code in this attribute is invoked after earlier fields are set to their defaults,
868
/// and before later fields are set to theirs.
869
///
870
/// It is an error to use this attribute along with [`default`] or [`no_default`].
871
///
872
/// <div id="fmeta:field_vis">
873
///
874
/// ### `deftly(tor_config(field(vis = "..")))` — Change the visibility of a field in the builder
875
///
876
/// </div>
877
///
878
/// By default, fields in the builder are private.
879
/// This attribute changes their visibility to the one provided.
880
///
881
///
882
/// <div id="fmeta:skip">
883
///
884
/// ### `deftly(tor_config(skip))` — Do not generate the field in the builder
885
///
886
/// </div>
887
///
888
/// If this attribute is present, no field is generated in the builder for this field.
889
/// Implies [`setter(skip)`].  Requires [`build`].
890
///
891
/// <div id="fmeta:attr">
892
///
893
/// ### `deftly(tor_config(attr = "..")))` — Apply an attribute to the field in the builder
894
///
895
/// </div>
896
///
897
/// Any attribute provided here is applied to the declared field in the builder.
898
///
899
/// Example:
900
/// ```no_compile
901
/// #[deftly(tor_config(attr = "allow(deprecated)"))]
902
/// x: SomeDeprecatedType,
903
/// ```
904
///
905
/// See also the [`cfg`](crate::derive::doc_ref_attrs#fmeta:cfg) and [`serde`] attributes.
906
///
907
/// <div id="fmeta:serde">
908
///
909
/// ### `deftly(tor_config(serde = "..")))` — Apply a serde attribute to the field in the builder
910
///
911
/// </div>
912
///
913
/// Any serde attribute provided here is applied to the declared field in the builder.
914
///
915
/// Example:
916
/// ```no_compile
917
/// #[deftly(tor_config(serde = r#"alias = "old_name_of_field" "#))]
918
/// current_name_of_field: String,
919
/// ```
920
///
921
/// Attributes applied with `serde` apply after any specified with
922
/// [`attr`](crate::derive::doc_ref_attrs#fmeta:attr) instead.
923
///
924
/// > This is a convenience attribute; you could just use
925
/// > [`attr`](crate::derive::doc_ref_attrs#fmeta:attr) instead.
926
///
927
/// <!-- TODO: write up a list of recommended serde attributes -->
928
///
929
/// <div id="fmeta:extend_with">
930
///
931
/// ### `deftly(tor_config(extend_with = ""))` — Change the ExtendBuilder behavior for a field.
932
///
933
/// </div>
934
///
935
/// Unless you specify [`no_extendbuilder_trait`], the builder type will
936
/// implement [`ExtendBuilder`],
937
/// and will need a way to replace or extend every field in the builder with
938
/// the value from another builder.
939
/// This attribute lets you override the default behavior for a single field.
940
/// It expects an expression that evaluates to type
941
/// `FnOnce(&mut T, T, `[`ExtendStrategy`]`)`,
942
/// where `T` is the type of the field in the builder.
943
///
944
/// <div id="fmeta:cfg">
945
///
946
/// ### `deftly(tor_config(cfg = "..")))` — Mark a field as conditionally present
947
///
948
/// </div>
949
///
950
/// This option causes a field in the builder to be conditionally present or absent at compile time,
951
/// similar to the ordinary [`cfg`] attribute.
952
/// However, unlike with the ordinary `cfg` attribute,
953
/// if the user provides any configuration values for this field when it is disabled,
954
/// the generated `build()` code will emit a warning via [`tracing`] at runtime telling them
955
/// what feature they would need to turn on.
956
///
957
/// If an error is more appropriate than a warning, additionally use
958
/// [`cfg_reject`].
959
///
960
/// > Note that you _cannot_ use this along with a regular [`cfg`] attribute,
961
/// > since a regular [`cfg`] attribute would suppress the field altogether.
962
/// > Therefore, the field will still be present in the configuration struct
963
/// > even when the `cfg` condition is false.
964
/// > To work around this limitation, it's conventional to arrange for the type of the field
965
/// > to be `()` when the `cfg` condition is false.
966
///
967
/// The `tor_config(cfg_desc)` attribute is mandatory to use along with `cfg`.
968
/// It should contain a short prepositional phrase
969
/// describing how the program needs to be built with
970
/// in order to make this feature present.
971
/// Examples might be "with RPC support" or "for Windows".
972
///
973
///
974
/// Example:
975
/// ```
976
/// # #![allow(unexpected_cfgs)]
977
/// # use derive_deftly::Deftly;
978
/// # use tor_config::{derive::prelude::*, ConfigBuildError};
979
/// #[cfg(feature = "rpc")]
980
/// pub type RpcOptionType = String;
981
///
982
/// #[cfg(not(feature = "rpc"))]
983
/// type RpcOptionType = ();
984
///
985
/// #[derive(Clone,Debug,PartialEq,Deftly)]
986
/// #[derive_deftly(TorConfig)]
987
/// pub struct OnionSoupConfig {
988
///     #[deftly(tor_config(cfg = r#" feature="rpc" "#, cfg_desc = "with RPC support"))]
989
///     #[deftly(tor_config(default))]
990
///     rpc_option: RpcOptionType,
991
/// }
992
/// ```
993
///
994
/// <!-- TODO: This is a warning now, since it is in general only a warning
995
///      to use an option that is not recognized.
996
///      We may want to provide a variant that produces an error instead. -->
997
///
998
/// <div id="fmeta:cfg_reject">
999
///
/// ### `deftly(tor_config(cfg_reject))` — Reject the configuration when a feature is missing.
///
/// </div>
///
/// Used alongside [`tor_config(cfg)`](#fmeta:cfg); see also that attribute's documentation.
///
/// Usually, `tor_config(cfg)` causes a warning if values are provided
/// for a compiled-out configuration option.
/// When this attribute is present, then `tor_config(cfg)` causes an error instead.
///
/// <div id="fmeta:cfg_desc">
///
/// ### `deftly(tor_config(cfg_desc = "..")))` — Description of when a field is present.
///
/// </div>
///
/// Used along with [`tor_config(cfg)`](#fmeta:cfg); see that attribute's documentation.
///
/// <div id="fmeta:no_magic">
///
/// ### `deftly(tor_config(no_magic)))` — Disable magic handling based on a field's type
///
/// </div>
///
/// This attribute disables [type-based magic behavior](crate::derive::doc_magic_types)
/// for the current field.
///
/// [`apply_defaults()`]: crate::load::ConfigBuilder::apply_defaults
/// [`build_fn(error)`]:  crate::derive::doc_ref_attrs#tmeta:build_fn_error
/// [`build_fn(missing_field)`]:  crate::derive::doc_ref_attrs#tmeta:build_fn_missing_field
/// [`build`]: crate::derive::doc_ref_attrs#fmeta:build
/// [`Buildable`]: crate::load::Buildable
/// [`ConfigBuildError`]: crate::ConfigBuildError
/// [`cfg_reject`]: crate::derive::doc_ref_attrs#fmeta:cfg_reject
/// [`default =`]: crate::derive::doc_ref_attrs#fmeta:default_equals
/// [`default`]: crate::derive::doc_ref_attrs#fmeta:default_default
/// [`extend_with`]: crate::derive::doc_ref_attrs#fmeta:extend_with
/// [`ExtendBuilder`]: crate::extend_builder::ExtendBuilder
/// [`ExtendStrategy`]: crate::extend_builder::ExtendStrategy
/// [`list`]: crate::derive::doc_ref_attrs#fmeta:list
/// [`list(listtype)`]: crate::derive::doc_ref_attrs#fmeta:list_listtype
/// [`list(element(build))`]:  crate::derive::doc_ref_attrs#fmeta:list_element_build
/// [`list(element(clone))`]:  crate::derive::doc_ref_attrs#fmeta:list_element_clone
/// [`no_default`]: crate::derive::doc_ref_attrs#fmeta:no_default
/// [`no_default_trait`]: crate::derive::doc_ref_attrs#tmeta:no_default_trait
/// [`no_deserialize_trait`]: crate::derive::doc_ref_attrs#tmeta:no_deserialize_trait
/// [`no_extendbuilder_trait`]: crate::derive::doc_ref_attrs#tmeta:no_extendbuilder_trait
/// [`no_flattenable_trait`]: crate::derive::doc_ref_attrs#tmeta:no_flattenable_trait
/// [`no_magic`]: crate::derive::doc_ref_attrs#fmeta:no_default
/// [`post_build`]: crate::derive::doc_ref_attrs#tmeta:post_build
/// [`serde`]:  crate::derive::doc_ref_attrs#fmeta:serde
/// [`setter(skip)`]: crate::derive::doc_ref_attrs#fmeta:setter_skip
/// [`sub_builder`]: crate::derive::doc_ref_attrs#fmeta:sub_builder
/// [`try_build`]: crate::derive::doc_ref_attrs#fmeta:try_build
pub mod doc_ref_attrs {}
/// Differences from `derive_builder`
///
/// * Not all derive_builder attributes have been cloned: only the ones that we used.
/// * Attributes have been adjusted where possible to be easier to use.
/// * It is not necessary to use `impl_standard_builder!`
/// * The appropriate `serde` attributes are automatically provided on the builder.
/// * Every field must have some default behavior specified, or must have the `no_default` option given.
///   (With `derive_builder`, `no_default` is the default, which can result in confusing test failures.)
/// * Sub-builders are supported.
/// * The `cfg` attribute can be used to warn when the user
///   tries to provide a value for an compiled-out field.
/// * There is (limited) support for generics.
/// * The generated documentation is a little better.
/// * `validate` has been renamed to `pre_build`.
/// * There is `post_build` attribute to replace the pattern where we would rename the build function,
///   make it private, and wrap it.
/// * A top-level `build_fn` does not override the build function on sub-builders.
/// * The list builder and map builder patterns are supported via attributes; you don't need separate
///   macros for them.
/// * Builders automatically derive `ExtendBuilder`, `Flattenable`, and `Builder`.
/// * The configuration type automatically derives `Buildable`.
/// * Visibility is set more reasonably.
/// * For many types, we automatically generate setters or serde code that conforms
///   to our standards.
pub mod doc_differences {}
/// # Types with "magic" handling
///
/// The `derive_deftly(TorConfig)` macro currently has automatic "magic"
/// handling for a few types, and a few other types where it can "magically"
/// detect that you forgot to use a certain option that you probably wanted.
///
/// To override the magic handling for a field, use the [`tor_config(no_magic)`]
/// attribute on that field.
///
/// These types are handled on a best-effort basis by matching their names.
/// If you define a field to have another type that is an alias one of these,
/// the macro won't be able to handle it.
/// To prevent this case, we use [`assert_not_impl`]
/// to insure that you will get a compile-time error if you use one of these
/// types under a different name without specifying [`tor_config(no_magic)`].
///
/// The types with magic handling are:
///
/// ## `String`
///
/// The setter for each [`String`] field takes `impl `[`StringOrStr`] as its argument.
/// This trait is implemented by `String` and `&str`.
///
/// > Earlier we had considered having it take `AsRef<str>`, but this is too general
/// > and can lead to unwanted surprises.
///
/// ## `NonZero<T>`
///
/// The setter for a [`NonZero`]`<T>` field takes
/// `impl `[`PossiblyBoundsChecked`]`<T>` as its argument.
/// This trait is implemented by `T` and by [`NonZero`]`<T>`.
///
/// The default for a `NonZero<T>` should be of type `T`.
/// (Passing the value `0` will cause a test failure.)
///
/// When the build() function is called, it returns an error if the provided
/// value was zero.
///
/// ## `Duration`
///
/// The serde implementations for a [`Duration`](std::time::Duration) field
/// use [`humantime_serde`] to accept and generate human-readable strings.
///
/// ## `Option`
///
/// For an `Option<T>` field, the setter accepts both `T` and `Option<T>`.
/// It does so by requiring that the argument implement traits as follows:
///
/// | Field type           | Setter arg trait                     | Implemented by |
/// | -------------------- | ------------------------------------ | -------------- |
/// | `Option<String>`     | [`OptionStringOrStr`]                | `String, &str, Option<String>, Option<&str>` |
/// | `Option<NonZero<T>>` | [`OptionPossiblyBoundsChecked`]`<T>` | `T, NonZero<T>, Option<T>, Option<NonZero<T>> `|
/// | `Option<T>`          | [`PossiblyOption`]`<T>`              | `T, Option<T>` |
///
/// ## `impl Buildable`
///
/// Any type that implements buildable must either use a the [`sub_builder`] attribute,
/// or opt out of it with [`no_sub_builder`] or [`no_magic`].
///
/// ## `Vec`, `HashSet`, `BTreeSet`
///
/// These types require you to either use the [`list`] attribute,
/// or to opt out of it with [`no_sub_builder`] or [`no_magic`].
///
/// ## `HashMap<String, impl Buildable>`, `BTreeMap<String, impl Buildable>`
///
/// These types require you to either use the [`map`] attribute,
/// or to opt out of it with [`no_sub_builder`] or [`no_magic`].
///
/// ## `Option<Duration>`
///
/// This type will cause a compile-time error unless you set [`no_magic`],
/// since there is not actually a way to
/// set a None in toml (other than omitting the value).
///
/// > (TODO: Doesn't) that logic apply to _all_ Option types?
///
/// ## Container of `Duration`.
///
/// These are currently disallowed unless you provide [`no_magic`],
/// and will cause a compile-time error,
/// since we cannot apply our regular serde magic.
///
/// [`StringOrStr`]: crate::setter_traits::StringOrStr
/// [`OptionStringOrStr`]: crate::setter_traits::OptionStringOrStr
/// [`PossiblyBoundsChecked`]: crate::setter_traits::PossiblyBoundsChecked
/// [`OptionPossiblyBoundsChecked`]: crate::setter_traits::OptionPossiblyBoundsChecked
/// [`PossiblyOption`]: crate::setter_traits::PossiblyOption
/// [`NonZero`]: std::num::NonZero
/// [`tor_config(no_magic)`]: crate::derive::doc_ref_attrs#fmeta:no_magic
/// [`list`]: crate::derive::doc_ref_attrs#fmeta:list
/// [`map`]: crate::derive::doc_ref_attrs#fmeta:map
/// [`sub_builder`]: crate::derive::doc_ref_attrs#fmeta:sub_builder
/// [`no_sub_builder`]: crate::derive::doc_ref_attrs#fmeta:no_sub_builder
/// [`no_magic`]: crate::derive::doc_ref_attrs#fmeta:no_magic
pub mod doc_magic_types {}
// TODO:
// - Can I replace cfg() with a single FeatureNotSupported type, or a family of such types?
//   (See #2298.)
// - derive-deftly#109 would let us have better syntax for tmeta:attr, fmeta:attr, and fmeta:serde.
// - We must decide before merging whether we actually _want_ to always accept T
//   for setters on `NonZero<T>`.  There are some places in our code where we do this now:
//   so if we were to stop doing so, we'd be breaking backward compat in the `arti` crate.
//   But that doesn't  mean we need to continue to do so everywhere.
//   (See #2296)
use derive_deftly::define_derive_deftly;
/// Values used by the tor_config derive_deftly template.
#[doc(hidden)]
pub mod exports {
    pub use super::{
        ShouldBeCaughtAsSerdeSpecialCase, ShouldBeCaughtAsSpecialCase, ShouldNotBeUsed,
        ShouldUseListBuilder, ShouldUseMapBuilder, assert_not_impl, bld_magic_check_type,
        bld_magic_cvt, bld_magic_setter_arg_type, bld_magic_setter_cvt, bld_magic_setter_docs,
        bld_magic_type, list_element, normalize_and_invoke, strip_option,
    };
    pub use crate::flatten::derive_deftly_template_Flattenable;
    pub use crate::{
        ConfigBuildError, define_list_builder_accessors, define_list_builder_helper,
        define_map_builder,
        extend_builder::{ExtendBuilder, ExtendStrategy},
        impl_standard_builder,
        load::Buildable as BuildableTrait,
        load::Builder as BuilderTrait,
        load::ConfigBuilder,
    };
    pub use derive_deftly::Deftly;
    pub use figment;
    pub use humantime_serde;
    pub use serde::{Deserialize, Deserializer, Serialize, Serializer};
    pub use serde_value;
    pub use std::{
        clone::Clone,
        convert::{AsRef, Into, TryInto},
        default::Default,
        fmt::Debug,
        option::Option,
        result::Result,
    };
    pub use tracing;
    pub use void;
}
/// Module to import in order to use the tor_config template.
pub mod prelude {
    pub use super::derive_deftly_template_TorConfig;
}
/// Helper to implement `strip_option`: Takes a single argument whose type is an Option<T>,
/// and yields T.
#[doc(hidden)]
#[macro_export]
macro_rules! strip_option {
    { $($($(::)? std::)? option::)? Option $(::)? < $t:ty >  } => { $t };
    { $t:ty } => { compile_error!{"'strip_option' only works on a type that is an Option<X>"} }
}
pub use strip_option;
/// Helper: Takes a @command name, a {type}, and a list of arguments.
/// Determines which macro corresponds to the type,
/// and invokes that macro with arguments: @command {type} args.
///
/// The macros corresponding to types are [`string_typemagic`] for `String`,
/// [`nonzero_typemagic`] for `NonZero*`,
/// and [`no_typemagic`] for everything else.
///
/// Recognized @commands are:
///  - `@build_type {ty}` - The type that should be used as `T` for the builder field's `Option<T>`.
///  - `@setter_arg_type {ty}` - The type that the setter should take as an argument.
///  - `@setter_cvt {ty} {e}`- Code to run inside the setter to convert {e} into a `@build_type {ty}`
///  - `@build_field {ty} {e} {name}` - Code to convert `@build_type {ty}` into {ty}.  Uses the
///    field name `{fname}` to generate errors.
///  - `@check_type {ty}` - Make sure that it is not a bug for this type to have reached this position.
///    Give a compile-time error if it is.
///  - `@setter_docs {ty}` - A string to add to the setter documentation.
#[doc(hidden)]
#[macro_export]
macro_rules! normalize_and_invoke {
    // HEY YOU! DON'T ADD OR REMOVE ANY TYPES WITHOUT READING THE COMMENT BELOW!
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $( $($(::)? std::)? num:: )? NonZero $(::)? < $t:ty > >
    } $($args:tt)*}                                                                   => { $crate::derive::opt_nz_typemagic!    { @$cmd {$t} $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $( $($(::)? std::)? num:: )? NonZeroU8 >
    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u8} $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $( $($(::)? std::)? num:: )? NonZeroU16 >
    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u16} $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $( $($(::)? std::)? num:: )? NonZeroU32 >
    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u32} $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $( $($(::)? std::)? num:: )? NonZeroU64 >
    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u64} $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $( $($(::)? std::)? num:: )? NonZeroU128 >
    } $($args:tt)*}                                                                    => { $crate::derive::opt_nz_typemagic!   { @$cmd {u128} $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $( $($(::)? std::)? string:: )? String >
    } $($args:tt)*}                                                                    => { $crate::derive::opt_str_typemagic!  { @$cmd $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? option:: )? Option $(::)?
        < $t:ty >
    } $($args:tt)*}                                                                    =>   {$crate::derive::opt_other_typemagic!{@$cmd {$t}  $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZero $(::)? < $t:ty >}  $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {$t}   $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU8}                 $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u8}   $($args)* } };
    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU16}                $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u16}  $($args)*  } };
    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU32}                $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u32}  $($args)*  } };
    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU64}                $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u64}  $($args)*  } };
    { @$cmd:ident {$( $($(::)? std::)? num:: )? NonZeroU128}               $($args:tt)*} => { $crate::derive::nonzero_typemagic!{ @$cmd {u128} $($args)*  } };
    { @$cmd:ident {$( $($(::)? std::)? string:: )? String}                 $($args:tt)*} => { $crate::derive::string_typemagic! { @$cmd $($args)* } };
    { @$cmd:ident {$($t:tt)+}                                              $($args:tt)*} => { $crate::derive::no_typemagic!     { @$cmd {$($t)+} $($args)* } };
    // HEY YOU! DON'T ADD OR REMOVE TYPES WITHOUT READING THIS COMMENT!
    //
    // 1. You need to make sure that every type handled by this macro implements
    //    `ShouldBeCaughtAsASpecialCase`.
    // 2. Make sure to document the behavior in `doc_magic_types` above.
}
pub use normalize_and_invoke;
/// Implement type magic for types that aren't at all special.
///
/// See [`normalize_and_invoke`] for details.
#[doc(hidden)]
#[macro_export]
macro_rules! no_typemagic {
    { @build_type {$t:ty} } => { $t };
    { @setter_arg_type {$t:ty}} => { $t };
    { @setter_cvt {$t:ty} {$e:expr} } => { $e };
    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => { $e.clone() };
    { @check_type {$t:ty} } => {
        $crate::derive::exports::assert_not_impl!(
            [type_was_not_correctly_identified_as_a_TorConfig_special_case]
            $t: $crate::derive::ShouldBeCaughtAsSpecialCase
        );
    };
    { @setter_docs {$t:ty} } => { "" };
}
pub use no_typemagic;
/// Implement type magic for `String`.
///
/// See [`normalize_and_invoke`] for details.
#[doc(hidden)]
#[macro_export]
macro_rules! string_typemagic {
    { @build_type } => { String };
    { @setter_arg_type } => { impl $crate::setter_traits::StringOrStr };
    { @setter_cvt {$e:expr} } => { $e.to_string() };
    { @build_field {$e:expr} {$fname:expr}} => { $e.clone() };
    { @check_type } => {};
    { @setter_docs } => {
        "\nFor convenience, this function accepts both `String` and `&str`.\n"
    };
}
pub use string_typemagic;
/// Implement type magic for `NonZero*`.
///
/// See [`normalize_and_invoke`] for details.
#[doc(hidden)]
#[macro_export]
macro_rules! nonzero_typemagic {
    { @build_type {$t:ty} } => { $t };
    { @setter_arg_type {$t:ty} } => { impl $crate::setter_traits::PossiblyBoundsChecked<$t> };
    { @setter_cvt {$t:ty} {$e:expr} } => { $e.to_unchecked() };
    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => {
        $e.try_into().map_err(|_| $crate::ConfigBuildError::Invalid {
8
                field: $fname.to_string(),
8
                problem: "value not allowed to be zero".to_string()
8
        })?
    };
    { @check_type {$t:ty} } => {};
    { @setter_docs {$t:ty} } => {
        concat!("\nFor convenience, this function accepts both `",
            stringify!($t), "` and `NonZero<", stringify!($t), ">`.\n" )
    };
}
pub use nonzero_typemagic;
/// Implement type magic for `Option<NonZero*>`
///
/// See [`normalize_and_invoke`] for details.
#[doc(hidden)]
#[macro_export]
macro_rules! opt_nz_typemagic {
    { @build_type {$t:ty} } => { Option<$t> };
    { @setter_arg_type {$t:ty} } => { impl $crate::setter_traits::OptionPossiblyBoundsChecked<$t> };
    { @setter_cvt {$t:ty} {$e:expr} } => { $e.to_option_unchecked() };
    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => {
        match $e {
            Some(v) => match v.try_into() {
                Ok(n) => Some(n),
                Err(_) => return Err( $crate::ConfigBuildError::Invalid {
                    field: $fname.to_string(),
                    problem: "value not allowed to be zero".to_string()
                })
            }
            None => None,
        }
    };
    { @check_type {$t:ty} } => {};
    { @setter_docs {$t:ty} } => {
        concat!("\nFor convenience, this function accepts `",
            stringify!($t), "`, `NonZero<", stringify!($t), ">`, `Option<", stringify!($t),
            ">`, and `Option<NonZero<", stringify!($t), ">`.\n")
    };
}
pub use opt_nz_typemagic;
/// Implement type magic for `Option<String>`
///
/// See [`normalize_and_invoke`] for details.
#[doc(hidden)]
#[macro_export]
macro_rules! opt_str_typemagic {
    { @build_type } => { Option<String> };
    { @setter_arg_type  } => { impl $crate::setter_traits::OptionStringOrStr };
    { @setter_cvt {$e:expr} } => { $e.to_option_string() };
    { @build_field {$e:expr} {$fname:expr}} => { $e.clone() };
    { @check_type } => {};
    { @setter_docs } => {
        "\nFor convenience, this function accepts `String`, `&str`, \
                 `Option<String>`, and `Option<&str>`.\n"
    };
}
pub use opt_str_typemagic;
/// Implement type magic for `Option<T>`
///
/// See [`normalize_and_invoke`] for details.
#[doc(hidden)]
#[macro_export]
macro_rules! opt_other_typemagic {
    { @build_type {$t:ty} } => { Option<$t> };
    { @setter_arg_type {$t:ty} } => { impl $crate::setter_traits::PossiblyOption<$t> };
    { @setter_cvt {$t:ty} {$e:expr} } => { $e.to_option() };
    { @build_field {$t:ty} {$e:expr} {$fname:expr}} => { $e.clone() };
    { @check_type {$t:ty} } => {
        $crate::derive::exports::assert_not_impl!(
            [type_was_not_correctly_identified_as_a_TorConfig_Option_special_case]
            $t: $crate::derive::ShouldBeCaughtAsSpecialCase
        );
    };
    { @setter_docs {$t:ty} } => {
        concat!("\nFor convenience, this function accepts both `", stringify!($t),
              "` and `Option<", stringify!($T), ">`\n.")
    };
}
pub use opt_other_typemagic;
/// Helper: Expand to the type `T` that a field of type `{$t}`
/// should have in the builder struct's Option<T>.
#[doc(hidden)]
#[macro_export]
macro_rules! bld_magic_type {
    { $($t:tt)+ } => { $crate::derive::normalize_and_invoke!{ @build_type {$($t)+} } };
}
pub use bld_magic_type;
/// Helper: Expand to the type `T` that a setter should take for a field of type `{$t}`
#[doc(hidden)]
#[macro_export]
macro_rules! bld_magic_setter_arg_type {
    { $($t:tt)+ } => { $crate::derive::normalize_and_invoke!{ @setter_arg_type {$($t)+} } };
}
pub use bld_magic_setter_arg_type;
/// Helper: Expand to the code that should be used to convert `{e}` into the type
/// `bld_magic_type!{$t}`.
#[doc(hidden)]
#[macro_export]
macro_rules! bld_magic_setter_cvt {
    { {$e:expr} {$($t:tt)+}} => { $crate::derive::normalize_and_invoke!{ @setter_cvt {$($t)+} {$e} } };
}
pub use bld_magic_setter_cvt;
/// Helper: Expand to the code that should be used to convert `{e}` from type
/// `bld_magic_type!{$t}` into $t.  Uses the field name `{fname} to generate errors.
#[doc(hidden)]
#[macro_export]
macro_rules! bld_magic_cvt {
    { {$e:expr} {$fname:expr} {$($t:tt)+}} => { $crate::derive::normalize_and_invoke!{ @build_field {$($t)+} {$e} {$fname} } };
}
pub use bld_magic_cvt;
/// Helper: Expand to the code that will make sure that the type `{t}`
/// can be handled correctly by these macros.
/// The code will cause a compile-time error on failure.
#[doc(hidden)]
#[macro_export]
macro_rules! bld_magic_check_type {
    { {$($t:tt)+}} => { $crate::derive::normalize_and_invoke!{ @check_type {$($t)+} } };
}
pub use bld_magic_check_type;
/// Helper: Expand to a documentation string describing any type-based magic for
/// the setter for this type.
#[doc(hidden)]
#[macro_export]
macro_rules! bld_magic_setter_docs {
    { {$($t:tt)+} } => { $crate::derive::normalize_and_invoke!{ @setter_docs {$($t)+} } };
}
pub use bld_magic_setter_docs;
/// Helper for sealing traits below.
mod seal {
    /// Used to seal ShouldBeCaughtAsSpecialCase.
    pub trait SealSpecialCase {}
    /// Used to seal ShouldBeCaughtAsSerdeSpecialCase.
    pub trait SealSerdeSpecialCase {}
    /// Used to seal ShouldUseListBuilder.
    pub trait SealUseListBuilder {}
    /// Used to seal ShouldUseMapBuilder
    pub trait SealUseMapBuilder {}
    /// Used to seal ShouldNotBeUsed
    pub trait SealShouldNotBeUsed {}
}
/// Implement each `trait` for every comma-separated type in `types`, with an empty body.
macro_rules! impl_many {
    { $($ty:ty),+ : $trait:ty } =>
    {
        $( impl $trait for $ty {} )+
    };
    { $($ty:ty),+ : $trait:ty , $($more:tt)+} =>
    {
        impl_many!{ $($ty),+ : $trait }
        impl_many!{ $($ty),+ : $($more)+ }
    };
}
/// A trait implemented by all the types that `normalize_and_invoke` does anything magic for.
///
/// We use this trait to detect cases that normalize_and_invoke should have handled, but didn't--
/// probably because the type was an alias.
pub trait ShouldBeCaughtAsSpecialCase: seal::SealSpecialCase {}
impl_many! {
    std::num::NonZero<u8>, std::num::NonZero<u16>,
    std::num::NonZero<u32>, std::num::NonZero<u64>,
    std::num::NonZero<u128>, String
    : seal::SealSpecialCase, ShouldBeCaughtAsSpecialCase
}
impl<T> seal::SealSpecialCase for Option<T> {}
impl<T> ShouldBeCaughtAsSpecialCase for Option<T> {}
/// A trait implemented by all the types that should receive automatic serde magic handling.
///
/// We use this trait to detect cases that the tor_config derive macro should have caught,
/// but didn't-- probably because the type was an alias.
pub trait ShouldBeCaughtAsSerdeSpecialCase: seal::SealSerdeSpecialCase {}
impl_many! {
    std::time::Duration
    : seal::SealSerdeSpecialCase, ShouldBeCaughtAsSerdeSpecialCase
}
/// A trait implemented by the types for which we should recommend the use of a
/// list builder.
pub trait ShouldUseListBuilder: seal::SealUseListBuilder {
    /// The element type of this list.
    type Element;
}
impl<T> seal::SealUseListBuilder for Vec<T> {}
impl<T> seal::SealUseListBuilder for std::collections::HashSet<T> {}
impl<T> seal::SealUseListBuilder for std::collections::BTreeSet<T> {}
impl<T> ShouldUseListBuilder for Vec<T> {
    type Element = T;
}
impl<T> ShouldUseListBuilder for std::collections::HashSet<T> {
    type Element = T;
}
impl<T> ShouldUseListBuilder for std::collections::BTreeSet<T> {
    type Element = T;
}
/// Helper to implement `list_builder`: find the element type for a list-like object.
#[doc(hidden)]
#[macro_export]
macro_rules! list_element {
    { $($($(::)? std::)? vec::)? Vec $(::)? < $t:ty > } => { $t };
    { $($($(::)? std::)? collections::)? HashSet $(::)? < $t:ty > } => { $t };
    { $($($(::)? std::)? collections::)? BTreeSet $(::)? < $t:ty > } => { $t };
    { $t:ty } => { compile_error!{"'list_builder' only works on Vec, HashSet, or BTreeSet."} }
}
pub use list_element;
/// A trait implemented by the types for which we should recommend the use of a
/// map builder.
pub trait ShouldUseMapBuilder: seal::SealUseMapBuilder {
    /// The corresponding type to use inside this map builder
    type BuilderMap;
}
impl<T> seal::SealUseMapBuilder for std::collections::HashMap<String, T> where
    T: crate::load::Buildable
{
}
impl<T> seal::SealUseMapBuilder for std::collections::BTreeMap<String, T> where
    T: crate::load::Buildable
{
}
impl<T> ShouldUseMapBuilder for std::collections::HashMap<String, T>
where
    T: crate::load::Buildable,
{
    type BuilderMap = std::collections::HashMap<String, T::Builder>;
}
impl<T> ShouldUseMapBuilder for std::collections::BTreeMap<String, T>
where
    T: crate::load::Buildable,
{
    type BuilderMap = std::collections::BTreeMap<String, T::Builder>;
}
/// A trait implemented by types that we shouldn't actually use as fields in a configuration.
pub trait ShouldNotBeUsed: seal::SealShouldNotBeUsed {}
impl_many! {
    // This is unsuitable, since there is no actual way to set a value to `none` in Toml.
    // Use Duration with a default instead.
    Option<std::time::Duration>,
    Option<Option<std::time::Duration>>
    : seal::SealShouldNotBeUsed, ShouldNotBeUsed
}
/// Declare that types shouldn't be used in a collection (because they would want magic
/// serde handling, but that isn't implemented).
macro_rules! should_not_be_used_in_collection {
    { $($t:ty),* $(,)?} => {
        $(
        impl_many!{
            Vec<$t>,
            std::collections::BTreeSet<$t>,
            std::collections::HashSet<$t>
            : seal::SealShouldNotBeUsed, ShouldNotBeUsed
        }
        impl<K> seal::SealShouldNotBeUsed for std::collections::HashMap<K,$t> {}
        impl<K> ShouldNotBeUsed for std::collections::HashMap<K,$t> {}
        impl<K> seal::SealShouldNotBeUsed for std::collections::BTreeMap<K,$t> {}
        impl<K> ShouldNotBeUsed for std::collections::BTreeMap<K,$t> {}
        )*
    }
}
should_not_be_used_in_collection! {
    std::time::Duration,
}
#[deprecated = "use as tor_basic_utils::assert_not_impl instead"]
pub use tor_basic_utils::assert_not_impl;
define_derive_deftly! {
    /// Define a builder type for a given type, with settings appropriate to participate in the Arti
    /// build system.
    ///
    /// See [module documentation](crate::derive) for more information and usage instructions.
    export TorConfig beta_deftly, for struct:
    #[allow(unused_imports)]
    use $crate::derive::exports as $<__tor_config_exports__ $tname>;
    // -------------------
    // Common definitions and aliases.
    // Location of exports for this macro.
    ${define E {$crate::derive::exports}}
    // Location of exports for this macro, as a string.
    //
    // TODO $crate: I would prefer to use ${concat $crate "::derive::exports"} instead,
    // but that won't work, since $crate gets expanded at the wrong time.
    // See
    // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/132#note_3288325
    // for discussion of the workaround used here.
    ${define EX ${concat "__tor_config_exports__" $tname}}
    // Current field name as string.
    ${define FNAME { ${concat $fname} }}
    // Name of the build method.
    ${define BLD_NAME {
        ${tmeta(tor_config(build_fn(name))) as ident, default build}
    } }
    // -------------------
    // Definitions and aliases for defining the builder struct.
    // True if the field type appears to be `std::time::Duration`
    //
    // (This can't be done with the regular "magic" macro system,
    // since it needs to be used in expansions that produce a field attribute.
    // macro_rules! macros can't appear in a field-attribute position.
    // There _are_ workarounds here, which I'll consider while
    // reafactoring the magic system.)
    ${defcond F_IS_DURATION
        any(approx_equal({$ftype}, {Duration}),
            approx_equal({$ftype}, {time::Duration}),
            approx_equal({$ftype}, {std::time::Duration}),
            approx_equal({$ftype}, {::std::time::Duration}))
    }
    // True if the field type should receive magic handling with serde.
    ${defcond F_SERDE_MAGIC any(F_IS_DURATION)}
    // Condition: True unless Serialize and Deserialize have both been disabled.
    ${defcond SERDE
        not(all(tmeta(tor_config(no_serialize_trait)),
                tmeta(tor_config(no_deserialize_trait))))
    }
    // Expands to any attributes that should be applied to the current builder field
    // based on magic type behavior.
    ${define BLD_MAGIC_ATTRIBUTES
        ${if fmeta(tor_config(no_magic)) {
        } else if SERDE {
            ${select1
            F_IS_DURATION {
                ${if SERDE {
                    #[serde(with = ${concat $EX "::humantime_serde::option"})]
                }}
            }
            // HEY YOU! DON'T ADD ANY MORE MAGIC SERDE TYPES HERE WITHOUT READING THIS!
            // 1. You need to add the condition for your type to `F_SERDE_MAGIC`,
            //    and you need to make sure that your type implements
            //    `ShouldBeCaughtAsSerdeSpecialCase`.
            // 2. You need to document the behavior in `doc_magic_types`.
            else {
                ${if F_SERDE_MAGIC {
                    ${error "Type should receive magic handling with serde, but we failed to apply any."}
                }}
                // No magic needed.
            }}
        }}
    }
    // For each list_builder field: the names of the list builder
    // type to define.
    ${define F_LST_BLD_TYPE {  $<
        ${fmeta(tor_config(list(listtype))) as ty,
            default ${paste $tname ${upper_camel_case $fname} List}
     } Builder>} }
    // For each map_builder field: the names of the map builder
    // type to define.
    ${define F_MAP_TYPE { ${paste // See derive_deftly#138 for this $paste.
        ${fmeta(tor_config(map(maptype))) as ty,
            default ${paste $tname ${upper_camel_case $fname} Map}}
    }}}
6
    ${define F_MAP_BLD_TYPE { $< $F_MAP_TYPE Builder > }}
    // Expands to $ftype of the current builder field, as modified by type magic.
    // (Most everybody should use $BLD_FTYPE instead.)
    ${define BLD_MAGIC_FTYPE {
        ${if fmeta(tor_config(no_magic)) {
            $ftype
        } else {
            $E::bld_magic_type!($ftype)
        }}
    }}
    // Expands to the type of the field within the builder.
    ${define BLD_FTYPE {
        ${if fmeta(tor_config(field(ty))) {
            ${fmeta(tor_config(field(ty))) as ty}
        } else if fmeta(tor_config(sub_builder)) {
            $< $ftype Builder >
        } else if fmeta(tor_config(list)) {
            $F_LST_BLD_TYPE
        } else if fmeta(tor_config(map)) {
            $F_MAP_BLD_TYPE
        } else {
            $E::Option<$BLD_MAGIC_FTYPE>
        }}
    }}
    // Expands to the error type for this builder.
    ${define ERR
       ${tmeta(tor_config(build_fn(error))) as ty, default {$E::ConfigBuildError}}}
    // If the current field is conditionally present, expands to the `cfg`
    // attribute we should apply to it.
    ${define IF_CFG {
        // TODO: Infelicity: It would be nice if this didn't have to take "cfg" as a string.
        // See https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
        ${if fmeta(tor_config(cfg)) {
            #[cfg( ${fmeta(tor_config(cfg)) as token_stream} )]
        }}
    }}
    // Visibility for the builder type.
    //
    // TODO: d-d has no ` .. as vis`, which is what really want.
    // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/137
    // (also, below)
    ${define BLD_TVIS
        ${tmeta(tor_config(vis)) as token_stream, default $tvis}
    }
    // Visibility for the current field in the builder type.
    ${define BLD_FVIS
        ${fmeta(tor_config(field(vis))) as token_stream, default {} }
    }
    // True if we want to derive Flattenable for the builder type
    ${defcond DD_FLATTENABLE_ON_BUILDER
        all(not(tmeta(tor_config(no_deserialize_trait))),
            not(tmeta(tor_config(no_flattenable_trait)))
        )}
    // Expands to the visibility for the current setter/accessor,
    // and for any types that we generate for it to expose.
    ${define SETTER_VIS {
        ${fmeta(tor_config(setter(vis))) as token_stream, default $BLD_TVIS}
    }}
    // -------------------
    // Invoke checks for our type-handling macros.
    $(
        ${if fmeta(tor_config(no_magic)) {
            // If we're disabling the magic, this is fine.
        } else {
            // Make sure that, for every other, it gets matched by the right case of
            // normalize_and_invoke.
            //
            // (We do this because our type checking in normalize_and_invoke is imperfect,
            // and can't detect aliases.)
            $E::bld_magic_check_type!({$ftype});
        }}
        ${if all(not(F_SERDE_MAGIC), not(fmeta(tor_config(no_magic))) ) {
            // If we don't get special handling from serde, make sure that the type doesn't actually
            // need it.
            //
            // (We do this because our type checking in F_IS_DURATION is imperfect and can't
            // detect)
            $E::assert_not_impl!(
                [type_was_not_correctly_identified_as_a_TorConfig_serde_special_case]
                $ftype: $E::ShouldBeCaughtAsSerdeSpecialCase
            );
        }}
    )
    // -------------------
    // Check for types that don't make sense in a configuration.
    $(
        ${when not(fmeta(tor_config(no_magic)))}
        $E::assert_not_impl!(
            [field_type_not_suitable_for_configuration]
            $ftype: $E::ShouldNotBeUsed
        );
    )
    // -------------------
    // Check for missing invocations of sub_builder, list, or map.
    $(
        ${when not(any(
            fmeta(tor_config(sub_builder)),
            fmeta(tor_config(no_sub_builder)),
            fmeta(tor_config(no_magic)),
            fmeta(tor_config(build)),
            fmeta(tor_config(try_build)),
        ))}
        $E::assert_not_impl!(
            [missing_sub_builder_declaration_for_Buildable_field]
            $ftype: $E::BuildableTrait
        );
    )
    $(
        ${when not(any(
            fmeta(tor_config(no_sub_builder)),
            fmeta(tor_config(no_magic)),
            fmeta(tor_config(list)),
        ))}
        $E::assert_not_impl!(
            [field_should_use_list_builder_or_opt_out]
            $ftype: $E::ShouldUseListBuilder
        );
    )
    $(
        ${when not(any(
            fmeta(tor_config(no_sub_builder)),
            fmeta(tor_config(no_magic)),
            fmeta(tor_config(map)),
        ))}
        $E::assert_not_impl!(
            [field_should_use_map_builder_or_opt_out]
            $ftype: $E::ShouldUseMapBuilder
        );
    )
    // -------------------
    // Define the builder type.
    #[doc = ${concat "A builder to create an instance of [`" $tname "`].\n"}]
    #[derive($E::Default, $E::Clone, $E::Debug, $E::Deftly)]
    ${if not(tmeta(tor_config(no_deserialize_trait))) {
        #[derive($E::Deserialize)]
    }}
    ${if not(tmeta(tor_config(no_serialize_trait))) {
        #[derive($E::Serialize)]
    }}
    ${if DD_FLATTENABLE_ON_BUILDER {
        #[derive_deftly($E::Flattenable)]
    }}
    // TODO: drop requirement this be a string.
    // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
    ${ if tmeta(tor_config(attr)) {
        #[ ${tmeta(tor_config(attr)) as token_stream} ]
    }}
    #[allow(dead_code)]
    $BLD_TVIS struct $<$tname Builder><$tdefgens>
    where $twheres
    {
        $(
            ${when not(fmeta(tor_config(skip)))}
            // TODO: drop requirement this be a string.
            // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
            ${if fmeta(tor_config(attr)) {
                #[${fmeta(tor_config(attr)) as token_stream}]
            }}
            ${if SERDE {
                #[serde(default)]
            }}
            // TODO: drop requirement this be a string.
            // https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/issues/56
            ${ if fmeta(tor_config(serde)) {
                #[ serde( ${fmeta(tor_config(serde)) as token_stream} )]
            }}
            #[doc = ${concat "In-progress value for " $fname ".\n\n"
                             "See [`" $tname "." $fname "`]("$tname "#structfield." $fname ")"}]
            $BLD_MAGIC_ATTRIBUTES
            $IF_CFG
            $BLD_FVIS ${fdefine $fname} $BLD_FTYPE,
            ${if all(SERDE, fmeta(tor_config(cfg))) {
                /// Placeholder to catch attempts to use this field when
                /// disabled by configuration.
                ///
                /// (This uses `serde_value` to make sure that Deserialize+Serialize is not
                /// needlessly lossy.)
                #[cfg(not(${fmeta(tor_config(cfg)) as token_stream} ))]
                #[serde(default)]
                ${fdefine $fname} $E::Option<$E::serde_value::Value>,
            }}
        )
    }
    // -------------------
    // Define any list-builder or map-builder types.
    ${define BUILD_LIST_ELEMENT {
        ${select1
        fmeta(tor_config(list(element(build)))) {
158
            |v| v.${fmeta(tor_config(list(element(build)))) as ident, default build}()
        }
        fmeta(tor_config(list(element(clone)))) {
            |v| Ok(v.clone())
        }
        else {
            ${error "With list, must specify list(element(clone)) or list(element(build))"}
        }}
    }}
    ${define APPLY_DEFAULTS_LIST_ELEMENT {
        ${select1
        fmeta(tor_config(list(element(build)))) {
            |v| $E::ConfigBuilder::apply_defaults(v)
        }
        fmeta(tor_config(list(element(clone)))) {
            |_v| Ok::<_ , $E::ConfigBuildError>(())
        }
        else {
            ${error "With list, must specify list(element(clone)) or list(element(build))"}
        }}
    }}
    ${define BLD_LIST_ELT_TYPE {
        ${select1
        fmeta(tor_config(list(element(build)))) {
            // TODO: Find a way to get the argument types for the setters be
            // nicer.
            //
            // It would be cool if we could paste "Builder" on to the end of the
            // output of $E::list_element, but that doesn't work.
            <<$ftype as $E::ShouldUseListBuilder>::Element as $E::BuildableTrait>::Builder
        }
        fmeta(tor_config(list(element(clone)))) {
            // We could use ShouldUseListBuilder::Element here, but the declared
            // argument types for the setters would be a bit nasty.
            $E::list_element!{ $ftype }
        }
        else {
            ${error "With list, must specify list(element(clone)) or list(element(build))"}
        }}
    }}
    $(
        ${when fmeta(tor_config(list))}
        $E::define_list_builder_helper! {
            #[doc = ${concat "Builder for the `" $ftype "` type.\n\n"}]
            $SETTER_VIS struct $F_LST_BLD_TYPE {
                $BLD_FVIS $fname: [
                    $BLD_LIST_ELT_TYPE
                ],
            }
            built: $ftype = $fname;
            default = ${fmeta(tor_config(default)) as expr};
            item_build: $BUILD_LIST_ELEMENT;
            item_apply_defaults: $APPLY_DEFAULTS_LIST_ELEMENT;
        }
    )
    $(
        ${when fmeta(tor_config(map))}
        $E::define_map_builder! {
            #[doc = ${concat "Builder for the `" $F_MAP_TYPE "` type.\n\n"}]
            $SETTER_VIS struct $F_MAP_BLD_TYPE =>
            $BLD_FVIS type $F_MAP_TYPE = {
                map: $ftype,
                builder_map: <$ftype as $E::ShouldUseMapBuilder>::BuilderMap,
            }
            defaults: ${fmeta(tor_config(default)) as expr};
        }
    )
    // -------------------
    // Definitions to implement setter/accessor methods.
    // Expands to the name of the setter/accessor for the current field.
    ${define SETTER_NAME { ${fmeta(tor_config(setter(name))) as ident, default $fname} }}
    // Expands the declared type that the setter should take as its argument.
    ${define SETTER_INPUT_TYPE {
        ${select1
            fmeta(tor_config(setter(into))) {
                impl $E::Into<$ftype>
            }
            fmeta(tor_config(setter(try_into))) {
                SetterArg
            }
            fmeta(tor_config(setter(strip_option))) {
                $E::strip_option!{$ftype}
            }
            else {
                ${if fmeta(tor_config(no_magic)) {
                    $ftype
                } else {
                    $E::bld_magic_setter_arg_type!{$ftype}
                }
            }}
        }}}
    // Expands to the generics (if any) that the setter should take.
    ${define SETTER_GENS {
        ${if fmeta(tor_config(setter(try_into))) {
            <SetterArg : $E::TryInto<$ftype>>
        } else {
        }}
    }}
    // Expands to the expression that the setter should return.
    ${define SETTER_RETURN {
        ${if fmeta(tor_config(setter(try_into))) {
            Ok(self)
        } else {
            self
        }}
    }}
    // Expands to the declared return type of the setter.
    ${define SETTER_RETURN_TYPE {
        ${if fmeta(tor_config(setter(try_into))) {
4
            $E::Result<&mut Self, SetterArg::Error>
        } else {
3338696
            &mut Self
14
        }}
14
    }}
14

            
14
    // Expands to a string that we should add to the documentation
14
    // to explain the default value of the current field.
14
    ${define DFLT_DOC {
14
        ${select1
14
            fmeta(tor_config(sub_builder)) { "" }
14
            // TODO: perhaps we should document _something_ about build and try_build,
14
            // even though we can't document any default.
14
            fmeta(tor_config(build)) { "" }
14
            fmeta(tor_config(try_build)) { "" }
14
            fmeta(tor_config(default)) {
14
                ${concat "If no value is provided for `" $fname "`, "
14
                  "[`build`](Self::build) will use `"
14
                  ${fmeta(default) as str, default "Default::default()"}
14
                  "`."
14
            }}
14
            fmeta(tor_config(no_default)) {
14
                ${concat "If no value is provided for `" $fname "`, "
14
                  "[`build`](Self::build) will fail with an error."}
14
            }
14
            else {
14
                ${error "Every field must have default, no_default, try_build, build, or sub_builder."}
14
            }
14
        }
14
    }}
14

            
14
    // Expands to a definition of the setter function for the current field.
14
    ${define SET_FN {
14
        #[doc = ${concat "Provide a value for `" $fname "`.\n\n"}]
14
        #[doc = $DFLT_DOC]
14
        ${if not(fmeta(tor_config(no_magic))) {
14
            #[doc = $E::bld_magic_setter_docs!{ { $ftype } } ]
14
        }}
14
        #[doc = ${concat "\n\n## " $fname "\n\n" }]
14
        ${fattrs doc}
14
        $IF_CFG
14
        $SETTER_VIS fn $SETTER_NAME $SETTER_GENS (&mut self, val: $SETTER_INPUT_TYPE) -> $SETTER_RETURN_TYPE {
            ${select1
                fmeta(tor_config(setter(into))) {
                    self.$fname = Some(val.into());
                }
                fmeta(tor_config(setter(try_into))) {
                    self.$fname = Some(val.try_into()?);
                }
                fmeta(tor_config(setter(strip_option))) {
                    self.$fname = Some(Some(val));
                }
                else {
                    ${if fmeta(tor_config(no_magic)) {
                        self.$fname = Some(val);
                    } else {
                        self.$fname = Some($E::bld_magic_setter_cvt!({val} {$ftype}));
                    }}
                }
            }
            $SETTER_RETURN
        }
    }}
    ${define F_SUB_BUILDER_TYPE
        ${if fmeta(tor_config(map)) {
            $F_MAP_BLD_TYPE
        } else {
1859
            $<$ftype Builder>
2
        }}
2
    }
2

            
2
    // Expands to a declaration for the sub-builder accessor function for the current field.
2
    ${define ACCESS_SUBBUILDER_FN {
2

            
2
        #[doc = ${concat "Return a mutable reference to the inner builder for `" $fname "`.\n\n"
2
                  "## " $fname "\n\n"
2
                }]
2
        ${fattrs doc}
2
        $IF_CFG
2
        $SETTER_VIS fn $fname(&mut self) -> &mut $F_SUB_BUILDER_TYPE {
            &mut self.$fname
        }
    }}
    // -------------------
    // Define the setter/accessors methods.
    #[allow(dead_code)]
    impl<$tgens> $<$ttype Builder>
    where $twheres {
        $(
            ${if any(fmeta(tor_config(setter(skip))),
                     fmeta(tor_config(skip)),
                     fmeta(tor_config(list))) {
                // generate nothing.
            } else if any(fmeta(tor_config(sub_builder)),
                          fmeta(tor_config(map))) {
                $ACCESS_SUBBUILDER_FN
            } else {
                $SET_FN
            }}
        )
    }
    $(
        ${when fmeta(tor_config(list))}
        $E::define_list_builder_accessors!{
            struct $<$tname Builder> {
                $SETTER_VIS $fname : [
                    $BLD_LIST_ELT_TYPE
                 ],
            }
        }
    )
    // -------------------
    // Definitions and helpers for the build method.
    // Expands to the name of the function to use to build the sub-builder for the current field.
    ${define SUB_BUILDER_BUILD_FN {
        ${fmeta(tor_config(sub_builder(build_fn))) as path, default build}
    }}
    // Expands to an expression of type Option<$ftype> for a field named "value",
    // taking type-based magic into account.
    ${define BLD_MAGIC_CVT {
        ${if fmeta(tor_config(no_magic)) {
            value.clone()
        } else {
            $E::bld_magic_cvt!({value} {${concat $fname}} {$ftype})
        }}
    }}
    // Expands to the closure we run on a missing field to get the error type.
    ${define BLD_MISSING_FIELD {
        ${tmeta(tor_config(missing_field)) as expr, default {
            |name_of_missing_field: &str| $ERR::MissingField { field: name_of_missing_field.into() }
        }}
    }}
    // Expands to an expression for building the current field,
    // and returning an appropriate error if there was a problem.
    ${define BUILD_FIELD {
         ${select1
            any(fmeta(tor_config(sub_builder)),
                fmeta(tor_config(list)),
                fmeta(tor_config(map))) {
20
                self.$fname.$SUB_BUILDER_BUILD_FN().map_err(|e| e.within($FNAME))?
            }
            all(fmeta(tor_config(default)), not(any(fmeta(tor_config(list)),
                                                    fmeta(tor_config(map))))) {
                {
                    let value = self.$fname.clone().unwrap_or_else(
66631
                        || ${fmeta(tor_config(default)) as expr, default {Default::default()}});
                    $BLD_MAGIC_CVT
                }
            }
            fmeta(tor_config(build)) {
                (${fmeta(tor_config(build)) as expr})(self)
            }
            fmeta(tor_config(try_build)) {
                (${fmeta(tor_config(try_build)) as expr})(self)?
            }
            fmeta(tor_config(no_default)) {
                {
                    let value = self.$fname.clone().ok_or_else(
4
                        || { ($BLD_MISSING_FIELD)(stringify!($fname)) })?;
                    $BLD_MAGIC_CVT
                }
            }
            else {
                ${error "Every field must have default, no_default, try_build, build, or sub_builder."}
            }
        }
    }}
    // Expands to the visibility of the build method.
    ${define BLD_FN_VIS {
        ${tmeta(tor_config(build_fn(vis))) as token_stream, default $BLD_TVIS}
    }}
    // -------------------
    // Define the build method and the new() method.
    #[allow(dead_code)]
    impl<$tgens> $<$ttype Builder>
    where $twheres {
        /// Return a new builder object.
34
        $BLD_TVIS fn new() -> Self {
            Self::default()
        }
        #[doc = ${concat
            "Try to construct a new [`" $tname "`] from the fields set in this builder.\n\n"
            "Return an error if any required field is missing, or is set to something invalid.\n"
        }]
1826278
        $BLD_FN_VIS fn $BLD_NAME(&self) -> $E::Result<$ttype, $ERR> {
            // Call pre_build as appropriate.
            ${if tmeta(tor_config(pre_build)) {
                let () = ${tmeta(tor_config(pre_build)) as path}(self)?;
            }}
            // Warn if any configured-out option was provided.
            $(
                ${if fmeta(tor_config(cfg)) {
                    #[cfg(not( ${fmeta(tor_config(cfg)) as token_stream} ))]
                    if self.$fname.is_some() {
                        ${if fmeta(tor_config(cfg_reject)) {
                            return Err($E::ConfigBuildError::NoCompileTimeSupport {
                                field: stringify!($fname).to_string(),
                                problem: ${concat "The program was not built "
                                    ${fmeta(tor_config(cfg_desc)) as str}
                                }.to_string()
                            });
                        } else {
                            $E::tracing::warn!(
                                ${concat "Ignored configuration for '" $fname
                                "'. This option has no effect unless the program is built "
                                ${fmeta(tor_config(cfg_desc)) as str} "'"}
                            )
                        }}
                    }
                }}
            )
            // TODO: It would be good to call apply_defaults here,
            // but if we make  change, we will hit extra redundancy:
            // If build() calls apply_defaults(),
            // our own apply_defaults will recurse to our sub-builders,
            // and then the build() functions of our sub-builders will
            // also invoke their apply_defaults methods.
            // Construct the configuration struct.
            let result = $tname {
                $(
                    $IF_CFG
                    $fname: $BUILD_FIELD ,
                    ${if fmeta(tor_config(cfg)) {
                        #[cfg(not( ${fmeta(tor_config(cfg)) as token_stream} ))]
                        $fname: $E::Default::default(),
                    }}
                )
            };
            // Call the post_build function to transform the result.
            ${if tmeta(tor_config(post_build)) {
                let result = ${tmeta(tor_config(post_build)) as path}(result)?;
            }}
            Ok(result)
        }
    }
    // -------------------
    // Implement ConfigBuilder
    impl<$tgens> $E::ConfigBuilder for $<$ttype Builder>
    where $twheres {
        fn apply_defaults(&mut self) -> Result<(), $E::ConfigBuildError> {
            #[allow(unused_imports)]
            use $E::ConfigBuilder as _;
            $(
                ${IF_CFG}
                ${if fmeta(tor_config(apply_field_default)) {
                    ${if any(fmeta(tor_config(default)),
                             fmeta(tor_config(no_default))) {
                        ${error "Cannot use apply_field_default with default or no_default."}
                    }}
                    {
                        let closure = ${fmeta(tor_config(apply_field_default)) as expr};
                        (closure)(self)?;
                    }
                } else if any(fmeta(tor_config(sub_builder)),
                        fmeta(tor_config(list)),
                        fmeta(tor_config(map))) {
                    self.$fname.apply_defaults()?;
                } else if fmeta(tor_config(default)) {
                    let _ = self.$fname.get_or_insert_with(
                        || ${fmeta(tor_config(default)) as expr, default {Default::default()}});
                }}
            )
            Ok(())
        }
    }
    // -------------------
    // Add a builder() method to the configuration type.
    //
    // NOTE: This and some other code below is redundant with impl_standard_builder!().
    // I'm not using that trait here because complying with its input format is rather
    // baroque, and it's easier just to do it ourselves.
    impl<$tgens> $ttype
    where $twheres {
        #[doc = ${concat "Return a new [`" $tname " Builder`] to construct an instance of this type."}]
        #[allow(dead_code)]
1668621
        $tvis fn builder() -> $<$ttype Builder> {
            $<$ttype Builder>::default()
        }
    }
    // -------------------
    // Implement `$crate::load::Builder` for the Builder type.
    ${if not(tmeta(tor_config(no_builder_trait))) {
        impl<$tgens> $E::BuilderTrait for $<$ttype Builder>
        where $twheres {
            type Built = $ttype;
            // We're writing it this way in case Builder::build() returns
            // a different Error type.
            #[allow(clippy::needless_question_mark)]
2788
            fn build(&self) -> $E::Result<$ttype, $E::ConfigBuildError> {
                Ok($<$ttype Builder>::$BLD_NAME(self)?)
            }
        }
    }}
    // -------------------
    // Implement $crate::extend_builder::ExtendBuiler on the builder type.
    // (We can't use derive_deftly_template_ExtendBuilder, since that macro was
    // written to apply to the configuration type and modify its builder. (!))
    ${if not(tmeta(tor_config(no_extendbuilder_trait))) {
        impl<$tgens> $E::ExtendBuilder for $<$ttype Builder>
        where $twheres {
            #[allow(unused_variables)]
50
            fn extend_from(&mut self, other: Self, strategy: $E::ExtendStrategy) {
                ${for fields {
                    ${when not(fmeta(tor_config(skip)))}
                    ${if fmeta(tor_config(cfg)) {
                        // For conditionally present features, it doesn't matter what we put
                        // in the field, so long as we make it set whenever _either_ config is set.
                        #[cfg(not( ${fmeta(tor_config(cfg)) as token_stream} ))]
                        if other.$fname.is_some() {
                            self.$fname = other.$fname;
                        }
                        #[cfg( ${fmeta(tor_config(cfg)) as token_stream} )]
                    }}
                    {
                        ${if fmeta(tor_config(extend_with)) {
                            ${fmeta(tor_config(extend_with)) as expr}(&mut self.$fname, other.$fname, strategy);
                        } else if fmeta(tor_config(extend_with_replace)) {
                            if let Some(other_val) = other.$fname {
                                self.$fname = Some(other_val);
                            }
                        } else if any(fmeta(tor_config(sub_builder)),
                                fmeta(tor_config(list)),
                                fmeta(tor_config(map))) {
                            $E::ExtendBuilder::extend_from(&mut self.$fname, other.$fname, strategy);
                        } else {
                            if let Some(other_val) = other.$fname {
                                self.$fname = Some(other_val);
                            }
                        }}
                    }
                }}
            }
        }
    }}
    // -------------------
    // Implement `$crate::load::Buildable` for the configuration type.
    ${if not(tmeta(tor_config(no_buildable_trait))) {
        impl<$tgens> $E::BuildableTrait for $ttype
        where $twheres {
            type Builder = $<$ttype Builder>;
            fn builder() -> $<$ttype Builder> {
                $<$ttype Builder>::default()
            }
        }
    }}
    // -------------------
    // Implement `Default` for the configuration type, in terms of the Builder.
    // (Unless the no_default_trait attribute was present.)
    ${if not(tmeta(tor_config(no_default_trait))) {
        impl<$tgens> $E::Default for $ttype
        where $twheres {
12735
            fn default() -> Self {
                // It's okay to use unwrap; one of the test cases verifies it.
                $<$ttype Builder>::default().$BLD_NAME().unwrap()
            }
        }
    }}
    // ------------------
    // Test module for the builder.
    ${if not(any(
        tmeta(tor_config(no_default_trait)),
        tmeta(tor_config(no_deserialize_trait)),
        tmeta(tor_config(no_test_default))))
        {
        #[cfg(test)]
        mod $<test_ ${snake_case $tname} _builder> {
            #[test]
            // TODO: doesn't work on generics. Do we care?  If so, how should we fix?
110
            fn test_impl_default() {
                let def = super::$ttype::default();
                let empty_config = $E::figment::Figment::new();
                let builder: super::$<$ttype Builder> = empty_config.extract().unwrap();
                let from_empty = builder.$BLD_NAME().unwrap();
                assert_eq!(def, from_empty);
            }
        }
    }}
}
pub use derive_deftly_template_TorConfig;
#[cfg(test)]
mod test {
    // @@ begin test lint list maintained by maint/add_warning @@
    #![allow(clippy::bool_assert_comparison)]
    #![allow(clippy::clone_on_copy)]
    #![allow(clippy::dbg_macro)]
    #![allow(clippy::mixed_attributes_style)]
    #![allow(clippy::print_stderr)]
    #![allow(clippy::print_stdout)]
    #![allow(clippy::single_char_pattern)]
    #![allow(clippy::unwrap_used)]
    #![allow(clippy::unchecked_time_subtraction)]
    #![allow(clippy::useless_vec)]
    #![allow(clippy::needless_pass_by_value)]
    #![allow(clippy::string_slice)] // See arti#2571
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
    use crate::ConfigBuildError;
    use assert_matches::assert_matches;
    use tracing_test::traced_test;
    /// Separate module to put config structs and their builders in, so that they aren't
    /// able to pick up anything we don't deliberately import.
    mod t {
        use std::{
            collections::{BTreeSet, HashMap},
            num::{NonZero, NonZeroU8},
            time::Duration,
        };
        // use crate::derive::prelude::*;
        use derive_deftly::Deftly;
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct Simple {
            #[deftly(tor_config(default))]
            pub(super) xyz: u32,
            #[deftly(tor_config(default = "3"))]
            pub(super) abc: u16,
            #[deftly(tor_config(build = "|_self| 6 * 7"))]
            pub(super) forty_two: u16,
            #[deftly(tor_config(
                try_build = "|_self| Ok::<_,crate::ConfigBuildError>(6 * 7 + 1)"
            ))]
            pub(super) forty_three: u16,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        #[deftly(tor_config(no_default_trait))]
        pub(super) struct FieldNoDefault {
            #[deftly(tor_config(default))]
            pub(super) has_default: u32,
            #[deftly(tor_config(no_default))]
            pub(super) has_no_default: u32,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        #[deftly(tor_config(no_default_trait))]
        pub(super) struct Sub {
            #[deftly(tor_config(sub_builder))]
            pub(super) simple: Simple,
            #[deftly(tor_config(sub_builder))]
            pub(super) fnd: FieldNoDefault,
            #[deftly(tor_config(default))]
            pub(super) s: String,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct Magic {
            #[deftly(tor_config(default = "7"))]
            pub(super) nzu8: NonZeroU8,
            #[deftly(tor_config(default = "123"))]
            pub(super) nzu8_2: NonZero<u8>,
            #[deftly(tor_config(default))]
            pub(super) dur: Duration,
            #[deftly(tor_config(default))]
            pub(super) s: String,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct CfgEnabled {
            #[deftly(tor_config(
                default,
                cfg = "true",
                cfg_desc = "with eschaton immenentization"
            ))]
            pub(super) flower_power: u32,
            #[deftly(tor_config(
                default,
                cfg = "true",
                cfg_reject,
                cfg_desc = "with eschaton immenentization"
            ))]
            pub(super) flower_power_err: u32,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct CfgDisabled {
            #[deftly(tor_config(
                default,
                cfg = "false",
                cfg_desc = "with resublimated thiotimoline"
            ))]
            pub(super) time_travel: u32,
            #[deftly(tor_config(
                default,
                cfg = "false",
                cfg_reject,
                cfg_desc = "with resublimated thiotimoline"
            ))]
            pub(super) time_travel_err: u32,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        #[deftly(tor_config(
            pre_build = "Self::check_odd",
            post_build = "CfgValidating::check_even"
        ))]
        pub(super) struct CfgValidating {
            #[deftly(tor_config(default = "1"))]
            pub(super) odd: u32,
            #[deftly(tor_config(default))]
            pub(super) even: u32,
        }
        impl CfgValidatingBuilder {
            fn check_odd(&self) -> Result<(), crate::ConfigBuildError> {
                if let Some(v) = self.odd {
                    if v & 1 != 1 {
                        return Err(crate::ConfigBuildError::Invalid {
                            field: "odd".to_string(),
                            problem: "Not odd".to_string(),
                        });
                    }
                }
                Ok(())
            }
        }
        impl CfgValidating {
            fn check_even(self) -> Result<Self, crate::ConfigBuildError> {
                if self.even & 1 != 0 {
                    return Err(crate::ConfigBuildError::Invalid {
                        field: "even".to_string(),
                        problem: "Not even".to_string(),
                    });
                }
                Ok(self)
            }
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        #[deftly(tor_config(
            no_serialize_trait,
            no_test_default,
            no_extendbuilder_trait,
            no_flattenable_trait
        ))]
        pub(super) struct CfgGeneric<T, U>
        where
            T: Clone + std::fmt::Debug + PartialEq + Default,
            U: Clone + std::fmt::Debug + PartialEq + Default,
        {
            #[deftly(tor_config(default, no_magic))]
            pub(super) t: T,
            #[deftly(tor_config(default, no_magic))]
            pub(super) u: U,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct OptionsCfg {
            #[deftly(tor_config(default))]
            pub(super) a: Option<u32>,
            #[deftly(tor_config(default = "Some(123)"))]
            pub(super) b: Option<u32>,
            #[deftly(tor_config(default = "Some(42)"))]
            pub(super) nz: Option<NonZeroU8>,
            #[deftly(tor_config(default))]
            pub(super) s: Option<String>,
            #[deftly(tor_config(default))]
            pub(super) other: Option<(u32, u32)>,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        #[deftly(tor_config(attr = "derive(Eq,Ord,PartialOrd,PartialEq)"))]
        pub(super) struct AttribsCfg {
            #[deftly(tor_config(default))]
            #[deftly(tor_config(attr = r#"serde(alias = "fun_with_numbers")"#))]
            #[deftly(tor_config(serde = r#"alias = "its_fun_to_count""#))]
            pub(super) a: u32,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct SettersCfg {
            #[deftly(tor_config(default, setter(skip)))]
            pub(super) a: u32,
            #[deftly(tor_config(default, setter(into)))]
            pub(super) b: u32,
            #[deftly(tor_config(default, setter(try_into)))]
            pub(super) c: u32,
            #[deftly(tor_config(default, setter(strip_option)))]
            pub(super) d: Option<u32>,
            #[deftly(tor_config(default, setter(name = "set_the_e")))]
            pub(super) e: u32,
        }
        impl SettersCfgBuilder {
            // Custom setter.
            pub(super) fn a(&mut self, val: u32) {
                self.a = Some(val * 2);
            }
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        #[deftly(tor_config(no_serialize_trait, no_deserialize_trait))]
        pub(super) struct NoSerdeCfg {
            #[deftly(tor_config(default))]
            pub(super) ip: u128,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        #[deftly(tor_config(build_fn(name = "build_this")))]
        pub(super) struct RenameBuild {
            #[deftly(tor_config(default))]
            pub(super) member: u16,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct RenameSubBuild {
            #[deftly(tor_config(sub_builder(build_fn = "build_this")))]
            pub(super) inner: RenameBuild,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct FullyCustom {
            #[deftly(tor_config(
                setter(skip),
                field(ty = "(u32, u32)", vis = "pub(super)"),
                build = r#"|this: &Self| format!("{} {}", this.value.0, this.value.1)"#,
                extend_with = r#"|mine: &mut (u32,u32), theirs: (u32,u32), _| *mine = theirs"#,
            ))]
            pub(super) value: String,
        }
        impl FullyCustomBuilder {
            pub(super) fn try_the_thing(&mut self, x: u64) {
                self.value = ((x >> 32) as u32, x as u32);
            }
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct FieldSkipCfg {
            #[deftly(tor_config(skip, build = r#"|_this: &Self| 25"#))]
            pub(super) value: u32,
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct ListsCfg {
            #[deftly(tor_config(list(element(clone)), default = "vec![7]"))]
            pub(super) integers: Vec<u32>,
            #[deftly(tor_config(
                list(listtype = "StringSet", element(clone)),
                default = "cats()"
            ))]
            pub(super) cats: BTreeSet<String>,
            #[deftly(tor_config(list(element(build)), default = "vec![]"))]
            pub(super) simple: Vec<Simple>,
        }
        fn cats() -> Vec<String> {
            ["Damiano", "Moonbeam", "Checkers", "Enigma"]
                .iter()
                .map(|s| s.to_string())
                .collect()
        }
        #[derive(Deftly, Clone, Debug, PartialEq)]
        #[derive_deftly(TorConfig)]
        pub(super) struct MapCfg {
            #[deftly(tor_config(map, default = "default_map()"))]
            pub(super) map: HashMap<String, Simple>,
        }
        fn default_map() -> HashMap<String, SimpleBuilder> {
            let mut b = SimpleBuilder::new();
            b.abc(32);
            b.xyz(123);
            let mut m = HashMap::new();
            m.insert("pangolin".to_string(), b);
            m
        }
    }
    #[test]
    fn test_simple_defaults() {
        let b = t::SimpleBuilder::new();
        let x = b.build().unwrap();
        assert_eq!(x.xyz, 0);
        assert_eq!(x.abc, 3);
        assert_eq!(x.forty_two, 42);
        assert_eq!(x.forty_three, 43);
    }
    #[test]
    fn test_simple_setters() {
        let mut b = t::SimpleBuilder::new();
        let x = b.abc(7).xyz(77).forty_two(777).build().unwrap();
        assert_eq!(x.xyz, 77);
        assert_eq!(x.abc, 7);
        assert_eq!(x.forty_two, 42);
        assert_eq!(x.forty_three, 43);
    }
    #[test]
    fn test_simple_serde() {
        let v = r#"
        xyz = 7
        "#;
        let b: t::SimpleBuilder = toml::from_str(v).unwrap();
        let x = b.build().unwrap();
        assert_eq!(x.xyz, 7);
        assert_eq!(x.abc, 3);
        assert_eq!(x.forty_two, 42);
        assert_eq!(x.forty_three, 43);
    }
    #[test]
    fn test_field_no_default() {
        let e = t::FieldNoDefaultBuilder::new().build().unwrap_err();
        assert_matches!(
            e,
            ConfigBuildError::MissingField {
                field
            } if field == "has_no_default"
        );
        let v = t::FieldNoDefaultBuilder::new()
            .has_no_default(42)
            .build()
            .unwrap();
        assert_eq!(v.has_default, 0);
        assert_eq!(v.has_no_default, 42);
    }
    #[test]
    fn test_subbuilder() {
        let e = t::SubBuilder::new().build().unwrap_err();
        assert_matches!(
            e,
            ConfigBuildError::MissingField {
                field
            } if field == "fnd.has_no_default"
        );
        let mut b = t::SubBuilder::new();
        b.fnd().has_no_default(5).has_default(66);
        b.simple().abc(123);
        b.s("Hello");
        let v = b.build().unwrap();
        assert_eq!(v.fnd.has_no_default, 5);
        assert_eq!(v.fnd.has_default, 66);
        assert_eq!(v.simple.abc, 123);
        assert_eq!(v.simple.xyz, 0);
        assert_eq!(v.s, "Hello");
    }
    #[test]
    fn test_subbuilder_serde() {
        let v = r#"
        s = "hello world"
        [fnd]
        has_no_default = 1234
        "#;
        let b: t::SubBuilder = toml::from_str(v).unwrap();
        let x = b.build().unwrap();
        assert_eq!(x.fnd.has_no_default, 1234);
        assert_eq!(x.fnd.has_default, 0);
        assert_eq!(x.s, "hello world");
    }
    #[test]
    fn test_magic_nz() {
        let mut b = t::Magic::builder();
        b.nzu8(123);
        b.nzu8_2(1);
        let v = b.build().unwrap();
        assert_eq!(v.nzu8.get(), 123);
        assert_eq!(v.nzu8_2.get(), 1);
        let e = t::MagicBuilder::new().nzu8(0).build().unwrap_err();
        let ConfigBuildError::Invalid { field, problem } = e else {
            panic!("Error not as expected ({e:?})");
        };
        assert_eq!(field, "nzu8");
        assert_eq!(problem, "value not allowed to be zero");
        let e = t::MagicBuilder::new().nzu8_2(0).build().unwrap_err();
        let ConfigBuildError::Invalid { field, problem } = e else {
            panic!("Error not as expected ({e:?})");
        };
        assert_eq!(field, "nzu8_2");
        assert_eq!(problem, "value not allowed to be zero");
    }
    #[test]
    fn test_magic_string() {
        let mut b = t::Magic::builder();
        b.s("hello"); // <-- note that this is not a String.
        let v = b.build().unwrap();
        assert_eq!(v.s, "hello");
        #[allow(clippy::unnecessary_to_owned)]
        b.s("world".to_string());
        let v = b.build().unwrap();
        assert_eq!(v.s, "world");
    }
    #[test]
    fn test_magic_duration() {
        let v = r#"
        dur = "1 hour"
        "#;
        let b: t::MagicBuilder = toml::from_str(v).unwrap();
        let x = b.build().unwrap();
        assert_eq!(x.dur, std::time::Duration::new(60 * 60, 0));
    }
    #[test]
    #[traced_test]
    fn test_cfg_enabled() {
        let s = r#"
        flower_power = 12
        flower_power_err = 14
        "#;
        let b: t::CfgEnabledBuilder = toml::from_str(s).unwrap();
        let v = b.build().unwrap();
        assert_eq!(v.flower_power, 12);
        assert_eq!(v.flower_power_err, 14);
        assert!(!logs_contain("no effect"));
    }
    #[test]
    #[traced_test]
    fn test_cfg_disabled() {
        let s = r#"
        time_travel = "hello world"
        "#;
        let b: t::CfgDisabledBuilder = toml::from_str(s).unwrap();
        let v = b.build().unwrap();
        assert_eq!(v.time_travel, 0);
        assert!(logs_contain(
            "Ignored configuration for 'time_travel'. \
            This option has no effect unless the program is built with resublimated thiotimoline"
        ));
        let s = r#"
        time_travel_err = "hello world"
        "#;
        let b: t::CfgDisabledBuilder = toml::from_str(s).unwrap();
        let e = b.build().unwrap_err();
        assert_matches!(e, ConfigBuildError::NoCompileTimeSupport { .. });
    }
    #[test]
    fn test_validating() {
        let err_notodd = t::CfgValidating::builder().odd(6).build().unwrap_err();
        assert_eq!(
            err_notodd.to_string(),
            "Value of odd was incorrect: Not odd"
        );
        let err_noteven = t::CfgValidating::builder().even(5).build().unwrap_err();
        assert_eq!(
            err_noteven.to_string(),
            "Value of even was incorrect: Not even"
        );
        let v = t::CfgValidating::builder().odd(5).even(6).build().unwrap();
        assert_eq!(v.odd, 5);
        assert_eq!(v.even, 6);
    }
    #[test]
    fn test_generic() {
        let mut b = t::CfgGeneric::<String, Vec<u32>>::builder();
        b.t("This is a test".to_string());
        b.u(vec![1, 2, 3]);
        let v = b.build().unwrap();
        assert_eq!(v.t, "This is a test");
        assert_eq!(&v.u, &[1, 2, 3]);
    }
    #[test]
    fn test_options_setters() {
        let mut b = t::OptionsCfg::builder();
        // Try with no-option inputs.
        b.a(32);
        b.s("hello");
        b.other((1, 2));
        b.nz(12);
        let c = b.build().unwrap();
        assert_eq!(c.a, Some(32));
        assert_eq!(c.b, Some(123));
        assert_eq!(c.s, Some("hello".to_string()));
        assert_eq!(c.other, Some((1, 2)));
        assert_eq!(c.nz, Some(12.try_into().unwrap()));
        // Try with option inputs.
        b.a(Some(12));
        b.b(None);
        b.s(Some("world"));
        b.other(Some((11, 22)));
        b.nz(Some(std::num::NonZeroU8::new(15).unwrap()));
        let c = b.build().unwrap();
        assert_eq!(c.a, Some(12));
        assert_eq!(c.b, None);
        assert_eq!(c.s, Some("world".to_string()));
        assert_eq!(c.other, Some((11, 22)));
        assert_eq!(c.nz, Some(15.try_into().unwrap()));
    }
    #[test]
    fn test_attributes() {
        let s1 = "fun_with_numbers = 1982374";
        let s2 = "its_fun_to_count = 1982375";
        let b1: t::AttribsCfgBuilder = toml::from_str(s1).unwrap();
        let b2: t::AttribsCfgBuilder = toml::from_str(s2).unwrap();
        // Make sure that derive(PartialEq, Ord) happened.
        assert_eq!(b1, b1);
        assert_ne!(b1, b2);
        assert!(b1 < b2);
    }
    #[test]
    fn test_setter_meta() {
        let mut b = t::SettersCfgBuilder::new();
        b.a(7);
        b.b(5_u8);
        assert!(b.c(1_u64 << 40).is_err());
        b.c(100_u64).unwrap();
        b.d(19);
        b.set_the_e(22);
        let v = b.build().unwrap();
        assert_eq!(v.a, 7 * 2);
        assert_eq!(v.b, 5_u32);
        assert_eq!(v.c, 100_u32);
        assert_eq!(v.d, Some(19));
        assert_eq!(v.e, 22);
    }
    #[test]
    fn test_build_fn_rename() {
        let mut b = t::RenameBuild::builder();
        let v = b.member(6).build_this().unwrap();
        assert_eq!(v.member, 6);
        let mut b = t::RenameSubBuild::builder();
        b.inner().member(5);
        let v = b.build().unwrap();
        assert_eq!(v.inner.member, 5);
    }
    #[test]
    fn test_custom() {
        let mut b = t::FullyCustomBuilder::new();
        b.try_the_thing(0xF00B00B512345678);
        assert_eq!(b.value, (0xF00B00B5, 0x12345678));
        let v = b.build().unwrap();
        assert_eq!(v.value, "4027252917 305419896");
    }
    #[test]
    fn test_field_skip() {
        let c = t::FieldSkipCfg::builder().build().unwrap();
        assert_eq!(c.value, 25);
    }
    #[test]
    fn test_list_builder() {
        let mut b = t::ListsCfgBuilder::new();
        b.set_integers(vec![12, 6, 3]);
        let c = b.build().unwrap();
        assert_eq!(&c.integers[..], &[12, 6, 3]);
        assert!(c.cats.contains("Moonbeam"));
        assert!(c.cats.contains("Damiano"));
        assert!(c.simple.is_empty());
        let b = t::ListsCfgBuilder::new();
        let c = b.build().unwrap();
        assert_eq!(&c.integers[..], &[7]);
        let mut b = t::ListsCfgBuilder::new();
        b.integers().push(22);
        b.cats().remove(0);
        b.cats().push("Frida".to_string());
        b.simple().push(t::SimpleBuilder::new());
        let c = b.build().unwrap();
        assert_eq!(&c.integers[..], &[7, 22]);
        assert!(c.cats.contains("Frida"));
        assert!(!c.cats.contains("Damiano"));
        assert_eq!(c.simple.len(), 1);
    }
    #[test]
    fn test_list_builder_serde() {
        let s1 = r#"
            integers = [ 1,2,3 ]
        "#;
        let s2 = r#"
            cats = [ "Prof. Jiggly", "Jorts" ]
        "#;
        let s3 = r#"
            cats = [ "Jenny" ]
            [[simple]]
            xyz = 9
            abc = 12
            [[simple]]
            xyz = 16
        "#;
        let b1: t::ListsCfgBuilder = toml::from_str(s1).unwrap();
        let b2: t::ListsCfgBuilder = toml::from_str(s2).unwrap();
        let b3: t::ListsCfgBuilder = toml::from_str(s3).unwrap();
        let c1 = b1.build().unwrap();
        let c2 = b2.build().unwrap();
        let c3 = b3.build().unwrap();
        assert_eq!(&c1.integers[..], &[1, 2, 3]);
        assert!(c1.cats.contains("Checkers"));
        assert!(!c1.cats.contains("Jorts"));
        assert_eq!(&c2.integers[..], &[7]);
        assert_eq!(c2.cats.len(), 2);
        assert!(c2.cats.contains("Jorts"));
        assert!(!c2.cats.contains("Checkers"));
        assert_eq!(c3.cats.len(), 1);
        assert_eq!(c3.simple.len(), 2);
        assert_eq!(c3.simple[0].xyz, 9);
        assert_eq!(c3.simple[0].abc, 12);
        assert_eq!(c3.simple[1].xyz, 16);
        assert_eq!(c3.simple[1].abc, 3);
    }
    #[test]
    fn test_map_builder() {
        let mut b = t::MapCfg::builder();
        {
            let mut sb = t::Simple::builder();
            sb.xyz(11);
            b.map().insert("Hello".to_string(), sb);
        }
        {
            let mut sb = t::Simple::builder();
            sb.abc(33);
            b.map().insert("World".to_string(), sb);
        }
        let c = b.build().unwrap();
        assert_eq!(c.map.len(), 3);
        assert_eq!(c.map.get("Hello").unwrap().xyz, 11);
        assert_eq!(c.map.get("Hello").unwrap().abc, 3);
        assert_eq!(c.map.get("World").unwrap().xyz, 0);
        assert_eq!(c.map.get("World").unwrap().abc, 33);
        assert_eq!(c.map.get("pangolin").unwrap().xyz, 123);
        assert_eq!(c.map.get("pangolin").unwrap().abc, 32);
    }
}