1
//! Lists in builders
2
//!
3
//! Use [`define_list_builder_helper`] and [`define_list_builder_accessors`] together when
4
//! a configuration (or other struct with a builder)
5
//! wants to contain a `Vec` of config sub-entries.
6
//!
7
//! ### How to use these macros
8
//!
9
//!  * For each kind of list, define a `ThingList` type alias for the validated form,
10
//!    and call [`define_list_builder_helper`] to define a `ThingListBuilder` helper
11
//!    type.  (Different lists with the same Rust type, but which ought to have a different
12
//!    default, are different "kinds" and should each have a separately named type alias.)
13
//!
14
//!    (Or, alternatively, with a hand-written builder type, make the builder field be
15
//!    `Option<Vec<ElementBuilder>>`.)
16
//!
17
// An alternative design would be declare the field on `Outer` as `Vec<Thing>`, and to provide
18
// a `VecBuilder`.  But:
19
//
20
//  (i) the `.build()` method would have to be from a trait (because it would be `VecBuilder<Item>`
21
//  which would have to contain some `ItemBuilder`, and for the benefit of `VecBuilder::build()`).
22
//  Although derive_builder` does not provide that trait now, this problem is not insuperable,
23
//  but it would mean us inventing a `Buildable` trait and a macro to generate it, or forking
24
//  derive_builder further.
25
//
26
//  (ii) `VecBuilder<Item>::build()` would have to have the same default list for every
27
//  type Item (an empty list).  So places where the default list is not empty would need special
28
//  handling.  The special handling would look quite like what we have here.
29
//
30
//!  * For each struct field containing a list, in a struct deriving `Builder`,
31
//!    decorate the field with `#[builder(sub_builder, setter(custom))]`
32
//!    to (i) get `derive_builder` call the appropriate build method,
33
//!    (ii) suppress the `derive_builder`-generated setter.
34
//!
35
// `ThingListBuilder` exists for two reasons:
36
//
37
//  * derive_builder wants to call simply `build` on the builder struct field, and will
38
//    generate code for attaching the field name to any error which occurs.  We could
39
//    override the per-field build expression, but it would be quite a lot of typing and
40
//    would recapitulate the field name three times.
41
//
42
//  * The field accessors (which must be generated by a different macro_rules macros, at least
43
//    unless we soup up derive_builder some more) might need to do defaulting, too.  if
44
//    the builder field is its own type, that can be a method on that type.
45
//
46
//!  * For each struct containing lists, call [`define_list_builder_accessors`]
47
//!    to define the accessor methods.
48
//!
49
//! ### Example - list of structs with builders
50
//!
51
//! ```
52
//! use derive_builder::Builder;
53
//! use serde::{Deserialize, Serialize};
54
//! use tor_config::{define_list_builder_helper, define_list_builder_accessors, ConfigBuildError};
55
//!
56
//! #[derive(Builder, Debug, Eq, PartialEq)]
57
//! #[builder(build_fn(error = "ConfigBuildError"))]
58
//! #[builder(derive(Debug, Serialize, Deserialize))]
59
//! pub struct Thing { value: i32 }
60
//!
61
//! #[derive(Builder, Debug, Eq, PartialEq)]
62
//! #[builder(build_fn(error = "ConfigBuildError"))]
63
//! #[builder(derive(Debug, Serialize, Deserialize))]
64
//! pub struct Outer {
65
//!     /// List of things, being built as part of the configuration
66
//!     #[builder(sub_builder, setter(custom))]
67
//!     things: ThingList,
68
//! }
69
//!
70
//! define_list_builder_accessors! {
71
//!     struct OuterBuilder {
72
//!         pub things: [ThingBuilder],
73
//!     }
74
//! }
75
//!
76
//! /// Type alias for use by list builder macrology
77
//! type ThingList = Vec<Thing>;
78
//!
79
//! define_list_builder_helper! {
80
//!     pub(crate) struct ThingListBuilder {
81
//!         pub(crate) things: [ThingBuilder],
82
//!     }
83
//!     built: ThingList = things;
84
//!     default = vec![];
85
//! }
86
//!
87
//! let mut builder = OuterBuilder::default();
88
//! builder.things().push(ThingBuilder::default().value(42).clone());
89
//! assert_eq!{ builder.build().unwrap().things, &[Thing { value: 42 }] }
90
//!
91
//! builder.set_things(vec![ThingBuilder::default().value(38).clone()]);
92
//! assert_eq!{ builder.build().unwrap().things, &[Thing { value: 38 }] }
93
//! ```
94
//!
95
//! ### Example - list of trivial values
96
//!
97
//! ```
98
//! use derive_builder::Builder;
99
//! use serde::{Deserialize, Serialize};
100
//! use tor_config::{define_list_builder_helper, define_list_builder_accessors, ConfigBuildError};
101
//!
102
//! #[derive(Builder, Debug, Eq, PartialEq)]
103
//! #[builder(build_fn(error = "ConfigBuildError"))]
104
//! #[builder(derive(Debug, Serialize, Deserialize))]
105
//! pub struct Outer {
106
//!     /// List of values, being built as part of the configuration
107
//!     #[builder(sub_builder, setter(custom))]
108
//!     values: ValueList,
109
//! }
110
//!
111
//! define_list_builder_accessors! {
112
//!    struct OuterBuilder {
113
//!        pub values: [u32],
114
//!    }
115
//! }
116
//!
117
//! /// Type alias for use by list builder macrology
118
//! pub type ValueList = Vec<u32>;
119
//!
120
//! define_list_builder_helper! {
121
//!    pub(crate) struct ValueListBuilder {
122
//!        pub(crate) values: [u32],
123
//!    }
124
//!    built: ValueList = values;
125
//!    default = vec![27];
126
//!    item_build: |&value| Ok(value);
127
//!    item_apply_defaults: |_| Ok::<_, ConfigBuildError>(());
128
//! }
129
//!
130
//! let mut builder = OuterBuilder::default();
131
//! assert_eq!{ builder.build().unwrap().values, &[27] }
132
//!
133
//! builder.values().push(12);
134
//! assert_eq!{ builder.build().unwrap().values, &[27, 12] }
135
//! ```
136

            
137
use std::fmt;
138
use std::marker::PhantomData;
139
use std::str::FromStr;
140

            
141
use educe::Educe;
142
use itertools::Itertools;
143
use serde::{Deserialize, Deserializer, Serialize};
144
use thiserror::Error;
145

            
146
pub use crate::define_list_builder_accessors;
147
pub use crate::define_list_builder_helper;
148

            
149
/// Define a list builder struct for use with [`define_list_builder_accessors`]
150
///
151
/// Generates an builder struct that can be used with derive_builder
152
/// and [`define_list_builder_accessors`] to configure a list of some kind.
153
///
154
/// **See the [`list_builder` module documentation](crate::list_builder) for an overview.**
155
///
156
/// ### Generated struct
157
///
158
/// This macro-generated builder struct contains `Option<Vec<ThingBuilder>>`, to allow it to
159
/// distinguish "never set" from "has been adjusted or set, possibly to the empty list".
160
///
161
/// This struct is not exposed as part of the API for setting the configuration.
162
/// Generally the visibility (`$vis`) should be private,
163
/// but sometimes `pub(crate)` or `pub` is necessary,
164
/// for example if the list is to be included in a struct in another module or crate.
165
/// Usually `$field_vis` should be the same as `$vis`.
166
///
167
/// `#[derive(Default, Clone, Debug, Serialize, Deserialize)]`
168
///  will be applied to the generated builder,
169
/// but you can specify other attributes too.
170
/// There is no need to supply any documentation; this is an internal struct and
171
/// the macro will supply a suitable (bland) doc comment.
172
/// (If you do supply documentation, the autogenerated docs will be appended,
173
/// so start with a summary line.)
174
/// Documentation for the semantics and default value should be applied
175
/// to the field(s) in the containing struct(s).
176
///
177
/// `#[serde(transparent)]` will be applied to the generated `ThingBuilder` struct,
178
/// so that it deserializes just like `Option<Vec<Thing>>`.
179
///
180
/// ### Input to the macro
181
///
182
/// For the input syntax, refer to the docs autogenerated from the macro's matcher.
183
///
184
/// The `built` clause specifies the type of the built value, and how to construct it.
185
/// In the expression part, `things` (the field name) will be the default-resolved `Vec<Thing>`;
186
/// it should be consumed by the expression.
187
/// If the built value is simply a `Vec`, you can just write `built: ThingList = things;`.
188
///
189
/// The `default` clause must provide an expression evaluating to a `Vec<ThingBuilder>`.
190
///
191
/// The `item_build` clause, if supplied, provides a closure with type
192
/// `FnMut(&ThingBuilder) -> Result<Thing, ConfigBuildError>`;
193
/// the default is to call `thing_builder.build()`.
194
///
195
/// The `#[ serde $serde_attrs:tt ]`, if supplied, replace the serde attribute
196
/// `#[serde(transparent)]`.
197
/// The transparent attribute is applied by default
198
/// to arrange that the serde view of the list is precisely `Option<Vec>`.
199
/// If serialisation is done another way, for example with `#[serde(into)]`,
200
/// that must be specified here.
201
///
202
/// `[$generics]` are generics for `$ListBuilder`.
203
/// Inline bounds (`T: Debug`) are not supported; use a `where` clause instead.
204
/// Due to limitations of `macro_rules`, the parameters must be within `[ ]` rather than `< >`,
205
/// and an extraneous pair of `[ ]` must appear around any `$where_clauses`.
206
//
207
// This difficulty with macro_rules is not well documented.
208
// The upstream Rust bug tracker has this issue
209
//   https://github.com/rust-lang/rust/issues/73174
210
//   Matching function signature is nearly impossible in declarative macros (mbe)
211
// which is not precisely this problem but is very nearby.
212
// There's also the vapourware "declarative macros 2.0"
213
//   https://github.com/rust-lang/rust/issues/39412
214
#[macro_export]
215
macro_rules! define_list_builder_helper {
216
    {
217
        $(#[ $docs_and_attrs:meta ])*
218
        $vis:vis
219
        struct $ListBuilder:ident $( [ $($generics:tt)* ] )?
220
        $( where [ $($where_clauses:tt)* ] )?
221
        {
222
            $field_vis:vis $things:ident : [$EntryBuilder:ty] $(,)?
223
        }
224
        built: $Built:ty = $built:expr;
225
        default = $default:expr;
226
        $( item_build: $item_build:expr; )?
227
        $( item_apply_defaults: $item_apply_defaults:expr; )?
228
        $(#[ serde $serde_attrs:tt ] )+
229
    } => {
230
        #[derive(Clone, Debug)]
231
        #[derive($crate::deps::serde::Serialize, $crate::deps::serde::Deserialize)]
232
        $(#[ serde $serde_attrs ])+
233
        $(#[ $docs_and_attrs ])*
234
        /// Wrapper struct to help derive_builder find the right types and methods
235
        ///
236
        /// This struct is not part of the configuration API.
237
        /// Refer to the containing structures for information on how to build the config.
238
        $vis struct $ListBuilder $( < $($generics)* > )?
239
        $( where $($where_clauses)* )?
240
        {
241
            /// The list, as overridden
242
            $field_vis $things: Option<Vec<$EntryBuilder>>,
243
        }
244

            
245
        impl $( <$($generics)*> )? Default for $ListBuilder$( < $($generics)* > )?
246
        $( where $($where_clauses)* )?
247
        {
248
627244
            fn default() -> Self {
249
627244
                Self {
250
627244
                    $things: None
251
627244
                }
252
627244
            }
253
        }
254

            
255
        impl $( < $($generics)* > )? $ListBuilder $( < $($generics)* > )?
256
        $( where $($where_clauses)* )?
257
        {
258
            /// Resolve this list to a list of built items.
259
            ///
260
            /// If the value is still the [`Default`],
261
            /// a built-in default list will be built and returned;
262
            /// otherwise each applicable item will be built,
263
            /// and the results collected into a single built list.
264
626658
            $vis fn build(&self) -> Result<$Built, $crate::ConfigBuildError> {
265
                let default_buffer;
266
626658
                let $things = match &self.$things {
267
7061
                    Some($things) => $things,
268
                    None => {
269
619597
                        default_buffer = Self::default_list();
270
619597
                        &default_buffer
271
                    }
272
                };
273

            
274
626658
                let $things = $things
275
626658
                    .iter()
276
626658
                    .map(
277
                        $crate::deps::macro_first_nonempty!{
278
                            [ $( $item_build )? ],
279
1668514
                            [ |item| item.build() ],
280
                        }
281
                    )
282
626658
                    .collect::<Result<_, $crate::ConfigBuildError>>()?;
283
626654
                Ok($built)
284
626658
            }
285

            
286
            /// The default list
287
625348
            fn default_list() -> Vec<$EntryBuilder> {
288
                 $default
289
625348
            }
290

            
291
            /// Resolve the list to the default if necessary and then return `&mut Vec`
292
6001
            $vis fn access(&mut self) -> &mut Vec<$EntryBuilder> {
293
6001
                self.$things.get_or_insert_with(Self::default_list)
294
6001
            }
295

            
296
            /// Resolve the list to the default if necessary and then return `&mut Vec`
297
1004
            $vis fn access_opt(&self) -> &Option<Vec<$EntryBuilder>> {
298
1004
                &self.$things
299
1004
            }
300

            
301
            /// Resolve the list to the default if necessary and then return `&mut Vec`
302
476
            $vis fn access_opt_mut(&mut self) -> &mut Option<Vec<$EntryBuilder>> {
303
476
                &mut self.$things
304
476
            }
305
        }
306

            
307
        impl $( < $($generics)* > )? $crate::load::Builder
308
        for $ListBuilder $( < $($generics)* > )?
309
        $( where $($where_clauses)* )? {
310
            type Built = $Built;
311
            fn build(&self) -> ::std::result::Result<$Built, $crate::ConfigBuildError> {
312
                $ListBuilder :: build(self)
313
            }
314
        }
315

            
316
        impl $( < $($generics)* > )? $crate::load::ConfigBuilder
317
        for $ListBuilder $( < $($generics)* > )?
318
        $( where $($where_clauses)* )? {
319
            fn apply_defaults(&mut self) -> ::std::result::Result<(), $crate::ConfigBuildError> {
320
                $crate::deps::if_empty!{ { $($item_build)? } {
321
                    // There is no per-item build function, so we don't have to apply defaults.
322
                } {
323
                    // There is a build function, so we call apply_defaults recursively.
324
                    #[allow(unused_imports)]
325
                    use $crate::load::ConfigBuilder as _;
326
                    for val in self.$things.get_or_insert_with(Self::default_list) {
327
                        $crate::deps::if_empty!{ { $($item_apply_defaults)? } {
328
                            val.apply_defaults()?;
329
                        } {
330
                            ($($item_apply_defaults)?)(val)?;
331
                        }}
332
                    }
333
                }};
334
                Ok(())
335
            }
336
        }
337

            
338
        impl $( < $($generics)* > )? $crate::extend_builder::ExtendBuilder
339
        for $ListBuilder $( < $($generics)* > )?
340
        $( where $($where_clauses)* )? {
341
            fn extend_from(&mut self, other: Self, strategy: $crate::extend_builder::ExtendStrategy) {
342
                match strategy {
343
                    $crate::extend_builder::ExtendStrategy::ReplaceLists =>
344
                        *self = other,
345
                }
346
            }
347
        }
348
    };
349

            
350
    // Expand the version without `#[ serde $serde_attrs ]` into a call
351
    // which provides `#[serde(transparent)]`.
352
    //
353
    // We can't use `macro_first_nonempty!` because macro calls cannot be invoked
354
    // to generate attributes, only items, expressions, etc.
355
    {
356
        $(#[ $docs_and_attrs:meta ])*
357
        $vis:vis
358
        struct $ListBuilder:ident $( [ $($generics:tt)* ] )?
359
        $( where [ $($where_clauses:tt)* ] )?
360
        {
361
            $field_vis:vis $things:ident : [$EntryBuilder:ty] $(,)?
362
        }
363
        built: $Built:ty = $built:expr;
364
        default = $default:expr;
365
        $( item_build: $item_build:expr; )?
366
        $( item_apply_defaults: $item_apply_defaults:expr; )?
367
    } => {
368
        $crate::define_list_builder_helper! {
369
            $(#[ $docs_and_attrs ])*
370
            $vis
371
            struct $ListBuilder $( [ $($generics)* ] )?
372
            $( where [ $($where_clauses)* ] )?
373
            {
374
                $field_vis $things : [$EntryBuilder],
375
            }
376
            built: $Built = $built;
377
            default = $default;
378
            $( item_build: $item_build; )?
379
            $( item_apply_defaults: $item_apply_defaults; )?
380
            #[serde(transparent)]
381
        }
382
    };
383
}
384

            
385
/// Define accessor methods for a configuration item which is a list
386
///
387
/// **See the [`list_builder` module documentation](crate::list_builder) for an overview.**
388
///
389
/// Generates the following methods for each specified field:
390
///
391
/// ```skip
392
/// impl $OuterBuilder {
393
///     pub fn $things(&mut self) -> &mut Vec<$EntryBuilder> { .. }
394
///     pub fn set_$things(&mut self, list: Vec<$EntryBuilder>) { .. }
395
///     pub fn opt_$things(&self) -> &Option<Vec<$EntryBuilder>> { .. }
396
///     pub fn opt_$things_mut>](&mut self) -> &mut Option<Vec<$EntryBuilder>> { .. }
397
/// }
398
/// ```
399
///
400
/// Each `$EntryBuilder` should have been defined by [`define_list_builder_helper`];
401
/// the method bodies from this macro rely on facilities which will beprovided by that macro.
402
///
403
/// You can call `define_list_builder_accessors` once for a particular `$OuterBuilder`,
404
/// with any number of fields with possibly different entry (`$EntryBuilder`) types.
405
#[macro_export]
406
macro_rules! define_list_builder_accessors {
407
    {
408
        struct $OuterBuilder:ty {
409
            $(
410
                $vis:vis $things:ident: [$EntryBuilder:ty],
411
            )*
412
        }
413
    } => {
414
        #[allow(dead_code)]
415
        impl $OuterBuilder { $( $crate::deps::paste!{
416
            /// Access the being-built list (resolving default)
417
            ///
418
            /// If the field has not yet been set or accessed, the default list will be
419
            /// constructed and a mutable reference to the now-defaulted list of builders
420
            /// will be returned.
421
2506476
            $vis fn $things(&mut self) -> &mut Vec<$EntryBuilder> {
422
337
                #[allow(unused_imports)]
423
337
                use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _;
424
2506584
                self.$things.access()
425
2506584
            }
426
337

            
427
337
            /// Set the whole list (overriding the default)
428
358
            $vis fn [<set_ $things>](&mut self, list: Vec<$EntryBuilder>) {
429
8969
                #[allow(unused_imports)]
430
8969
                use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _;
431
8982
                *self.$things.access_opt_mut() = Some(list)
432
8982
            }
433
8969

            
434
8969
            /// Inspect the being-built list (with default unresolved)
435
8969
            ///
436
8969
            /// If the list has not yet been set, or accessed, `&None` is returned.
437
8991
            $vis fn [<opt_ $things>](&self) -> &Option<Vec<$EntryBuilder>> {
438
                #[allow(unused_imports)]
439
                use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _;
440
9101
                self.$things.access_opt()
441
9101
            }
442

            
443
            /// Mutably access the being-built list (with default unresolved)
444
            ///
445
            /// If the list has not yet been set, or accessed, `&mut None` is returned.
446
2
            $vis fn [<opt_ $things _mut>](&mut self) -> &mut Option<Vec<$EntryBuilder>> {
447
                #[allow(unused_imports)]
448
                use $crate::list_builder::DirectDefaultEmptyListBuilderAccessors as _;
449
2
                self.$things.access_opt_mut()
450
2
            }
451
        } )* }
452
    }
453
}
454

            
455
/// Extension trait, an alternative to `define_list_builder_helper`
456
///
457
/// Useful for a handwritten `Builder` which wants to contain a list,
458
/// which is an `Option<Vec<ItemBuilder>>`.
459
///
460
/// # Example
461
///
462
/// ```
463
/// use tor_config::define_list_builder_accessors;
464
///
465
/// #[derive(Default)]
466
/// struct WombatBuilder {
467
///     leg_lengths: Option<Vec<u32>>,
468
/// }
469
///
470
/// define_list_builder_accessors! {
471
///     struct WombatBuilder {
472
///         leg_lengths: [u32],
473
///     }
474
/// }
475
///
476
/// let mut wb = WombatBuilder::default();
477
/// wb.leg_lengths().push(42);
478
///
479
/// assert_eq!(wb.leg_lengths, Some(vec![42]));
480
/// ```
481
///
482
/// It is not necessary to `use` this trait anywhere in your code;
483
/// the macro `define_list_builder_accessors` arranges to have it in scope where it needs it.
484
pub trait DirectDefaultEmptyListBuilderAccessors {
485
    /// Entry type
486
    type T;
487
    /// Get access to the `Vec`, defaulting it
488
    fn access(&mut self) -> &mut Vec<Self::T>;
489
    /// Get access to the `Option<Vec>`
490
    fn access_opt(&self) -> &Option<Vec<Self::T>>;
491
    /// Get mutable access to the `Option<Vec>`
492
    fn access_opt_mut(&mut self) -> &mut Option<Vec<Self::T>>;
493
}
494
impl<T> DirectDefaultEmptyListBuilderAccessors for Option<Vec<T>> {
495
    type T = T;
496
2501802
    fn access(&mut self) -> &mut Vec<T> {
497
2501802
        self.get_or_insert_with(Vec::new)
498
2501802
    }
499
8706
    fn access_opt(&self) -> &Option<Vec<T>> {
500
8706
        self
501
8706
    }
502
2
    fn access_opt_mut(&mut self) -> &mut Option<Vec<T>> {
503
2
        self
504
2
    }
505
}
506

            
507
define_list_builder_helper! {
508
    /// List of `T`, a straightforward type, being built as part of the configuration
509
    ///
510
    /// The default is the empty list.
511
    ///
512
    /// ### Example
513
    ///
514
    /// ```
515
    /// use derive_builder::Builder;
516
    /// use serde::{Deserialize, Serialize};
517
    /// use tor_config::ConfigBuildError;
518
    /// use tor_config::{define_list_builder_accessors, list_builder::VecBuilder};
519
    /// use std::net::SocketAddr;
520
    ///
521
    /// #[derive(Debug, Clone, Builder)]
522
    /// #[builder(build_fn(error = "ConfigBuildError"))]
523
    /// #[builder(derive(Debug, Serialize, Deserialize))]
524
    /// pub struct FallbackDir {
525
    ///     #[builder(sub_builder(fn_name = "build"), setter(custom))]
526
    ///     orports: Vec<SocketAddr>,
527
    /// }
528
    ///
529
    /// define_list_builder_accessors! {
530
    ///     struct FallbackDirBuilder {
531
    ///         pub orports: [SocketAddr],
532
    ///     }
533
    /// }
534
    ///
535
    /// let mut bld = FallbackDirBuilder::default();
536
    /// bld.orports().push("[2001:db8:0::42]:12".parse().unwrap());
537
    /// assert_eq!( bld.build().unwrap().orports[0].to_string(),
538
    ///             "[2001:db8::42]:12" );
539
    /// ```
540
    pub struct VecBuilder[T] where [T: Clone] {
541
        values: [T],
542
    }
543
    built: Vec<T> = values;
544
    default = vec![];
545
6
    item_build: |item| Ok(item.clone());
546
    item_apply_defaults: |_| Ok::<_, crate::ConfigBuildError>(());
547
}
548

            
549
/// Configuration item specifiable as a list, or a single multi-line string
550
///
551
/// If a list is supplied, they are deserialized as builders.
552
/// If a single string is supplied, it is split into lines, and `#`-comments
553
/// and blank lines and whitespace are stripped, and then each line is parsed
554
/// as a builder.
555
/// (Eventually, the builders will be built.)
556
///
557
/// For use with `sub_builder` and [`define_list_builder_helper`],
558
/// with `#[serde(try_from)]` and `#[serde(into)]`.
559
///
560
/// # Example
561
///
562
/// ```
563
/// use derive_builder::Builder;
564
/// use serde::{Deserialize, Serialize};
565
/// use tor_config::{ConfigBuildError, MultilineListBuilder};
566
/// use tor_config::convert_helper_via_multi_line_list_builder;
567
/// use tor_config::{define_list_builder_accessors, define_list_builder_helper};
568
/// use tor_config::impl_standard_builder;
569
///
570
/// # fn generate_random<T: Default>() -> T { Default::default() }
571
///
572
/// #[derive(Debug, Clone, Builder, Eq, PartialEq)]
573
/// #[builder(build_fn(error = "ConfigBuildError"))]
574
/// #[builder(derive(Debug, Serialize, Deserialize))]
575
/// #[non_exhaustive]
576
/// pub struct LotteryConfig {
577
///     /// What numbers should win the lottery?  Setting this is lottery fraud.
578
///     #[builder(sub_builder, setter(custom))]
579
///     #[builder_field_attr(serde(default))]
580
///     winners: LotteryNumberList,
581
/// }
582
/// impl_standard_builder! { LotteryConfig }
583
///
584
/// /// List of lottery winners
585
/// //
586
/// // This type alias arranges that we can put `LotteryNumberList` in `LotteryConfig`
587
/// // and have derive_builder put a `LotteryNumberListBuilder` in `LotteryConfigBuilder`.
588
/// pub type LotteryNumberList = Vec<u16>;
589
///
590
/// define_list_builder_helper! {
591
///     struct LotteryNumberListBuilder {
592
///         numbers: [u16],
593
///     }
594
///     built: LotteryNumberList = numbers;
595
///     default = generate_random();
596
///     item_build: |number| Ok(*number);
597
///     item_apply_defaults: |_| Ok::<_, tor_config::ConfigBuildError>(());
598
///
599
///     #[serde(try_from="MultilineListBuilder<u16>")]
600
///     #[serde(into="MultilineListBuilder<u16>")]
601
/// }
602
///
603
/// convert_helper_via_multi_line_list_builder! {
604
///     struct LotteryNumberListBuilder {
605
///         numbers: [u16],
606
///     }
607
/// }
608
///
609
/// define_list_builder_accessors! {
610
///     struct LotteryConfigBuilder {
611
///         pub winners: [u16],
612
///     }
613
/// }
614
///
615
/// let lc: LotteryConfigBuilder = toml::from_str(r#"winners = [1,2,3]"#).unwrap();
616
/// let lc = lc.build().unwrap();
617
/// assert_eq!{ lc.winners, [1,2,3] }
618
///
619
/// let lc = r#"
620
/// winners = '''
621
///   ## Enny tells us this is the ticket they bought:
622
///
623
///   4
624
///   5
625
///   6
626
/// '''
627
/// "#;
628
/// let lc: LotteryConfigBuilder = toml::from_str(lc).unwrap();
629
/// let lc = lc.build().unwrap();
630
/// assert_eq!{ lc.winners, [4,5,6] }
631
/// ```
632
#[derive(Clone, Debug, Default, Serialize)]
633
#[serde(untagged)]
634
#[non_exhaustive]
635
pub enum MultilineListBuilder<EB> {
636
    /// Config key not present
637
    #[default]
638
    Unspecified,
639

            
640
    /// Config key was a string which is to be parsed line-by-line
641
    String(String),
642

            
643
    /// Config key was a list of the individual entry builders
644
    List(Vec<EB>),
645
}
646

            
647
/// Error from trying to parse a MultilineListBuilder as a list of particular items
648
///
649
/// Usually, this error is generated during deserialization.
650
#[derive(Error, Debug, Clone)]
651
#[error("multi-line string, line/item {item_number}: could not parse {line:?}: {error}")]
652
#[non_exhaustive]
653
pub struct MultilineListBuilderError<E: std::error::Error + Clone + Send + Sync> {
654
    /// The line number (in the multi-line text string) that could not be parsed
655
    ///
656
    /// Starting at 1.
657
    item_number: usize,
658

            
659
    /// The line that could not be parsed
660
    line: String,
661

            
662
    /// The parse error from `FromStr`
663
    ///
664
    /// This is not a `source` because we want to include it in the `Display`
665
    /// implementation so that serde errors are useful.
666
    error: E,
667
}
668

            
669
// We could derive this with `#[serde(untagged)]` but that produces quite terrible error
670
// messages, which do not reproduce the error messages from any of the variants.
671
//
672
// Instead, have a manual implementation, which can see whether the input is a list or a string.
673
impl<'de, EB: Deserialize<'de>> Deserialize<'de> for MultilineListBuilder<EB> {
674
48
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
675
48
    where
676
48
        D: Deserializer<'de>,
677
    {
678
48
        deserializer.deserialize_any(MllbVisitor::default())
679
48
    }
680
}
681

            
682
/// Visitor for deserialize_any for [`MultilineListBuilder`]
683
#[derive(Educe)]
684
#[educe(Default)]
685
struct MllbVisitor<EB> {
686
    /// Variance: this visitor constructs `EB`s
687
    ret: PhantomData<fn() -> EB>,
688
}
689

            
690
impl<'de, EB: Deserialize<'de>> serde::de::Visitor<'de> for MllbVisitor<EB> {
691
    type Value = MultilineListBuilder<EB>;
692

            
693
    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
694
        write!(f, "list of items, or multi-line string")
695
    }
696

            
697
40
    fn visit_seq<A: serde::de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
698
40
        let mut v = vec![];
699
82
        while let Some(e) = seq.next_element()? {
700
42
            v.push(e);
701
42
        }
702
38
        Ok(MultilineListBuilder::List(v))
703
40
    }
704

            
705
8
    fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
706
8
        self.visit_string(v.to_owned())
707
8
    }
708
8
    fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
709
8
        Ok(MultilineListBuilder::String(v))
710
8
    }
711

            
712
    fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> {
713
        Ok(MultilineListBuilder::Unspecified)
714
    }
715
}
716

            
717
impl<EB> From<Option<Vec<EB>>> for MultilineListBuilder<EB> {
718
68
    fn from(list: Option<Vec<EB>>) -> Self {
719
        use MultilineListBuilder as MlLB;
720
68
        match list {
721
68
            None => MlLB::Unspecified,
722
            Some(list) => MlLB::List(list),
723
        }
724
68
    }
725
}
726

            
727
impl<EB> TryInto<Option<Vec<EB>>> for MultilineListBuilder<EB>
728
where
729
    EB: FromStr,
