1
//! Deriving `NetdocParseable`
2

            
3
use super::*;
4

            
5
//==================== Common definitions used by many of the macros ====================
6

            
7
/// Helper to implemnet `dtrace!` inside `NetdocParseable` derive-deftly macro.
8
#[doc(hidden)]
9
#[allow(clippy::print_stderr)]
10
108
pub fn netdoc_parseable_derive_debug(ttype: &str, msg: &str, vals: &[&dyn Debug]) {
11
    // We use `eprintln!` so that the output is captured as expected under cargo test.
12
    // We buffer the output into a string so that it a;ll appears at once,
13
    // rather than possibly being interleaved with similar output for other types.
14
108
    let mut out = String::new();
15
108
    (|| {
16
108
        write!(out, "netdoc {ttype} parse: {msg}")?;
17
198
        for val in vals {
18
198
            write!(out, ", {val:?}")?;
19
        }
20
108
        writeln!(out)
21
    })()
22
108
    .expect("write to string failed");
23

            
24
108
    eprint!("{out}");
25
108
}
26

            
27
define_derive_deftly_module! {
28
    /// Common definitions for all parsing macros.
29
    NetdocParseAnyCommon beta_deftly:
30

            
31
    // Convenience alias for our prelude
32
    ${define P { $crate::parse2::internal_prelude }}
33

            
34
    // Defines the `dtrace` macro.
35
    ${define DEFINE_DTRACE {
36
        #[allow(unused_macros)]
37
        macro_rules! dtrace { { $$msg:literal $$(, $$val:expr )* $$(,)? } => {
38
          ${if tmeta(netdoc(debug)) {
39
              $P::netdoc_parseable_derive_debug(
40
                  ${concat $ttype},
41
                  $$msg,
42
                  &[ $$( &&$$val as _, )* ],
43
              )
44
          }}
45
        }}
46
    }}
47
}
48

            
49
define_derive_deftly_module! {
50
    /// Common definitions for `NetdocParseable`, `NetdocParseableFields`,
51
    /// and `NetdocParseableSignatures`
52
    ///
53
    /// The including macro is expected to define:
54
    ///
55
    ///  * **`ITEM_STREAM`**: The input `ItemStream<'_>`.
56
    ///
57
    ///  * **`THIS_ITEM`**: consumes the next item and evaluates to it as an `UnparsedItem`.
58
    ///    See the definition in `NetdocParseable`.
59
    ///
60
    ///  * **`F_ACCUMULATE_VAR`** the variable or field into which to accumulate
61
    ///    normal items for this field.  Must be of type `&mut $F_ACCUMULATE_TYPE`.
62
    ///
63
    /// Importer must also import `NetdocSomeItemsDeriveCommon` and `NetdocDeriveAnyCommon`.
64
    NetdocSomeItemsParseableCommon beta_deftly:
65

            
66
    // The effective field type for parsing.
67
    //
68
    // Handles #[deftly(netdoc(default))], in which case we parse as if the field was Option,
69
    // and substitute in the default at the end.
70
    //
71
    ${define F_EFFECTIVE_TYPE {
72
        ${if all(fmeta(netdoc(default))) {
73
            Option::<$ftype>
74
        } else {
75
            $ftype
76
        }}
77
    }}
78

            
79
    // Provide `$<selector_ $fname>` for every (suitable) field.
80
    ${define ITEM_SET_SELECTORS {
81
        $(
82
          ${when not(any(F_FLATTEN, F_SKIP))}
83

            
84
          // See `mod multiplicity`.
85
        ${if not(all(F_INTRO, fmeta(netdoc(with)))) {
86
          // If the intro it has `with`, we don't check its trait impl, and this ends up unused
87
          let $<selector_ $fname> = $F_SELECTOR_VALUE;
88
        }}
89
        )
90
    }}
91
    // The item set selector for this field.
92
    // We must provide this, rather than expanding $<selector_ $fname> at the use sites,
93
    // because the identifier `selector_` has different macro_rules hygiene here vs there!
94
    // TODO derive-deftly#130
95
9104
    ${define F_SELECTOR $<selector_ $fname>}
96
    // The selector value for this field.  Used where we don't want to bind a selector
97
    // for every field with $ITEM_SET_SELECTORS (and within $ITEM_SET_SELECTORS).
98
    ${define F_SELECTOR_VALUE {( MultiplicitySelector::<$F_EFFECTIVE_TYPE>::default() )}}
99
    // Check that every field type implements the necessary trait.
100
    ${define CHECK_FIELD_TYPES_PARSEABLE {
101
        $(
102
          ${when not(any(F_FLATTEN, F_SKIP))}
103

            
104
          // Expands to `selector_FIELD.check_SOMETHING();`
105
          //
106
          // If the relevant trait isn't implemented, rustc reports the error by
107
          // pointing at the `check-something` call.  We re-span that identifier
108
          // to point to the field name, so that's where the error is reported.
109
          //
110
          // Without this, we just get a report that `item` doesn't implement the required
111
          // trait - but `item` is a local variable here, so the error points into the macro
112
        ${if not(all(any(F_INTRO, F_NORMAL), fmeta(netdoc(with)))) {
113
          $<selector_ $fname> . ${paste_spanned $fname ${select1
114
                  any(F_INTRO, F_NORMAL){
115
                      // For the intro item, this is not completely precise, because the
116
                      // it will allow Option<> and Vec<> which aren't allowed there.
117
                      ${if
118
                        fmeta(netdoc(single_arg)) { check_item_argument_parseable }
119
                        else { check_item_value_parseable }
120
                      }
121
                  }
122
                  F_SIGNATURE { check_signature_item_parseable }
123
                  F_SUBDOC    { check_subdoc_parseable         }
124
          }} (
125
              ${if F_SIGNATURE { sig_hashes, }}
126
          );
127
        }}
128
        )
129
    }}
130

            
131
    // Convert the UnparsedItem (in `item` to the value (to accumulate).
132
    // Expands to an expression.
133
    ${define ITEM_VALUE_FROM_UNPARSED {
134
        ${if fmeta(netdoc(with)) {
135
          ${fmeta(netdoc(with)) as path}
136
              ::${paste_spanned $fname from_unparsed}
137
              (item)?
138
        } else if fmeta(netdoc(single_arg)) { {
139
          let item = ItemValueParseable::from_unparsed(item)?;
140
          let (item,) = item;
141
          item
142
        } } else {
143
          ItemValueParseable::from_unparsed(item)?
144
        }}
145
    }}
146

            
147
    // Type into which we accumulate value(s) of this field
148
    ${define F_ACCUMULATE_TYPE {
149
        ${if F_FLATTEN {
150
            <$ftype as $P::NetdocParseableFields>::Accumulator
151
        } else {
152
            Option::<$F_EFFECTIVE_TYPE>
153
        }
154
    }}}
155

            
156
    // Parse the intro item and bind `$fpatname` accumulator for each field.
157
    //
158
    // For the intro item, parse it and bind it to $fpatname.
159
    //
160
    // For other items, set up a mutable $fpatname, initialised to `default()` (normally None).
161
    ${define INIT_ACCUMULATE_VARS {
162
        $( ${select1 F_INTRO {
163

            
164
          let item = input.next_item()?.ok_or(EP::EmptyDocument)?;
165
          dtrace!("intro", item);
166
          if !Self::is_intro_item_keyword(item.keyword()) {
167
              Err(EP::WrongDocumentType)?;
168
          }
169
          let $fpatname: $ftype = $ITEM_VALUE_FROM_UNPARSED;
170

            
171
        } F_SKIP {
172

            
173
        } else {
174

            
175
          let mut $fpatname = $F_ACCUMULATE_TYPE::default();
176

            
177
        }})
178
    }}
179

            
180
    // Accumulates `item` (which must be `ItemSetMethods::Each`) into `$F_ACCUMULATE_VAR`
181
    ${define ACCUMULATE_ITEM_VALUE { {
182
        dtrace!($"accumulating $fname", $F_SELECTOR.item_set_debug());
183
        $F_SELECTOR.${paste_spanned $fname accumulate}($F_ACCUMULATE_VAR, item)?;
184
    } }}
185

            
186
    // Handle a nonstructural field, parsing and accumulating its value
187
    //
188
    // Looks at `kw` for the keyword.
189
    //
190
    // Expands to a series of `if ... { ... } else`.
191
    // The use site must provide (maybe further arms) and a fallback block!
192
    //
193
    // If the item is the intro item for this document, evaluates `break` -
194
    // so if `f_INTRO` is not trivially false, must be expanded within a field loop.
195
    ${define NONSTRUCTURAL_ACCUMULATE_ELSE {
196
        ${for fields {
197
          ${when not(any(F_FLATTEN, F_SUBDOC, F_SKIP))}
198

            
199
          if kw == $F_KEYWORD {
200
            ${select1
201
              F_NORMAL {
202
                let item = $THIS_ITEM;
203
                dtrace!("is normal", item);
204
                let item = $ITEM_VALUE_FROM_UNPARSED;
205
                $ACCUMULATE_ITEM_VALUE
206
              }
207
              F_SIGNATURE {
208
                let hash_inputs = input
209
                      .peek_signature_hash_inputs(signed_doc_body)?
210
                      .expect("not eof, we peeked kw");
211

            
212
                let item = $THIS_ITEM;
213
                dtrace!("is signature", item);
214
                let item = SignatureItemParseable::from_unparsed_and_body(
215
                    item,
216
                    &hash_inputs,
217
                    AsMut::as_mut(sig_hashes),
218
                )?;
219
                $ACCUMULATE_ITEM_VALUE
220
              }
221
              F_INTRO {
222
                dtrace!("is intro", kw);
223
                break;
224
              } // start of next similar document
225
            }
226
          } else
227
        }}
228
        ${for fields {
229
          ${when F_FLATTEN}
230

            
231
          if <$ftype>::is_item_keyword(kw) {
232
              dtrace!(${concat "is flatten in " $fname}, kw);
233
              let item = $THIS_ITEM;
234
              <$ftype as NetdocParseableFields>::accumulate_item($F_ACCUMULATE_VAR, item)?;
235
          } else
236
        }}
237
    }}
238

            
239
    // Completes a document
240
    //
241
    // The fields accumulated so far must be in `$fpatname` (as a value, not a ref,
242
    // and therefore not in $F_ACCUMULATE_VAR).
243
    //
244
    // Expands to code which resolves the fields, and ends with `Ok(document value)`.
245
    ${define FINISH_RESOLVE {
246
        ${for fields {
247
            ${select1
248
              F_INTRO {}
249
              any(F_NORMAL, F_SIGNATURE) {
250
                  let $fpatname = $F_SELECTOR.finish($fpatname, $F_KEYWORD_REPORT)?;
251
              }
252
              F_FLATTEN {
253
                  let $fpatname = <$ftype as NetdocParseableFields>::finish(
254
                      $fpatname,
255
                      $ITEM_STREAM,
256
                  )?;
257
              }
258
              F_SUBDOC {
259
                  let $fpatname = $F_SELECTOR.finish_subdoc($fpatname)?;
260
              }
261
              F_SKIP {
262
                  #[allow(non_snake_case)]
263
                  let $fpatname = Default::default();
264
              }
265
            }
266
        }}
267
        $(
268
            ${when not(any(F_INTRO, F_SKIP))}
269
            // These conditions are mirrored in NetdocSomeItemsEncodableCommon,
270
            // which is supposed to recognise netdoc(default) precisely when we do.
271
          ${if fmeta(netdoc(default)) {
272
            let $fpatname = Option::unwrap_or_default($fpatname);
273
          }}
274
        )
275

            
276
        #[allow(deprecated)]
277
        Ok($vpat)
278
    }}
279
}
280

            
281
//==================== Main whole document parsing impl ====================
282
//
283
// deftly module ` NetdocParseable`:
284
//
285
//   * IMPL_NETDOC_PARSEABLE expanding to `impl NetdocParseable { ... }`
286
//
287
// Much of the heavy lifting is done in the NetdocSomeItemsParseableCommon deftly module.
288

            
289
define_derive_deftly_module! {
290
    /// Provides `IMPL_NETDOC_PARSEABLE` which impls `NetdocParseable`
291
    ///
292
    /// Used by the `NetdocParseable` and `NetdocParseableUnverified` derives.
293
    NetdocParseable beta_deftly:
294

            
295
    use NetdocDeriveAnyCommon;
296
    use NetdocParseAnyCommon;
297
    use NetdocEntireDeriveCommon;
298
    use NetdocSomeItemsDeriveCommon;
299
    use NetdocSomeItemsParseableCommon;
300

            
301
    ${define ITEM_STREAM input}
302
    ${define F_ACCUMULATE_VAR { (&mut $fpatname) }}
303

            
304
  ${define IMPL_NETDOC_PARSEABLE {
305
    impl<$tgens> $P::NetdocParseable for $NETDOC_PARSEABLE_TTYPE {
306
642
        fn doctype_for_error() -> &'static str {
307
            ${tmeta(netdoc(doctype_for_error)) as expr,
308
              default ${concat ${for fields { ${when F_INTRO} $F_KEYWORD_STR }}}}
309
        }
310

            
311
84390
        fn is_intro_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
312
            use $P::*;
313

            
314
            ${for fields {
315
                ${when F_INTRO}
316
                ${loop_exactly_1 "internal error, somehow not exactly one intro item!"}
317
                kw == $F_KEYWORD
318
            }}
319
        }
320

            
321
412
        fn is_structural_keyword(kw: $P::KeywordRef<'_>) -> Option<$P::IsStructural> {
322
            #[allow(unused_imports)] // not used if there are no subdocs
323
            use $P::*;
324

            
325
            if Self::is_intro_item_keyword(kw) {
326
                return Some(IsStructural)
327
            }
328

            
329
            ${for fields {
330
                ${when F_SUBDOC}
331
                if let y @ Some(_) = $F_SELECTOR_VALUE.is_structural_keyword(kw) {
332
                    return y;
333
                }
334
            }}
335

            
336
            None
337
        }
338

            
339
        //##### main parsing function #####
340

            
341
        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
342
1464
        fn from_items<'s>(
343
1464
            input: &mut $P::ItemStream<'s>,
344
1464
            outer_stop: $P::stop_at!(),
345
1464
        ) -> $P::Result<Self, $P::ErrorProblem> {
346
            use $P::*;
347
            $DEFINE_DTRACE
348
            $FIELD_ORDERING_CHECK
349

            
350
            //----- prepare item set selectors for every field -----
351
            $ITEM_SET_SELECTORS
352
            $CHECK_FIELD_TYPES_PARSEABLE
353

            
354
            // Is this an intro item keyword ?
355
            //
356
            // Expands to an appropriate `is_intro_item_keyword` method invocation,
357
            // but *without arguments*.  So, something a bit like an expression of type
358
            //    fn(KeywordRef) -> bool
359
            ${define F_SUBDOC_IS_INTRO_ITEM_KEYWORD {
360
                ${if not(F_SUBDOC) { ${error "internal-error: subdoc kw, but not subdoc field"} }}
361
9104
                $F_SELECTOR.is_intro_item_keyword
362
            }}
363

            
364
            //----- Helper fragments for parsing individual pieces of the document -----
365

            
366
            // Peeks a keyword, and returns it but only if it's part of this (sub)doc.
367
            // Return `None` if it was in outer_stop
368
10772
            let peek_keyword = |input: &mut ItemStream<'s>| -> Result<Option<KeywordRef<'s>>, EP> {
369
                let Some(kw) = input.peek_keyword()? else {
370
                    dtrace!("stopping, because EOF");
371
                    return Ok(None)
372
                };
373
                if outer_stop.stop_at(kw) {
374
                    dtrace!("stopping, because peeked", kw);
375
                    return Ok(None)
376
                }
377
                Ok(Some(kw))
378
            };
379

            
380
            // Returns the actual item as an UnparsedItem, committing to consuming it.
381
            // Can panic if called without previous `peek_keyword`.
382
            ${define THIS_ITEM  {
383
                input.next_item()?.expect("peeked")
384
            }}
385

            
386
            //----- keyword classification closures -----
387

            
388
            // Is this a keyword for one of our sub-documents?
389
            let is_subdoc_kw = ${for fields {
390
                ${when F_SUBDOC}
391
                StopAt(|kw: KeywordRef<'_>| $F_SUBDOC_IS_INTRO_ITEM_KEYWORD(kw)) |
392
              }}
393
                StopAt(false)
394
            ;
395
            // Is this a keyword for one of our parents or sub-documents?
396
            let inner_stop = outer_stop | is_subdoc_kw;
397

            
398
            //========== actual parsing ==========
399

            
400
            // For each parsing loop/section, where we aren't looking for precisely one thing,
401
            // we should explicitly decide what to do with each of:
402
            //   - F_INTRO - intro item for this document (maybe next instance in parent)
403
            //   - F_NORMAL - normal items
404
            //   - subdocuments, is_subdoc_kw and F_SUBDOC
405
            //   - our parent's structural keywords, outer_stop
406
            //     (this includes signature items for the signed version of this doc)
407
            // 5 cases in all.
408

            
409
            //----- Parse the intro item, and introduce bindings for the other items. -----
410

            
411
            dtrace!("looking for intro item");
412
            $INIT_ACCUMULATE_VARS
413

            
414
            //----- Parse the normal items -----
415
            dtrace!("looking for normal items");
416

            
417
            while let Some(kw) = peek_keyword(input)? {
418
                dtrace!("for normal, peeked", kw);
419
                if inner_stop.stop_at(kw) {
420
                    dtrace!("is inner stop", kw);
421
                    break;
422
                };
423

            
424
                $NONSTRUCTURAL_ACCUMULATE_ELSE
425
                {
426
                    dtrace!("is unknown (in normal)");
427
                    let _: UnparsedItem = $THIS_ITEM;
428
                }
429
            }
430

            
431
            //----- Parse the subdocs, in order -----
432
            dtrace!("looking for subdocs");
433

            
434
          ${for fields {
435
            ${when F_SUBDOC}
436
            dtrace!("looking for subdoc", $F_KEYWORD_REPORT);
437

            
438
            loop {
439
                let Some(kw) = peek_keyword(input)? else { break };
440
                dtrace!("for subdoc, peek", kw);
441

            
442
                if !$F_SUBDOC_IS_INTRO_ITEM_KEYWORD(kw) {
443
                    dtrace!("is not this subdoc", kw);
444
                    break;
445
                };
446

            
447
                $F_SELECTOR.can_accumulate(&mut $fpatname)?;
448

            
449
                dtrace!("is this subdoc", kw);
450
                let item = NetdocParseable::from_items(input, inner_stop);
451
                dtrace!("parsed this subdoc", item.as_ref().map(|_| ()));
452
                let item = item?;
453

            
454
                $ACCUMULATE_ITEM_VALUE
455
            }
456
          }}
457

            
458
            // Resolve all the fields
459
            dtrace!("reached end, resolving");
460

            
461
            $FINISH_RESOLVE_PARSEABLE
462
        }
463
    }
464
  }}
