Skip to main content

tor_netdoc/parse2/
derive.rs

1//! Deriving `NetdocParseable`
2
3use 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)]
10pub 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    let mut out = String::new();
15    (|| {
16        write!(out, "netdoc {ttype} parse: {msg}")?;
17        for val in vals {
18            write!(out, ", {val:?}")?;
19        }
20        writeln!(out)
21    })()
22    .expect("write to string failed");
23
24    eprint!("{out}");
25}
26
27define_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
49define_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    ${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
289define_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        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        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        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        fn from_items<'s>(
343            input: &mut $P::ItemStream<'s>,
344            outer_stop: $P::stop_at!(),
345        ) -> $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                $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            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
476define_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
694define_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        fn is_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
796            use $P::*;
797            ${for fields {
798                kw == $F_KEYWORD ||
799            }}
800                false
801        }
802
803        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
804        fn from_items<'s>(
805            input: &mut $P::ItemStream<'s>,
806            signed_doc_body: $P::SignedDocumentBody<'s>,
807            sig_hashes: &mut $SIGS_HASHES_ACCU_TYPE,
808            outer_stop: $P::stop_at!(),
809        ) -> $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            while let Some(kw) = input.peek_keyword()? {
822                dtrace!("for signatures, peeked", kw);
823                if outer_stop.stop_at(kw) {
824                    dtrace!("is outer stop", kw);
825                    break;
826                };
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        }
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
852define_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        fn is_item_keyword(
889            #[allow(unused_variables)] // If there are no fields, this is unused
890            kw: $P::KeywordRef<'_>,
891        ) -> 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            kw == $F_KEYWORD ||
899          }}
900          ${for fields {
901            ${when F_FLATTEN}
902            ${when not(F_SKIP)}
903            <$ftype as NetdocParseableFields>::is_item_keyword(kw) ||
904          }}
905            false
906        }
907
908        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
909        fn accumulate_item(
910            #[allow(unused_variables)] // If there are no fields, this is unused
911            acc: &mut Self::Accumulator,
912            #[allow(unused_variables)] // If there are no fields, this is unused
913            item: $P::UnparsedItem<'_>,
914        ) -> $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            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            Ok(())
933        }
934
935        fn finish(
936            #[allow(unused_variables)] // If there are no fields, this is unused
937            acc: Self::Accumulator,
938            #[allow(unused_variables)] // often unused
939            items: &$P::ItemStream<'_>,
940        ) -> $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            let $fpatname = acc.$fname;
952         )
953            $FINISH_RESOLVE
954        }
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
973define_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.
1000    ///
1001    ///   * Return `TimeRangebound<Foo>`.
1002    ///
1003    /// ### Generated code
1004    ///
1005    /// Supposing your input structure is `Foo`, this macro will
1006    /// generate a **`struct FooUnverified`**
1007    /// implementing [`NetdocParseable`] and [`NetdocParseableUnverified`]:
1008    ///
1009    /// ```rust,ignore
1010    /// # struct Foo; struct FooSignatures;
1011    /// pub struct FooUnverified {
1012    ///     body: Foo,
1013    ///     pub sigs: SignaturesData<FooUnverified>,
1014    /// }
1015    /// ```
1016    ///
1017    /// Also generated is `FooUnverifiedParsedBody`
1018    /// and an impl of [`HasUnverifiedParsedBody`] on `Foo`.
1019    /// These allow the generated code to call [`ItemStream::parse_signed`]
1020    /// and it should not normally be necessary to use them elsewhere.
1021    ///
1022    /// ### Required top-level attributes:
1023    ///
1024    /// * **`#[deftly(netdoc(signature = TYPE))]`**:
1025    ///   Type of the signature(s) section.
1026    ///
1027    ///   TYPE must implement `NetdocParseable`,
1028    ///   with `is_intro_item_keyword` reporting *every* signature keyword.
1029    ///   Normally this is achieved with
1030    ///   `#[derive_deftly(NetdocParseable)] #[deftly(netdoc(signatures))]`.
1031    ///
1032    /// ### Optional attributes
1033    ///
1034    /// All the attributes supported by the `NetdocParseable` derive are supported.
1035    //
1036    // We don't make NetdocParseableUnverified a generic struct because
1037    //  - the defining module (crate) will want to add verification methods,
1038    //    which means they must define the struct
1039    //  - that lets the actual `body` field be private to the defining module.
1040    export NetdocParseableUnverified for struct, meta_quoted rigorous, expect items, beta_deftly:
1041
1042    ${define NETDOC_PARSEABLE_TTYPE { $<$ttype UnverifiedParsedBody> }}
1043    ${define FINISH_RESOLVE_PARSEABLE {
1044        { $FINISH_RESOLVE }
1045        .map(|unverified| $<$tname UnverifiedParsedBody> { unverified })
1046    }}
1047
1048    $IMPL_NETDOC_PARSEABLE
1049
1050    // FooSignatures (type name)
1051    ${define SIGS_TYPE { $< ${tmeta(netdoc(signatures)) as ty, default $<$ttype Signatures>} > }}
1052    ${define SIGS_DATA_TYPE { $P::SignaturesData<$<$ttype Unverified>> }}
1053    ${define SIGS_HASHES_ACCU_TYPE { <$SIGS_TYPE as $P::NetdocParseableSignatures>::HashesAccu }}
1054
1055   $///Signed (unverified) form of [`$tname`]
1056    ///
1057    /// Embodies:
1058    ///
1059   $///  * **[`$tname`]**: document body
1060   $///  * **[`$SIGS_TYPE`]**: signatures
1061    ///
1062    /// If this type was parsed from a document text,
1063    /// the signatures have *not* yet been verified.
1064    ///
1065    /// Use a `.verify_...` method to obtain useable, verified, contents.
1066    #[derive(Debug, Clone)]
1067    $tvis struct $<$ttype Unverified> {
1068        /// The actual body
1069        //
1070        // Misuse is prevented by this field not being public.
1071        // It can be accessed only in this module, where the verification functions are.
1072        body: $ttype,
1073
1074        /// Signatures
1075        $tvis sigs: $SIGS_DATA_TYPE,
1076    }
1077
1078    /// The parsed but unverified body part of a signed network document (working type)
1079    ///
1080   $/// Contains a $tname which has been parsed
1081    /// as part of a signed document,
1082    /// but the signatures aren't embodied here, and have not been verified.
1083    ///
1084    /// Not very useful to callers, who should use the `BodyUnverified` type instead,
1085    /// and its implementation of `NetdocParseable`.
1086    //
1087    // We implement NetdocParseable on FooUnverified using ItemStream::parse_signed.
1088    // ItemStream::parse_signed is a fairly normal but ad-hoc
1089    // implementation of NetdocParseable which uses as subroutines implementations
1090    // of NetdocParseable for the body and NetdocParseableSignatures for the signatures.
1091    //
1092    // We need a newtype because we don't want to implement `NetdocParseable`
1093    // for a type which is just the body.  Such an impl would be usable by mistake,
1094    // via the top-level parse2 functions, and it would then simply discard the signatures
1095    // and return unverified data, bypassing our efforts to prevent such bugs.
1096    //
1097    // Ideally we would have a generic `UnverifiedParsedBody<B>` type or something
1098    // but then this macro, invoked in other crates, couldn't impl NetdocParseable for
1099    // UnverifiedParsedBody<TheirType>, due to trait coherence rules.
1100    //
1101    #[derive(derive_more::From)]
1102    pub struct $NETDOC_PARSEABLE_TTYPE<$tdefgens> {
1103        /// The unverified body
1104        unverified: $ttype,
1105    }
1106
1107    impl<$tgens> $P::NetdocParseable for $<$ttype Unverified> {
1108        fn doctype_for_error() -> &'static str {
1109            $NETDOC_PARSEABLE_TTYPE::doctype_for_error()
1110        }
1111
1112        fn is_intro_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
1113            $NETDOC_PARSEABLE_TTYPE::is_intro_item_keyword(kw)
1114        }
1115
1116        fn is_structural_keyword(kw: $P::KeywordRef<'_>) -> Option<$P::IsStructural> {
1117            $NETDOC_PARSEABLE_TTYPE::is_structural_keyword(kw).or_else(
1118                || <$SIGS_TYPE as $P::NetdocParseableSignatures>
1119                    ::is_item_keyword(kw).then_some($P::IsStructural)
1120            )
1121        }
1122
1123        fn from_items<'s>(
1124            input: &mut $P::ItemStream<'s>,
1125            outer_stop: $P::stop_at!(),
1126        ) -> $P::Result<$<$ttype Unverified>, $P::ErrorProblem> {
1127            $EMIT_DEBUG_PLACEHOLDER
1128            input.parse_signed(outer_stop)
1129        }
1130    }
1131
1132    impl<$tgens> $P::NetdocParseableUnverified for $<$ttype Unverified> {
1133        type Body = $ttype;
1134        type Signatures = $SIGS_TYPE;
1135        fn inspect_unverified(&self) -> (&Self::Body, &$SIGS_DATA_TYPE) {
1136            (&self.body, &self.sigs)
1137        }
1138        fn unwrap_unverified(self) -> (Self::Body, $SIGS_DATA_TYPE) {
1139            (self.body, self.sigs)
1140        }
1141        fn from_parts(body: Self::Body, sigs: $SIGS_DATA_TYPE) -> Self {
1142            Self { body, sigs }
1143        }
1144    }
1145
1146    impl<$tgens> $P::HasUnverifiedParsedBody for $ttype {
1147        type UnverifiedParsedBody = $NETDOC_PARSEABLE_TTYPE;
1148        fn unverified_into_inner_unchecked(unverified: Self::UnverifiedParsedBody) -> Self {
1149            unverified.unverified
1150        }
1151    }
1152}
1153
1154//==================== ItemValueParseable user-facing derive macro ====================
1155//
1156// deftly template `ItemValueParseable`
1157//
1158//  * entrypoint for deriving the `ItemValueParseable` and `SignatureItemParseable` traits
1159//  * docs for the meta attributes we support during *item* parsing
1160//  * implementation of those derives
1161
1162define_derive_deftly! {
1163    use NetdocDeriveAnyCommon;
1164    use NetdocParseAnyCommon;
1165    use NetdocItemDeriveCommon;
1166
1167    /// Derive `ItemValueParseable` (or `SignatureItemParseable`)
1168    ///
1169    // NB there is very similar wording in the ItemValueEncodable derive docs.
1170    // If editing any of this derive's documentation, considering editing that too.
1171    //
1172    /// Fields in the struct are parsed from the keyword line arguments,
1173    /// in the order they appear in the struct.
1174    ///
1175    /// ### Field type
1176    ///
1177    /// Each field should be:
1178    ///
1179    ///  * `impl `[`ItemArgumentParseable`] (one argument),
1180    ///  * `Option<impl ItemArgumentParseable>` (one optional argument),
1181    ///  * `Vec<impl ItemArgumentParseable>` (zero or more arguments), or
1182    ///  * `BTreeSet<impl ItemArgumentParseable + Ord>` (zero or more arguments).
1183    ///
1184    /// `ItemArgumentParseable` can be implemented via `impl FromStr`,
1185    /// by writing `impl NormalItemArgument`.
1186    ///
1187    /// For `Option` or `Vec`, we expect that *if* there are any further arguments,
1188    /// they are for this field.
1189    /// So absence of any optional argument means absence of following arguments,
1190    /// and no arguments can follow a `Vec`.
1191    ///
1192    /// Some Tor netdocs have optional arguments followed by other data,
1193    /// with unclear/ambiguous parsing rules.
1194    /// These cases typically require manual implementation of [`ItemValueParseable`].
1195    ///
1196    /// (Multiplicity is implemented via types in the [`multiplicity`] module,
1197    /// specifically [`ArgumentSetSelector`] and [`ArgumentSetMethods`].)
1198    ///
1199    /// ### Top-level attributes:
1200    ///
1201    ///  * **`#[deftly(netdoc(no_extra_args))]**:
1202    ///
1203    ///    Reject, rather than ignore, additional arguments found in the document
1204    ///    which aren't described by the struct.
1205    ///
1206    ///  * **`#[deftly(netdoc(signature(hash_accu = HASH_ACCU))]**:
1207    ///
1208    ///    This item is a signature item.
1209    ///    [`SignatureItemParseable`] will be implemented instead of [`ItemValueParseable`].
1210    ///
1211    ///    **`HASH_ACCU`** is the type in which the hash(es) for this item will be accumulated,
1212    ///    and must implement [`SignatureHashesAccumulator`].
1213    ///    It is used as [`SignatureItemParseable::HashAccu`].
1214    ///
1215    /// * **`#[deftly(netdoc(debug))]`**:
1216    ///
1217    ///   Currently implemented only as a placeholder
1218    ///
1219    ///   The generated implementation may in future generate copious debug output
1220    ///   to the program's stderr when it is run.
1221    ///   Do not enable in production!
1222    ///
1223    $DOC_DEBUG_PLACEHOLDER
1224    ///
1225    /// ### Field-level attributes:
1226    ///
1227    ///  * **`#[deftly(netdoc(rest))]**:
1228    ///
1229    ///    The field is the whole rest of the line.
1230    ///    Must come after any other normal argument fields.
1231    ///    Only allowed once.
1232    ///
1233    ///    The field type must implement `FromStr`.
1234    ///    (I.e. `Vec` , `Option` etc., are not allowed, and `ItemArgumentParseable` is not used.)
1235    ///
1236    ///  * **`#[deftly(netdoc(object))]**:
1237    ///
1238    ///    The field is the Object.
1239    ///    It must implement [`ItemObjectParseable`]
1240    ///    (or be `Option<impl ItemObjectParseable>`).
1241    ///
1242    ///    Only allowed once.
1243    ///    If omittted, any object is rejected.
1244    ///
1245    ///  * **`#[deftly(netdoc(object(label = "LABEL")))]**:
1246    ///
1247    ///    Sets the expected label for an Object.
1248    ///    If not supplied, uses [`ItemObjectParseable::check_label`].
1249    ///
1250    ///  * **`#[deftly(netdoc(with = MODULE)]**:
1251    ///
1252    ///    Instead of `ItemArgumentParseable`, the argument is parsed with `MODULE::from_args`,
1253    ///    which must have the same signature as [`ItemArgumentParseable::from_args`].
1254    ///
1255    ///    With `#[deftly(netdoc(rest))]`, the argument is parsed with `MODULE::from_args_rest`,
1256    ///    must have the signature
1257    ///    `fn from_args_rest(s: &str) -> Result<FIELD, _>`).
1258    ///    and replaces `<FIELD as FromStr>::from_str`.
1259    ///
1260    ///    With `#[deftly(netdoc(object))]`, uses `MODULE::try_from`
1261    ///    which must have the signature `fn(Vec<u8>) -> Result<OBJECT, _>;
1262    ///    like `TryFrom::<Vec<u8>>>::try_from`.
1263    ///    LABEL must also be specified
1264    ///    unless the object also implements `ItemObjectParseable`.
1265    ///    Errors from parsing will all be collapsed into
1266    ///    [`ErrorProblem::ObjectInvalidData`].
1267    ///
1268    ///  * **`#[deftly(netdoc(skip))]**:
1269    ///
1270    ///    Do not parse this field; fill it in with `Default::default()` instead.
1271    export ItemValueParseable for struct, meta_quoted rigorous, expect items, beta_deftly:
1272
1273    ${define TRAIT ${if T_IS_SIGNATURE { SignatureItemParseable } else { ItemValueParseable }}}
1274    ${define METHOD ${if T_IS_SIGNATURE { from_unparsed_and_body } else { from_unparsed }}}
1275
1276    // SignatureItemParseable::HashAccu
1277    ${define SIG_HASH_ACCU_TYPE ${tmeta(netdoc(signature(hash_accu))) as ty}}
1278
1279    // Avoid that someone wanting to parse a signed netdoc
1280    //   - tries to use parse2 on Foo rather than FooUnverified
1281    //   - fails to notice the impl on FooUnverified
1282    //   - adds a derive of NetdocParseable
1283    //   - calls that parser
1284    // thereby completely ignoring the signatures.
1285    $P::assert_not_impl! {
1286        [signed_documents_should_be_parsed_only_as_foo_unverified <$tgens>]
1287        $ttype: $P::NetdocParseable
1288    }
1289
1290    impl<$tgens> $P::$TRAIT for $ttype {
1291      ${if T_IS_SIGNATURE {
1292        type HashAccu = $SIG_HASH_ACCU_TYPE;
1293      }}
1294
1295        fn $METHOD<'s>(
1296            mut input: $P::UnparsedItem<'s>,
1297          ${if T_IS_SIGNATURE {
1298            document_body: &SignatureHashInputs<'_>,
1299            hash_accu: &mut $SIG_HASH_ACCU_TYPE,
1300          }}
1301        ) -> $P::Result<Self, $P::EP>
1302        {
1303            #[allow(unused_imports)] // false positive when macro is used with prelude in scope
1304            use $P::*;
1305
1306            $DEFINE_DTRACE
1307
1308            dtrace!(
1309                "item start",
1310                input.keyword().as_str(),
1311                input.args_copy().into_remaining(),
1312                input.object().map(|o| o.label()),
1313            );
1314
1315            ${if T_IS_SIGNATURE {
1316                <$SIG_HASH_ACCU_TYPE as SignatureHashesAccumulator>::update_from_netdoc_body(
1317                    hash_accu,
1318                    document_body
1319                )?;
1320            }}
1321
1322            let object = input.object();
1323            #[allow(unused)]
1324            let mut args = input.args_mut();
1325          $(
1326            #[allow(non_snake_case)]
1327            let $fpatname = ${select1
1328              F_NORMAL { {
1329                  let selector = MultiplicitySelector::<$ftype>::default();
1330                  dtrace!(
1331                      $"field $fname, normal",
1332                      selector.argument_set_debug(),
1333                      args.clone().into_remaining(),
1334                  );
1335                ${if not(fmeta(netdoc(with))) {
1336                  selector.${paste_spanned $fname check_argument_value_parseable}();
1337                }}
1338                  selector.parse_with(
1339                      &mut args,
1340                      ${fmeta(netdoc(with))
1341                        as path,
1342                        default { ItemArgumentParseable }}::${paste_spanned $fname from_args},
1343                  ).map_err(args.error_handler(stringify!($fname)))?
1344              } }
1345              F_OBJECT { {
1346                  let selector = MultiplicitySelector::<$ftype>::default();
1347                  dtrace!(
1348                      $"field $fname, object",
1349                      selector.object_set_debug(),
1350                      object.as_ref().map(|o| (o.label(), o.decode_data().map(|d| d.len()))),
1351                  );
1352                  let object = object.map(|object| {
1353                      let data = object.decode_data()?;
1354                      ${if fmeta(netdoc(object(label))) {
1355                          if object.label() != ${fmeta(netdoc(object(label))) as str} {
1356                              return Err(EP::ObjectIncorrectLabel)
1357                          }
1358                      } else {
1359                          selector.${paste_spanned $fname check_label}(object.label())?;
1360                      }}
1361                      ${if fmeta(netdoc(with)) {
1362                          ${fmeta(netdoc(with)) as path}::${paste_spanned $fname try_from}
1363                              (data)
1364                              .map_err(|_| EP::ObjectInvalidData)
1365                      } else {
1366                          selector.${paste_spanned $fname check_object_parseable}();
1367                          ItemObjectParseable::from_bytes(&data)
1368                      }}
1369                  }).transpose()?;
1370                  selector.resolve_option(object)?
1371              } }
1372              F_REST { {
1373                  dtrace!($"field $fname, rest", args.clone().into_remaining());
1374                  // consumes `args`, leading to compile error if the rest field
1375                  // isn't last (or is combined with no_extra_args).
1376                  let args_consume = args;
1377                  ${if fmeta(netdoc(with)) {
1378                      ${fmeta(netdoc(with)) as path}::${paste_spanned $fname from_args_rest}
1379                  } else {
1380                      <$ftype as FromStr>::from_str
1381                  }}
1382                      (args_consume.into_remaining())
1383                      .map_err(|_| AE::Invalid)
1384                      .map_err(args_consume.error_handler(stringify!($fname)))?
1385              } }
1386              F_SKIP { {
1387                  <$ftype as Default>::default()
1388              } }
1389            };
1390          )
1391          ${if approx_equal({}, $( ${when F_OBJECT} $fname )) {
1392            if object.is_some() {
1393                return Err(EP::ObjectUnexpected);
1394            }
1395          }}
1396          ${if tmeta(netdoc(no_extra_args)) {
1397            args.reject_extra_args()?;
1398          }}
1399            dtrace!("item complete Ok");
1400            #[allow(deprecated)]
1401            Ok($tname { $( $fname: $fpatname, ) })
1402        }
1403    }
1404}