730
    EB::Err: std::error::Error + Clone + Send + Sync,
731
{
732
    type Error = MultilineListBuilderError<EB::Err>;
733
144
    fn try_into(self) -> Result<Option<Vec<EB>>, Self::Error> {
734
        use MultilineListBuilder as MlLB;
735

            
736
        /// Helper for parsing each line of `iter` and collecting the results
737
40
        fn parse_collect<'s, I>(
738
40
            iter: impl Iterator<Item = (usize, &'s str)>,
739
40
        ) -> Result<Option<Vec<I>>, MultilineListBuilderError<I::Err>>
740
40
        where
741
40
            I: FromStr,
742
40
            I::Err: std::error::Error + Clone + Send + Sync,
743
        {
744
            Ok(Some(
745
108
                iter.map(|(i, l)| {
746
108
                    l.parse().map_err(|error| MultilineListBuilderError {
747
2
                        item_number: i + 1,
748
2
                        line: l.to_owned(),
749
2
                        error,
750
2
                    })
751
108
                })
752
40
                .try_collect()?,
753
            ))
754
40
        }
755

            
756
144
        Ok(match self {
757
2
            MlLB::Unspecified => None,
758
102
            MlLB::List(list) => Some(list),
759
40
            MlLB::String(s) => parse_collect(
760
40
                s.lines()
761
40
                    .enumerate()
762
142
                    .map(|(i, l)| (i, l.trim()))
763
142
                    .filter(|(_, l)| !(l.starts_with('#') || l.is_empty())),
764
2
            )?,
765
        })
766
144
    }
767
}
768

            
769
/// Implement `TryFrom<MultilineListBuilder>` and `Into<MultilineListBuilder>` for $Builder.
770
///
771
/// The input syntax is the `struct` part of that for `define_list_builder_helper`.
772
/// `$EntryBuilder` must implement `FromStr`.
773
//
774
// This is a macro because a helper trait to enable blanket impl would have to provide
775
// access to `$things`, defeating much of the point.
776
#[macro_export]
777
macro_rules! convert_helper_via_multi_line_list_builder { {
778
    struct $ListBuilder:ident { $things:ident: [$EntryBuilder:ty] $(,)? }
779
} => {
780
    impl std::convert::TryFrom<$crate::MultilineListBuilder<$EntryBuilder>> for $ListBuilder {
781
        type Error = $crate::MultilineListBuilderError<<$EntryBuilder as std::str::FromStr>::Err>;
782

            
783
132
        fn try_from(mllb: $crate::MultilineListBuilder<$EntryBuilder>)
784
132
                    -> std::result::Result<$ListBuilder, Self::Error> {
785
132
            Ok($ListBuilder { $things: mllb.try_into()? })
786
132
        }
787
    }
788

            
789
    impl From<$ListBuilder> for MultilineListBuilder<$EntryBuilder> {
790
68
        fn from(lb: $ListBuilder) -> MultilineListBuilder<$EntryBuilder> {
791
68
            lb.$things.into()
792
68
        }
793
    }
794
} }
795

            
796
#[cfg(test)]
797
mod test {
798
    // @@ begin test lint list maintained by maint/add_warning @@
799
    #![allow(clippy::bool_assert_comparison)]
800
    #![allow(clippy::clone_on_copy)]
801
    #![allow(clippy::dbg_macro)]
802
    #![allow(clippy::mixed_attributes_style)]
803
    #![allow(clippy::print_stderr)]
804
    #![allow(clippy::print_stdout)]
805
    #![allow(clippy::single_char_pattern)]
806
    #![allow(clippy::unwrap_used)]
807
    #![allow(clippy::unchecked_time_subtraction)]
808
    #![allow(clippy::useless_vec)]
809
    #![allow(clippy::needless_pass_by_value)]
810
    #![allow(clippy::string_slice)] // See arti#2571
811
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
812
    use super::*;
813
    use derive_builder::Builder;
814

            
815
    #[derive(Eq, PartialEq, Builder)]
816
    #[builder(derive(Deserialize))]
817
    struct Outer {
818
        #[builder(sub_builder, setter(custom))]
819
        list: List,
820
    }
821

            
822
    define_list_builder_accessors! {
823
        struct OuterBuilder {
824
            list: [char],
825
        }
826
    }
827

            
828
    type List = Vec<char>;
829

            
830
    define_list_builder_helper! {
831
        struct ListBuilder {
832
            list: [char],
833
        }
834
        built: List = list;
835
        default = vec!['a'];
836
        item_build: |&c| Ok(c);
837
        item_apply_defaults: |_| Ok::<_, crate::ConfigBuildError>(());
838
    }
839

            
840
    #[test]
841
    fn nonempty_default() {
842
        let mut b = OuterBuilder::default();
843
        assert!(b.opt_list().is_none());
844
        assert_eq! { b.build().expect("build failed").list, ['a'] };
845

            
846
        b.list().push('b');
847
        assert!(b.opt_list().is_some());
848
        assert_eq! { b.build().expect("build failed").list, ['a', 'b'] };
849

            
850
        for mut b in [b.clone(), OuterBuilder::default()] {
851
            b.set_list(vec!['x', 'y']);
852
            assert!(b.opt_list().is_some());
853
            assert_eq! { b.build().expect("build failed").list, ['x', 'y'] };
854
        }
855

            
856
        *b.opt_list_mut() = None;
857
        assert_eq! { b.build().expect("build failed").list, ['a'] };
858
    }
859

            
860
    #[test]
861
    fn vecbuilder() {
862
        // Minimal test, since rustdoc tests seem not to be finding the documentation inside
863
        // the declaration of VecBuilder.  (Or at least that's what the coverage says.)
864
        let mut b = VecBuilder::<u32>::default();
865
        b.access().push(1);
866
        b.access().push(2);
867
        b.access().push(3);
868
        assert_eq!(b.build().unwrap(), vec![1, 2, 3]);
869
    }
870

            
871
    #[test]
872
    fn deser() {
873
        let o: OuterBuilder = toml::from_str("list = ['x','y']").unwrap();
874
        let o = o.build().unwrap();
875
        assert_eq!(o.list, ['x', 'y']);
876

            
877
        #[derive(Deserialize, Debug)]
878
        struct OuterWithMllb {
879
            #[serde(default)]
880
            list: MultilineListBuilder<u32>,
881
        }
882

            
883
        let parse_ok = |s: &str| {
884
            let o: OuterWithMllb = toml::from_str(s).unwrap();
885
            let l: Option<Vec<_>> = o.list.try_into().unwrap();
886
            l
887
        };
888

            
889
        let l = parse_ok("");
890
        assert!(l.is_none());
891

            
892
        let l = parse_ok("list = []");
893
        assert!(l.unwrap().is_empty());
894

            
895
        let l = parse_ok("list = [12,42]");
896
        assert_eq!(l.unwrap(), [12, 42]);
897

            
898
        let l = parse_ok(r#"list = """#);
899
        assert!(l.unwrap().is_empty());
900

            
901
        let l = parse_ok("list = \"\"\"\n12\n42\n\"\"\"\n");
902
        assert_eq!(l.unwrap(), [12, 42]);
903

            
904
        let e = toml::from_str::<OuterWithMllb>("list = [\"fail\"]")
905
            .unwrap_err()
906
            .to_string();
907
        assert!(dbg!(e).contains(r#"invalid type: string "fail", expected u32"#));
908

            
909
        let o = toml::from_str::<OuterWithMllb>("list = \"\"\"\nfail\n\"\"\"").unwrap();
910
        let l: Result<Option<Vec<_>>, _> = o.list.try_into();
911
        let e = l.unwrap_err().to_string();
912
        assert_eq!(
913
            e,
914
            "multi-line string, line/item 1: could not parse \"fail\": invalid digit found in string"
915
        );
916
    }
917
}