465
}
466

            
467
//==================== NetdocParseable user-facing derive macro ====================
468
//
469
// deftly template `NetdocParseable`:
470
//
471
//  * main entrypoint for deriving the `NetdocParseable` trait
472
//  * docs for the meta attributes we support during document parsing
473
//
474
// The actual implementation is in  the `NetdocParseable` deftly module, above.
475

            
476
define_derive_deftly! {
477
    use NetdocParseable;
478

            
479
    /// Derive [`NetdocParseable`] for a document (or sub-document)
480
    ///
481
    // NB there is very similar wording in the NetdocEncodable derive docs.
482
    // If editing any of this derive's documentation, considering editing that too.
483
    //
484
    /// ### Expected input structure
485
    ///
486
    /// Should be applied named-field struct, where each field is
487
    /// an Item which may appear in the document,
488
    /// or a sub-document.
489
    ///
490
    /// The first field will be the document's intro Item.
491
    /// The expected Keyword for each Item will be kebab-case of the field name.
492
    ///
493
    /// ### Field type
494
    ///
495
    /// Each field must be
496
    ///  * `impl `[`ItemValueParseable`] for an "exactly once" field,
497
    ///  * `Vec<T: ItemValueParseable>` for "zero or more", or
498
    ///  * `BTreeSet<T: ItemValueParseable + Ord>`, or
499
    ///  * `Option<T: ItemValueParseable>` for "zero or one".
500
    ///
501
    /// We don't directly support "at least once":
502
    /// the parsed network document doesn't imply the invariant
503
    /// that at least one such item was present.
504
    // We could invent a `NonemptyVec` or something for this.
505
    ///
506
    /// (This is implemented via types in the [`multiplicity`] module,
507
    /// specifically [`ItemSetSelector`].)
508
    ///
509
    /// ### Signed documents
510
    ///
511
    /// To handle signed documents:
512
    ///
513
    ///  * Define `struct Foo`, containing only the content, not the signatures.
514
    ///    Derive [`NetdocParseableUnverified`](crate::derive_deftly_template_NetdocParseableUnverified).
515
    ///  * Define `struct FooSignatures`, containing only the signatures.
516
    ///    Derive `NetdocParseableSignatures`.
517
    ///
518
    ///  * Implement a suitable `FooUnverified::verify`.
519
    ///    See [`NetdocParseableUnverified`](crate::derive_deftly_template_NetdocParseableUnverified)
520
    ///    for guidance.
521
    ///
522
    /// Don't mix signature items with non-signature items in the same struct.
523
    /// (This wouldn't compile, because the field type would implement the wrong trait.)
524
    ///
525
    /// ### Top-level attributes:
526
    ///
527
    /// * **`#[deftly(netdoc(doctype_for_error = EXPRESSION))]`**:
528
    ///
529
    ///   Specifies the value to be returned from
530
    ///   [`NetdocParseable::doctype_for_error`].
531
    ///
532
    ///   Note, must be an expression, so for a literal, nested `""` are needed.
533
    ///
534
    ///   The default is the intro item keyword.
535
    ///
536
    /// * **`#[deftly(netdoc(debug))]`**:
537
    ///
538
    ///   The generated implementation will generate copious debug output
539
    ///   to the program's stderr when it is run.
540
    ///   Do not enable in production!
541
    ///
542
    /// ### Field-level attributes:
543
    ///
544
    /// * **`#[deftly(netdoc(keyword = STR))]`**:
545
    ///
546
    ///   Use `STR` as the Keyword for this Item.
547
    ///
548
    /// * **`#[deftly(netdoc(single_arg))]`**:
549
    ///
550
    ///   The field type implements `ItemArgumentParseable`,
551
    ///   instead of `ItemValueParseable`,
552
    ///   and is parsed as if `(FIELD_TYPE,)` had been written.
553
    ///
554
    /// * **`#[deftly(netdoc(with = MODULE))]`**:
555
    ///
556
    ///   Instead of `ItemValueParseable`, the item is parsed with `MODULE::from_unparsed`,
557
    ///   which must have the same signature as [`ItemValueParseable::from_unparsed`].
558
    ///
559
    ///   (Not supported for sub-documents, signature items, or field collections.)
560
    ///
561
    /// * **`#[deftly(netdoc(default))]`**:
562
    ///
563
    ///   This field is optional ("at most once");
564
    ///   if not present, `FIELD_TYPE::default()` will be used.
565
    ///
566
    ///   This is an alternative to declaring the field type as `Option`
567
    ///   With `netdoc(default)`, the field value doesn't need unwrapping.
568
    ///   With `Option` it is possible to see if the field was provided.
569
    ///
570
    /// * **`#[deftly(netdoc(flatten))]`**:
571
    ///
572
    ///   This field is a struct containing further individual normal fields.
573
    ///   The Items for those individual fields can appear in *this*
574
    ///   outer document in any order, interspersed with other normal fields.
575
    ///
576
    ///   The field type must implement [`NetdocParseableFields`].
577
    ///
578
    /// * **`#[deftly(netdoc(skip))]`**:
579
    ///
580
    ///   This field doesn't really appear in the network document.
581
    ///   It won't be recognised during parsing.
582
    ///   Instead, `Default::default()` will be used for the field value.
583
    ///
584
    /// * **`#[deftly(netdoc(subdoc))]`**:
585
    ///
586
    ///   This field is a sub-document.
587
    ///   The value type `T` must implement [`NetdocParseable`]
588
    ///   *instead of* `ItemValueParseable`.
589
    ///
590
    ///   The field name is not used for parsging;
591
    ///   the sub-document's intro keyword is used instead.
592
    ///
593
    ///   Sub-documents are expected to appear after all normal items,
594
    ///   in the order presented in the struct definition.
595
    ///
596
    /// # Example
597
    ///
598
    /// ```
599
    /// use derive_deftly::Deftly;
600
    /// use tor_checkable::{Timebound, timed::TimerangeBound};
601
    /// use tor_netdoc::derive_deftly_template_AsMutSelf;
602
    /// use tor_netdoc::derive_deftly_template_NetdocParseableSignatures;
603
    /// use tor_netdoc::derive_deftly_template_NetdocParseableUnverified;
604
    /// use tor_netdoc::derive_deftly_template_ItemValueParseable;
605
    /// use tor_netdoc::parse2::{
606
    ///     parse_netdoc, ErrorProblem, ParseInput, VerifyFailed,
607
    ///     SignatureItemParseable, SignatureHashesAccumulator, SignatureHashInputs,
608
    /// };
609
    ///
610
    /// #[derive(Deftly, Debug, Clone)]
611
    /// #[derive_deftly(NetdocParseableUnverified)]
612
    /// pub struct NdThing {
613
    ///     pub thing_start: (),
614
    ///     pub value: (String,),
615
    /// }
616
    ///
617
    /// #[derive(Deftly, Debug, Clone)]
618
    /// #[derive_deftly(NetdocParseableSignatures)]
619
    /// #[deftly(netdoc(signatures(hashes_accu = UseLengthAsFoolishHash)))]
620
    /// pub struct NdThingSignatures {
621
    ///     pub signature: FoolishSignature,
622
    /// }
623
    ///
624
    /// #[derive(Deftly, Debug, Clone)]
625
    /// #[derive_deftly(ItemValueParseable)]
626
    /// #[deftly(netdoc(signature(hash_accu = UseLengthAsFoolishHash)))]
627
    /// pub struct FoolishSignature {
628
    ///     pub doc_len: usize,
629
    /// }
630
    ///
631
    /// #[derive(Deftly, Debug, Default, Clone)]
632
    /// #[derive_deftly(AsMutSelf)]
633
    /// pub struct UseLengthAsFoolishHash {
634
    ///     pub doc_len_actual_pretending_to_be_hash: Option<usize>,
635
    /// }
636
    /// impl SignatureHashesAccumulator for UseLengthAsFoolishHash {
637
    ///     fn update_from_netdoc_body(
638
    ///         &mut self,
639
    ///         document_body: &SignatureHashInputs<'_>,
640
    ///     ) -> Result<(), ErrorProblem> {
641
    ///         self
642
    ///             .doc_len_actual_pretending_to_be_hash
643
    ///             .get_or_insert_with(|| document_body.body().body().len());
644
    ///         Ok(())
645
    ///     }
646
    /// }
647
    ///
648
    /// let doc_text =
649
    /// r#"thing-start
650
    /// value something
651
    /// signature 28
652
    /// "#;
653
    ///
654
    /// impl NdThingUnverified {
655
    ///     pub fn verify_foolish(self) -> Result<TimerangeBound<NdThing>, VerifyFailed> {
656
    ///         // See docs for derive_deftly_template_NetdocParseableUnverified
657
    ///         // for how to write a verify function.
658
    ///
659
    ///         let sig = &self.sigs.sigs.signature;
660
    ///         let hash = self.sigs.hashes.doc_len_actual_pretending_to_be_hash
661
    ///             .as_ref().ok_or(VerifyFailed::Bug)?;
662
    ///         if sig.doc_len != *hash {
663
    ///             return Err(VerifyFailed::VerifyFailed);
664
    ///         }
665
    ///         let foolish_lack_of_validity_time_info = ..;
666
    ///         let body = TimerangeBound::new(self.body, foolish_lack_of_validity_time_info);
667
    ///         Ok(body)
668
    ///     }
669
    /// }
670
    ///
671
    /// let input = ParseInput::new(&doc_text, "<input>");
672
    /// let doc: NdThingUnverified = parse_netdoc(&input).unwrap();
673
    /// let doc = doc.verify_foolish().unwrap().dangerously_assume_timely();
674
    /// assert_eq!(doc.value.0, "something");
675
    /// ```
676
    export NetdocParseable for struct, meta_quoted rigorous, expect items, beta_deftly:
677

            
678
    ${define NETDOC_PARSEABLE_TTYPE { $ttype }}
679
    ${define FINISH_RESOLVE_PARSEABLE $FINISH_RESOLVE}
680

            
681
    $IMPL_NETDOC_PARSEABLE
682
}
683

            
684
//==================== NetdocParseableSignatures user-facing derive macro ====================
685
//
686
// deftly template `NetdocParseableSignatures`:
687
//
688
//  * entrypoint for deriving the `NetdocParseableSignatures` trait
689
//  * docs for the signatures-section-specific attributes
690
//  * implementation of that derive
691
//
692
// Much of the heavy lifting is done in the NetdocSomeItemsParseableCommon deftly module.
693

            
694
define_derive_deftly! {
695
    use NetdocDeriveAnyCommon;
696
    use NetdocParseAnyCommon;
697
    use NetdocSomeItemsDeriveCommon;
698
    use NetdocSomeItemsParseableCommon;
699

            
700
    /// Derive [`NetdocParseable`] for the signatures section of a network document
701
    ///
702
    /// This type is the signatures section of another document.
703
    /// Signature sections have no separate intro keyword:
704
    /// every field is structural and they are recognised in any order.
705
    ///
706
    /// This signatures sub-document will typically be included in a
707
    /// `FooUnverified` struct derived with
708
    /// [`NetdocParseableUnverified`](crate::derive_deftly_template_NetdocParseableUnverified),
709
    /// rather than included anywhere manually.
710
    ///
711
    /// ### Expected input structure
712
    ///
713
    /// Should be applied named-field struct, where each field
714
    /// implements [`SignatureItemParseable`],
715
    /// or is a `SignatureItemParseable` in `Vec` or `BTreeSet` or `Option`.
716
    ///
717
    /// ### Attributes
718
    ///
719
    ///  * The following top-level attributes are supported:
720
    ///    `#[deftly(netdoc(debug))]`
721
    ///
722
    ///  * The following field-level attributes are supported:
723
    ///    `#[deftly(netdoc(keyword = STR))]`
724
    ///    `#[deftly(netdoc(default))]`
725
    ///    `#[deftly(netdoc(single_arg))]`
726
    ///    `#[deftly(netdoc(with = MODULE))]`
727
    ///    `#[deftly(netdoc(flatten))]`
728
    ///    `#[deftly(netdoc(skip))]`
729
    ///
730
    /// ### Signature item ordering, and signatures covering signatures
731
    ///
732
    /// The derived code does not impose any mutual ordering of signatures.
733
    /// If signatures are independent, hashing can be done with [`SignedDocumentBody`]
734
    /// (from [`SignatureHashInputs::body`]).
735
    ///
736
    /// In sane netdoc signature scheme, no signatures would cover other signatures,
737
    /// and there would be no ordering requirement on signatures on the same document.
738
    ///  A relying party would verify the signatures that they are proposing to rely on
739
    /// (which would generally include signatures for *one* algorithm, not several)
740
    /// and ignore the others.
741
    ///
742
    /// (Such a signature, which also does not include any of its own item encoding
743
    /// in its hash, is called Orderly.  See [SignedDocumentBody].)
744
    ///
745
    /// Unfortunately, many Tor netdocs have signature schemes
746
    /// which are not sane (by this definition).
747
    ///
748
    /// When signatures are specified to cover other signatures,
749
    /// the signature item implementation must contain ad-hoc code in
750
    /// [`SignatureItemParseable::from_unparsed_and_body`].
751
    /// to hash not only the body, but also the prior signatures.
752
    /// Methods on [`SignatureHashInputs`] are available to get
753
    /// the relevant parts of the input document text
754
    /// (eg, [`document_sofar`](SignatureHashInputs::document_sofar)).
755
    ///
756
    /// When the spec states a required ordering on signature items,
757
    /// this should be enforced by ad-hoc code in implementation(s) of
758
    /// `SignatureItemParseable`.
759
    /// The implementation should use
760
    /// [`HashAccu`](SignatureItemParseable::HashAccu)
761
    /// to store any necessary state.
762
    /// Usually, this can be achieved by using the same Rust struct for the
763
    /// `HashAccu` of each of the signature items:
764
    /// that will make the signature hashes computed so far, for items seen so far,
765
    /// visible to subsequent items;
766
    /// the subsequent items can check that the prior items filled in the hash,
767
    /// thus imposing an ordering.
768
    ///
769
    /// Alternatively, the ordering could be enforced in the user-supplied
770
    /// ad-hoc `verify` function(s) on `FooUUnverified`.
771
    ///
772
    /// Note that this enforcement should be done for protocol compliance
773
    /// and availability reasons, but is not a security issue.
774
    /// There is not a security risk from accepting documents some of whose signatures
775
    /// aren't covered by other signatures even though the protocol specifies they should be:
776
    /// relying parties *verify* the signatures but do not treat them as trusted data.
777
    /// So there is no engineered safeguard against failing to implement
778
    /// signature item ordering checks.
779
    export NetdocParseableSignatures for struct, meta_quoted rigorous, expect items, beta_deftly:
780

            
781
    ${defcond F_INTRO false}
782
    ${defcond F_SUBDOC false}
783
    ${defcond F_SIGNATURE true}
784

            
785
    // NetdocParseableSignatures::HashesAccu
786
    ${define SIGS_HASHES_ACCU_TYPE { ${tmeta(netdoc(signatures(hashes_accu))) as ty} }}
787

            
788
    ${define ITEM_STREAM input}
789
    ${define THIS_ITEM { input.next_item()?.expect("peeked") }}
790
    ${define F_ACCUMULATE_VAR { (&mut $fpatname) }}
791

            
792
    impl<$tgens> $P::NetdocParseableSignatures for $ttype {
793
        type HashesAccu = $SIGS_HASHES_ACCU_TYPE;
794

            
795
39020
        fn is_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
796
            use $P::*;
797
            ${for fields {
798
38980
                kw == $F_KEYWORD ||
799
            }}
800
37602
                false
801
39020
        }
802

            
803
        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
804
998
        fn from_items<'s>(
805
998
            input: &mut $P::ItemStream<'s>,
806
998
            signed_doc_body: $P::SignedDocumentBody<'s>,
807
998
            sig_hashes: &mut $SIGS_HASHES_ACCU_TYPE,
808
998
            outer_stop: $P::stop_at!(),
809
998
        ) -> $P::Result<$ttype, $P::ErrorProblem> {
810
            use $P::*;
811
            $DEFINE_DTRACE
812

            
813
            //----- prepare item set selectors for every field -----
814
            $ITEM_SET_SELECTORS
815
            $CHECK_FIELD_TYPES_PARSEABLE
816
            $INIT_ACCUMULATE_VARS
817

            
818
            //----- parse the items -----
819
            dtrace!("looking for signature items");
820

            
821
2112
            while let Some(kw) = input.peek_keyword()? {
822
                dtrace!("for signatures, peeked", kw);
823
2002
                if outer_stop.stop_at(kw) {
824
                    dtrace!("is outer stop", kw);
825
888
                    break;
826
1114
                };
827

            
828
                $NONSTRUCTURAL_ACCUMULATE_ELSE
829
                {
830
                    dtrace!("is unknown (in signatures)");
831
                    let _: UnparsedItem = $THIS_ITEM;
832
                }
833
            }
834

            
835
            // Resolve all the fields
836
            dtrace!("reached end, resolving");
837

            
838
            $FINISH_RESOLVE
839
998
        }
