Skip to content
Snippets Groups Projects

Introduce macro for ThingListBuilder, and use for AuthorityListBuilder

Merged Ian Jackson requested to merge Diziet/arti:config-sub-list into main

This is the first part of #447 (closed) which is part of #371 (closed) which is part of #285 (closed)

Edited by Ian Jackson

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
41 /// default = vec![];
42 /// }
43 ///
44 /// let mut thinglist = ThingListBuilder::default();
45 /// thinglist.append(ThingBuilder::default().value(42).clone());
46 /// assert_eq!{ thinglist.build().unwrap().things, &[Thing { value: 42 }] }
47 ///
48 /// thinglist.set(vec![ThingBuilder::default().value(38).clone()]);
49 /// assert_eq!{ thinglist.build().unwrap().things, &[Thing { value: 38 }] }
50 /// ```
51 #[macro_export]
52 macro_rules! define_list_config_builder {
53 {
54 [
55 $($docs_and_attrs:tt)*
56 ]
  • Nick Mathewson
  • Nick Mathewson
    Nick Mathewson @nickm started a thread on an outdated change in commit 0036b916
  • 59 }
    60 built: $Built:ty = $built:expr;
    61 default = $default:expr;
    62 } => {
    63 $($docs_and_attrs)*
    64 #[derive(Default, Clone, Deserialize)]
    65 #[serde(transparent)]
    66 ///
    67 /// This is a builder pattern struct which will be resolved
    68 /// during configuration resolution, via the `build` method.
    69 pub struct $ListBuilder {
    70 /// The list, as overridden
    71 $field_vis $things: Option<Vec<$EntryBuilder>>,
    72 }
    73 impl $ListBuilder {
    74 /// Add one
  • Nick Mathewson
    Nick Mathewson @nickm started a thread on an outdated change in commit 0036b916
  • 60 built: $Built:ty = $built:expr;
    61 default = $default:expr;
    62 } => {
    63 $($docs_and_attrs)*
    64 #[derive(Default, Clone, Deserialize)]
    65 #[serde(transparent)]
    66 ///
    67 /// This is a builder pattern struct which will be resolved
    68 /// during configuration resolution, via the `build` method.
    69 pub struct $ListBuilder {
    70 /// The list, as overridden
    71 $field_vis $things: Option<Vec<$EntryBuilder>>,
    72 }
    73 impl $ListBuilder {
    74 /// Add one
    75 pub fn append(&mut self, item: $EntryBuilder) -> &mut Self {
    • Would "push" be a more idiomatic name for this method?

    • Author Maintainer

      I discussed the name with @eta. My conclusion was that append was better; IIRC @eta didn't have a strong opinion.. We might want to add a prepend at some point, and then push becomes ambiguous (which is why VecDeque has push_front and push_back). Rust stdlib currently uses append mostly for things that are basically the Extend trait and I think this is anomalous.

    • Ian Jackson changed this line in version 8 of the diff

      changed this line in version 8 of the diff

    • Hm; personally I'd expect to find push here. My own thought is that if there's a method that Vec also has, we should probably give it the same name as Vec uses, since every Rust programmer will be familiar with the Vec API.

      On the other hand, all the current use-cases for this kind of type are order-irrelevant: maybe insert would be a better name, to match HashSet.

      I'm not going to insist either way here, since I hope that people will usually not need these APIs at all, so feel free to ignore this if you still disagree.

    • Author Maintainer

      I do think it's worth thinking about the name as we are doing here (ie, I don't regard this conversation as a bikeshed). But I still think append is better than push. So, thanks.

    • Please register or sign in to reply
  • Nick Mathewson
    Nick Mathewson @nickm started a thread on an outdated change in commit 0036b916
  • 68 /// during configuration resolution, via the `build` method.
    69 pub struct $ListBuilder {
    70 /// The list, as overridden
    71 $field_vis $things: Option<Vec<$EntryBuilder>>,
    72 }
    73 impl $ListBuilder {
    74 /// Add one
    75 pub fn append(&mut self, item: $EntryBuilder) -> &mut Self {
    76 self.$things
    77 .get_or_insert_with(|| $default)
    78 .push(item);
    79 self
    80 }
    81
    82 /// Set the list to the supplied one, discarding any previous settings
    83 pub fn set(&mut self, list: impl IntoIterator<Item = $EntryBuilder>) -> &mut Self {
  • Nick Mathewson
    Nick Mathewson @nickm started a thread on commit 0036b916
  • 94 pub fn build(&self) -> Result<$Built, ConfigBuildError> {
    95 let default_buffer;
    96 let $things = match &self.$things {
    97 Some($things) => $things,
    98 None => {
    99 default_buffer = $default;
    100 &default_buffer
    101 }
    102 };
    103 let $things = $things
    104 .iter()
    105 .map(|item| item.build())
    106 .collect::<Result<_, _>>()?;
    107 Ok($built)
    108 }
    109 }
    • Additional methods we might want to add: extend and clear. I don't know if those are necessary now, though.

    • Author Maintainer

      Yes. (After discussion with @eta) I felt it best to leave this for now. clear can be done with replace(vec![]). If we want to add extend we should impl Extend.

      (Also, the semantics of clear aren't super-obvious: does it reset it to "use the default list", or does it mean "definitely use an empty list plus anything I subsequently add". The former can be done with x = default().)

    • Please register or sign in to reply
  • Nick Mathewson
    Nick Mathewson @nickm started a thread on commit 6d7a9e74
  • 140 140 }
    141 141
    142 142 // ----------------------------------------------------------------------
    143
    144 /// Helper for assisting with macro "argument" defaulting
    145 ///
    146 /// ```ignore
    147 /// macro_coalesce_args!{ [ something ] ... } // => something
    • Would "macro_first_nonempty" be a better name for this? To me "coalesce" sounds more like it would concatenate all of the arguments, not take the first nonempty one.

    • Author Maintainer

      I don't have a strong opinion about this. I was borrowing the name from (eg) SQL, and the name for Typescript's ?? aka "nullish coalescing". I'll change it :-).

    • Please register or sign in to reply
  • Nick Mathewson
    Nick Mathewson @nickm started a thread on commit 5d8c067b
  • 17 17 /// nontrivial, you should put the actual defaulting functionality in a (probably-private)
    18 18 /// function, as the macro will expand it twice.
    19 19 ///
    20 /// The `item_build` clause, if supplied, provides a closure with type
    21 /// `FnMut(&ThingBuilder) -> Result<Thing, ConfigBuildErro>`; the default is to call
    22 /// `thing_builder.build()`.
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Please register or sign in to reply
    Loading