840
    }
841
}
842

            
843
//==================== NetdocParseableFields user-facing derive macro ====================
844
//
845
// deftly template `NetdocParseableFields`
846
//
847
//  * entrypoint for deriving the `NetdocParseableFields` trait
848
//  * docs and implementation for that derive
849
//
850
// Much of the heavy lifting is done in the NetdocSomeItemsParseableCommon deftly module.
851

            
852
define_derive_deftly! {
853
    use NetdocDeriveAnyCommon;
854
    use NetdocParseAnyCommon;
855
    use NetdocFieldsDeriveCommon;
856
    use NetdocSomeItemsDeriveCommon;
857
    use NetdocSomeItemsParseableCommon;
858

            
859
    /// Derive [`NetdocParseableFields`] for a struct with individual items
860
    ///
861
    /// Defines a struct `FooNetdocParseAccumulator` to be the
862
    /// `NetdocParseableFields::Accumulator`.
863
    ///
864
    /// Similar to
865
    /// [`#[derive_deftly(NetdocParseable)]`](derive_deftly_template_NetdocParseable),
866
    /// but:
867
    ///
868
    ///  * Derives [`NetdocParseableFields`]
869
    $DOC_NETDOC_FIELDS_DERIVE_SUPPORTED
870
    ///
871
    export NetdocParseableFields for struct , meta_quoted rigorous, expect items, beta_deftly:
872

            
873
    ${define ITEM_STREAM items}
874
    ${define THIS_ITEM item}
875
    ${define F_ACCUMULATE_VAR { (&mut acc.$fname) }}
876

            
877
    #[doc = ${concat "Partially parsed `" $tname "`"}]
878
    ///
879
    /// Used for [`${concat $P::NetdocParseableFields::Accumulator}`].
880
    #[derive(Default, Debug)]
881
    $tvis struct $<$tname NetdocParseAccumulator><$tdefgens> { $(
882
        $fname: $F_ACCUMULATE_TYPE,
883
    ) }
884

            
885
    impl<$tgens> $P::NetdocParseableFields for $ttype {
886
        type Accumulator = $<$ttype NetdocParseAccumulator>;
887

            
888
748
        fn is_item_keyword(
889
748
            #[allow(unused_variables)] // If there are no fields, this is unused
890
748
            kw: $P::KeywordRef<'_>,
891
748
        ) -> bool {
892
            #[allow(unused_imports)] // false positives in some situations
893
            use $P::*;
894

            
895
          ${for fields {
896
            ${when not(F_FLATTEN)}
897
            ${when not(F_SKIP)}
898
460
            kw == $F_KEYWORD ||
899
          }}
900
          ${for fields {
901
            ${when F_FLATTEN}
902
            ${when not(F_SKIP)}
903
12
            <$ftype as NetdocParseableFields>::is_item_keyword(kw) ||
904
          }}
905
104
            false
906
748
        }
907

            
908
        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
909
568
        fn accumulate_item(
910
568
            #[allow(unused_variables)] // If there are no fields, this is unused
911
568
            acc: &mut Self::Accumulator,
912
568
            #[allow(unused_variables)] // If there are no fields, this is unused
913
568
            item: $P::UnparsedItem<'_>,
914
568
        ) -> $P::Result<(), $P::ErrorProblem> {
915
            #[allow(unused_imports)] // false positives in some situations
916
            use $P::*;
917
            $DEFINE_DTRACE
918

            
919
            $ITEM_SET_SELECTORS
920
            $CHECK_FIELD_TYPES_PARSEABLE
921

            
922
            #[allow(unused_variables)] // If there are no fields, this is unused
923
568
            let kw = item.keyword();
924

            
925
            $NONSTRUCTURAL_ACCUMULATE_ELSE
926
            {
927
                panic!("accumulate_item called though is_item_keyword returns false");
928
            }
929

            
930
            #[allow(unreachable_code)] // If there are no fields!
931
            #[allow(deprecated)]
932
568
            Ok(())
933
568
        }
934

            
935
318
        fn finish(
936
318
            #[allow(unused_variables)] // If there are no fields, this is unused
937
318
            acc: Self::Accumulator,
938
318
            #[allow(unused_variables)] // often unused
939
318
            items: &$P::ItemStream<'_>,
940
318
        ) -> $P::Result<Self, $P::ErrorProblem> {
941
            #[allow(unused_imports)] // false positives in some situations
942
            use $P::*;
943
            $DEFINE_DTRACE
944

            
945
            dtrace!("finish, resolving");
946

            
947
            $ITEM_SET_SELECTORS
948

            
949
         $(
950
            ${when not(F_SKIP)}
951
306
            let $fpatname = acc.$fname;
952
         )
953
            $FINISH_RESOLVE
954
318
        }
955
    }
956
}
957

            
958
//==================== NetdocParseableUnverified user-facing derive macro ====================
959
//
960
// deftly template `NetdocParseableUnverified`
961
//
962
//  * entrypoint for deriving the `FooUnverified` struct implementing `NetdocParseable`
963
//    (and supporting items such as `FooUnverifiedParsedBody` structs and its impl).
964
//  * docs for that derive, including doc-level signatures-related attributes
965
//  * implementation glue for those derived impls
966
//
967
// The principal derived parsing impl on the body type `Foo` is expanded by this macro,
968
// but that is implemented via IMPL_NETDOC_PARSEABLE in the NetdocParseable deftly module.
969
//
970
// The substantive code to implement `NetdocParseable` for `FooUnverified` is
971
// in the `ItemStream::parse_signed` helper function; a call to that is expanded here.
972

            
973
define_derive_deftly! {
974
    use NetdocParseable;
975

            
976
    /// Derive `NetdocParseable` for a top-level signed document
977
    ///
978
    /// ### Expected input structure
979
    ///
980
    /// Apply this derive to the main body struct `Foo`,
981
    /// which should meet all the requirements to derive
982
    /// [`NetdocParseable`](derive_deftly_template_NetdocParseable).
983
    ///
984
    /// Usually, the caller will provide suitable ad-hoc `.verify_...` methods
985
    /// on `FooUnverified`.
986
    ///
987
    /// The `verify` method should:
988
    ///
989
    ///   * Take as an argument(s) the expected (trustworthy) signer(s),
990
    ///     (if the document is not always just supposed to be self-signed).
991
    ///
992
    ///   * Work directly with the fields `body` and `sigs` in `FooUnverified`.
993
    ///
994
    ///   * Verify all the signatures, including any [`EmbeddedCert`]s in the body.
995
    ///
996
    ///   * Cross-check any information that is supposed to be duplicated.
997
    ///
998
    ///   * Determine the validity period, from the validity time
999
    ///     information contained in the document or signatures.
    ///
    ///   * Return `TimeRangebound<Foo>`.
    ///
    /// ### Generated code
    ///
    /// Supposing your input structure is `Foo`, this macro will
    /// generate a **`struct FooUnverified`**
    /// implementing [`NetdocParseable`] and [`NetdocParseableUnverified`]:
    ///
    /// ```rust,ignore
    /// # struct Foo; struct FooSignatures;
    /// pub struct FooUnverified {
    ///     body: Foo,
    ///     pub sigs: SignaturesData<FooUnverified>,
    /// }
    /// ```
    ///
    /// Also generated is `FooUnverifiedParsedBody`
    /// and an impl of [`HasUnverifiedParsedBody`] on `Foo`.
    /// These allow the generated code to call [`ItemStream::parse_signed`]
    /// and it should not normally be necessary to use them elsewhere.
    ///
    /// ### Required top-level attributes:
    ///
    /// * **`#[deftly(netdoc(signature = TYPE))]`**:
    ///   Type of the signature(s) section.
    ///
    ///   TYPE must implement `NetdocParseable`,
    ///   with `is_intro_item_keyword` reporting *every* signature keyword.
    ///   Normally this is achieved with
    ///   `#[derive_deftly(NetdocParseable)] #[deftly(netdoc(signatures))]`.
    ///
    /// ### Optional attributes
    ///
    /// All the attributes supported by the `NetdocParseable` derive are supported.
    //
    // We don't make NetdocParseableUnverified a generic struct because
    //  - the defining module (crate) will want to add verification methods,
    //    which means they must define the struct
    //  - that lets the actual `body` field be private to the defining module.
    export NetdocParseableUnverified for struct, meta_quoted rigorous, expect items, beta_deftly:
    ${define NETDOC_PARSEABLE_TTYPE { $<$ttype UnverifiedParsedBody> }}
    ${define FINISH_RESOLVE_PARSEABLE {
        { $FINISH_RESOLVE }
998
        .map(|unverified| $<$tname UnverifiedParsedBody> { unverified })
    }}
    $IMPL_NETDOC_PARSEABLE
    // FooSignatures (type name)
    ${define SIGS_TYPE { $< ${tmeta(netdoc(signatures)) as ty, default $<$ttype Signatures>} > }}
    ${define SIGS_DATA_TYPE { $P::SignaturesData<$<$ttype Unverified>> }}
    ${define SIGS_HASHES_ACCU_TYPE { <$SIGS_TYPE as $P::NetdocParseableSignatures>::HashesAccu }}
   $///Signed (unverified) form of [`$tname`]
    ///
    /// Embodies:
    ///
   $///  * **[`$tname`]**: document body
   $///  * **[`$SIGS_TYPE`]**: signatures
    ///
    /// If this type was parsed from a document text,
    /// the signatures have *not* yet been verified.
    ///
    /// Use a `.verify_...` method to obtain useable, verified, contents.
    #[derive(Debug, Clone)]
    $tvis struct $<$ttype Unverified> {
        /// The actual body
        //
        // Misuse is prevented by this field not being public.
        // It can be accessed only in this module, where the verification functions are.
        body: $ttype,
        /// Signatures
        $tvis sigs: $SIGS_DATA_TYPE,
    }
    /// The parsed but unverified body part of a signed network document (working type)
    ///
   $/// Contains a $tname which has been parsed
    /// as part of a signed document,
    /// but the signatures aren't embodied here, and have not been verified.
    ///
    /// Not very useful to callers, who should use the `BodyUnverified` type instead,
    /// and its implementation of `NetdocParseable`.
    //
    // We implement NetdocParseable on FooUnverified using ItemStream::parse_signed.
    // ItemStream::parse_signed is a fairly normal but ad-hoc
    // implementation of NetdocParseable which uses as subroutines implementations
    // of NetdocParseable for the body and NetdocParseableSignatures for the signatures.
    //
    // We need a newtype because we don't want to implement `NetdocParseable`
    // for a type which is just the body.  Such an impl would be usable by mistake,
    // via the top-level parse2 functions, and it would then simply discard the signatures
    // and return unverified data, bypassing our efforts to prevent such bugs.
    //
    // Ideally we would have a generic `UnverifiedParsedBody<B>` type or something
    // but then this macro, invoked in other crates, couldn't impl NetdocParseable for
    // UnverifiedParsedBody<TheirType>, due to trait coherence rules.
    //
    #[derive(derive_more::From)]
    pub struct $NETDOC_PARSEABLE_TTYPE<$tdefgens> {
        /// The unverified body
        unverified: $ttype,
    }
    impl<$tgens> $P::NetdocParseable for $<$ttype Unverified> {
2
        fn doctype_for_error() -> &'static str {
            $NETDOC_PARSEABLE_TTYPE::doctype_for_error()
2
        }
        fn is_intro_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
            $NETDOC_PARSEABLE_TTYPE::is_intro_item_keyword(kw)
        }
        fn is_structural_keyword(kw: $P::KeywordRef<'_>) -> Option<$P::IsStructural> {
            $NETDOC_PARSEABLE_TTYPE::is_structural_keyword(kw).or_else(
                || <$SIGS_TYPE as $P::NetdocParseableSignatures>
                    ::is_item_keyword(kw).then_some($P::IsStructural)
            )
        }
1000
        fn from_items<'s>(
1000
            input: &mut $P::ItemStream<'s>,
1000
            outer_stop: $P::stop_at!(),
1000
        ) -> $P::Result<$<$ttype Unverified>, $P::ErrorProblem> {
            $EMIT_DEBUG_PLACEHOLDER
1000
            input.parse_signed(outer_stop)
1000
        }
    }
    impl<$tgens> $P::NetdocParseableUnverified for $<$ttype Unverified> {
        type Body = $ttype;
        type Signatures = $SIGS_TYPE;
920
        fn inspect_unverified(&self) -> (&Self::Body, &$SIGS_DATA_TYPE) {
920
            (&self.body, &self.sigs)
920
        }
72
        fn unwrap_unverified(self) -> (Self::Body, $SIGS_DATA_TYPE) {
72
            (self.body, self.sigs)
72
        }
1006
        fn from_parts(body: Self::Body, sigs: $SIGS_DATA_TYPE) -> Self {
1006
            Self { body, sigs }
1006
        }
    }
    impl<$tgens> $P::HasUnverifiedParsedBody for $ttype {
        type UnverifiedParsedBody = $NETDOC_PARSEABLE_TTYPE;
998
        fn unverified_into_inner_unchecked(unverified: Self::UnverifiedParsedBody) -> Self {
998
            unverified.unverified
998
        }
    }
}
//==================== ItemValueParseable user-facing derive macro ====================
//
// deftly template `ItemValueParseable`
//
//  * entrypoint for deriving the `ItemValueParseable` and `SignatureItemParseable` traits
//  * docs for the meta attributes we support during *item* parsing
//  * implementation of those derives
define_derive_deftly! {
    use NetdocDeriveAnyCommon;
    use NetdocParseAnyCommon;
    use NetdocItemDeriveCommon;
    /// Derive `ItemValueParseable` (or `SignatureItemParseable`)
    ///
    // NB there is very similar wording in the ItemValueEncodable derive docs.
    // If editing any of this derive's documentation, considering editing that too.
    //
    /// Fields in the struct are parsed from the keyword line arguments,
    /// in the order they appear in the struct.
    ///
    /// ### Field type
    ///
    /// Each field should be:
    ///
    ///  * `impl `[`ItemArgumentParseable`] (one argument),
    ///  * `Option<impl ItemArgumentParseable>` (one optional argument),
    ///  * `Vec<impl ItemArgumentParseable>` (zero or more arguments), or
    ///  * `BTreeSet<impl ItemArgumentParseable + Ord>` (zero or more arguments).
    ///
    /// `ItemArgumentParseable` can be implemented via `impl FromStr`,
    /// by writing `impl NormalItemArgument`.
    ///
    /// For `Option` or `Vec`, we expect that *if* there are any further arguments,
    /// they are for this field.
    /// So absence of any optional argument means absence of following arguments,
    /// and no arguments can follow a `Vec`.
    ///
    /// Some Tor netdocs have optional arguments followed by other data,
    /// with unclear/ambiguous parsing rules.
    /// These cases typically require manual implementation of [`ItemValueParseable`].
    ///
    /// (Multiplicity is implemented via types in the [`multiplicity`] module,
    /// specifically [`ArgumentSetSelector`] and [`ArgumentSetMethods`].)
    ///
    /// ### Top-level attributes:
    ///
    ///  * **`#[deftly(netdoc(no_extra_args))]**:
    ///
    ///    Reject, rather than ignore, additional arguments found in the document
    ///    which aren't described by the struct.
    ///
    ///  * **`#[deftly(netdoc(signature(hash_accu = HASH_ACCU))]**:
    ///
    ///    This item is a signature item.
    ///    [`SignatureItemParseable`] will be implemented instead of [`ItemValueParseable`].
    ///
    ///    **`HASH_ACCU`** is the type in which the hash(es) for this item will be accumulated,
    ///    and must implement [`SignatureHashesAccumulator`].
    ///    It is used as [`SignatureItemParseable::HashAccu`].
    ///
    /// * **`#[deftly(netdoc(debug))]`**:
    ///
    ///   Currently implemented only as a placeholder
    ///
    ///   The generated implementation may in future generate copious debug output
    ///   to the program's stderr when it is run.
    ///   Do not enable in production!
    ///
    $DOC_DEBUG_PLACEHOLDER
    ///
    /// ### Field-level attributes:
    ///
    ///  * **`#[deftly(netdoc(rest))]**:
    ///
    ///    The field is the whole rest of the line.
    ///    Must come after any other normal argument fields.
    ///    Only allowed once.
    ///
    ///    The field type must implement `FromStr`.
    ///    (I.e. `Vec` , `Option` etc., are not allowed, and `ItemArgumentParseable` is not used.)
    ///
    ///  * **`#[deftly(netdoc(object))]**:
    ///
    ///    The field is the Object.
    ///    It must implement [`ItemObjectParseable`]
    ///    (or be `Option<impl ItemObjectParseable>`).
    ///
    ///    Only allowed once.
    ///    If omittted, any object is rejected.
    ///
    ///  * **`#[deftly(netdoc(object(label = "LABEL")))]**:
    ///
    ///    Sets the expected label for an Object.
    ///    If not supplied, uses [`ItemObjectParseable::check_label`].
    ///
    ///  * **`#[deftly(netdoc(with = MODULE)]**:
    ///
    ///    Instead of `ItemArgumentParseable`, the argument is parsed with `MODULE::from_args`,
    ///    which must have the same signature as [`ItemArgumentParseable::from_args`].
    ///
    ///    With `#[deftly(netdoc(rest))]`, the argument is parsed with `MODULE::from_args_rest`,
    ///    must have the signature
    ///    `fn from_args_rest(s: &str) -> Result<FIELD, _>`).
    ///    and replaces `<FIELD as FromStr>::from_str`.
    ///
    ///    With `#[deftly(netdoc(object))]`, uses `MODULE::try_from`
    ///    which must have the signature `fn(Vec<u8>) -> Result<OBJECT, _>;
    ///    like `TryFrom::<Vec<u8>>>::try_from`.
    ///    LABEL must also be specified
    ///    unless the object also implements `ItemObjectParseable`.
    ///    Errors from parsing will all be collapsed into
    ///    [`ErrorProblem::ObjectInvalidData`].
    ///
    ///  * **`#[deftly(netdoc(skip))]**:
    ///
    ///    Do not parse this field; fill it in with `Default::default()` instead.
    export ItemValueParseable for struct, meta_quoted rigorous, expect items, beta_deftly:
    ${define TRAIT ${if T_IS_SIGNATURE { SignatureItemParseable } else { ItemValueParseable }}}
    ${define METHOD ${if T_IS_SIGNATURE { from_unparsed_and_body } else { from_unparsed }}}
    // SignatureItemParseable::HashAccu
    ${define SIG_HASH_ACCU_TYPE ${tmeta(netdoc(signature(hash_accu))) as ty}}
    // Avoid that someone wanting to parse a signed netdoc
    //   - tries to use parse2 on Foo rather than FooUnverified
    //   - fails to notice the impl on FooUnverified
    //   - adds a derive of NetdocParseable
    //   - calls that parser
    // thereby completely ignoring the signatures.
    $P::assert_not_impl! {
        [signed_documents_should_be_parsed_only_as_foo_unverified <$tgens>]
        $ttype: $P::NetdocParseable
    }
    impl<$tgens> $P::$TRAIT for $ttype {
      ${if T_IS_SIGNATURE {
        type HashAccu = $SIG_HASH_ACCU_TYPE;
      }}
9600
        fn $METHOD<'s>(
9600
            mut input: $P::UnparsedItem<'s>,
9600
          ${if T_IS_SIGNATURE {
9600
            document_body: &SignatureHashInputs<'_>,
9600
            hash_accu: &mut $SIG_HASH_ACCU_TYPE,
9600
          }}
9600
        ) -> $P::Result<Self, $P::EP>
        {
            #[allow(unused_imports)] // false positive when macro is used with prelude in scope
            use $P::*;
            $DEFINE_DTRACE
18
            dtrace!(
18
                "item start",
18
                input.keyword().as_str(),
18
                input.args_copy().into_remaining(),
27
                input.object().map(|o| o.label()),
            );
            ${if T_IS_SIGNATURE {
938
                <$SIG_HASH_ACCU_TYPE as SignatureHashesAccumulator>::update_from_netdoc_body(
938
                    hash_accu,
938
                    document_body
                )?;
            }}
9600
            let object = input.object();
            #[allow(unused)]
9600
            let mut args = input.args_mut();
          $(
            #[allow(non_snake_case)]
9336
            let $fpatname = ${select1
              F_NORMAL { {
5428
                  let selector = MultiplicitySelector::<$ftype>::default();
18
                  dtrace!(
18
                      $"field $fname, normal",
18
                      selector.argument_set_debug(),
18
                      args.clone().into_remaining(),
                  );
                ${if not(fmeta(netdoc(with))) {
416
                  selector.${paste_spanned $fname check_argument_value_parseable}();
                }}
5428
                  selector.parse_with(
5428
                      &mut args,
                      ${fmeta(netdoc(with))
                        as path,
                        default { ItemArgumentParseable }}::${paste_spanned $fname from_args},
5428
                  ).map_err(args.error_handler(stringify!($fname)))?
              } }
              F_OBJECT { {
5910
                  let selector = MultiplicitySelector::<$ftype>::default();
18
                  dtrace!(
18
                      $"field $fname, object",
18
                      selector.object_set_debug(),
27
                      object.as_ref().map(|o| (o.label(), o.decode_data().map(|d| d.len()))),
                  );
6247
                  let object = object.map(|object| {
5874
                      let data = object.decode_data()?;
                      ${if fmeta(netdoc(object(label))) {
2842
                          if object.label() != ${fmeta(netdoc(object(label))) as str} {
2
                              return Err(EP::ObjectIncorrectLabel)
2840
                          }
                      } else {
3030
                          selector.${paste_spanned $fname check_label}(object.label())?;
                      }}
                      ${if fmeta(netdoc(with)) {
                          ${fmeta(netdoc(with)) as path}::${paste_spanned $fname try_from}
2840
                              (data)
                              .map_err(|_| EP::ObjectInvalidData)
                      } else {
246
                          selector.${paste_spanned $fname check_object_parseable}();
3026
                          ItemObjectParseable::from_bytes(&data)
                      }}
6247
                  }).transpose()?;
5900
                  selector.resolve_option(object)?
              } }
              F_REST { {
                  dtrace!($"field $fname, rest", args.clone().into_remaining());
                  // consumes `args`, leading to compile error if the rest field
                  // isn't last (or is combined with no_extra_args).
22
                  let args_consume = args;
                  ${if fmeta(netdoc(with)) {
                      ${fmeta(netdoc(with)) as path}::${paste_spanned $fname from_args_rest}
                  } else {
16
                      <$ftype as FromStr>::from_str
                  }}
16
                      (args_consume.into_remaining())
16
                      .map_err(|_| AE::Invalid)
16
                      .map_err(args_consume.error_handler(stringify!($fname)))?
              } }
              F_SKIP { {
2160
                  <$ftype as Default>::default()
              } }
            };
          )
          ${if approx_equal({}, $( ${when F_OBJECT} $fname )) {
3670
            if object.is_some() {
                return Err(EP::ObjectUnexpected);
3670
            }
          }}
          ${if tmeta(netdoc(no_extra_args)) {
3960
            args.reject_extra_args()?;
          }}
18
            dtrace!("item complete Ok");
            #[allow(deprecated)]
9566
            Ok($tname { $( $fname: $fpatname, ) })
9600
        }
    }
}