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    ///  * **`THIS_ITEM`**: consumes the next item and evaluates to it as an `UnparsedItem`.
56    ///    See the definition in `NetdocParseable`.
57    ///
58    ///  * **`F_ACCUMULATE_VAR`** the variable or field into which to accumulate
59    ///    normal items for this field.  Must be of type `&mut $F_ACCUMULATE_TYPE`.
60    ///
61    /// Importer must also import `NetdocSomeItemsDeriveCommon` and `NetdocDeriveAnyCommon`.
62    NetdocSomeItemsParseableCommon beta_deftly:
63
64    // The effective field type for parsing.
65    //
66    // Handles #[deftly(netdoc(default))], in which case we parse as if the field was Option,
67    // and substitute in the default at the end.
68    //
69    ${define F_EFFECTIVE_TYPE {
70        ${if all(fmeta(netdoc(default))) {
71            Option::<$ftype>
72        } else {
73            $ftype
74        }}
75    }}
76
77    // Provide `$<selector_ $fname>` for every (suitable) field.
78    ${define ITEM_SET_SELECTORS {
79        $(
80          ${when not(any(F_FLATTEN, F_SKIP))}
81
82          // See `mod multiplicity`.
83        ${if not(all(F_INTRO, fmeta(netdoc(with)))) {
84          // If the intro it has `with`, we don't check its trait impl, and this ends up unused
85          let $<selector_ $fname> = $F_SELECTOR_VALUE;
86        }}
87        )
88    }}
89    // The item set selector for this field.
90    // We must provide this, rather than expanding $<selector_ $fname> at the use sites,
91    // because the identifier `selector_` has different macro_rules hygiene here vs there!
92    // TODO derive-deftly#130
93    ${define F_SELECTOR $<selector_ $fname>}
94    // The selector value for this field.  Used where we don't want to bind a selector
95    // for every field with $ITEM_SET_SELECTORS (and within $ITEM_SET_SELECTORS).
96    ${define F_SELECTOR_VALUE {( MultiplicitySelector::<$F_EFFECTIVE_TYPE>::default() )}}
97    // Check that every field type implements the necessary trait.
98    ${define CHECK_FIELD_TYPES_PARSEABLE {
99        $(
100          ${when not(any(F_FLATTEN, F_SKIP))}
101
102          // Expands to `selector_FIELD.check_SOMETHING();`
103          //
104          // If the relevant trait isn't implemented, rustc reports the error by
105          // pointing at the `check-something` call.  We re-span that identifier
106          // to point to the field name, so that's where the error is reported.
107          //
108          // Without this, we just get a report that `item` doesn't implement the required
109          // trait - but `item` is a local variable here, so the error points into the macro
110        ${if not(all(any(F_INTRO, F_NORMAL), fmeta(netdoc(with)))) {
111          $<selector_ $fname> . ${paste_spanned $fname ${select1
112                  any(F_INTRO, F_NORMAL){
113                      // For the intro item, this is not completely precise, because the
114                      // it will allow Option<> and Vec<> which aren't allowed there.
115                      ${if
116                        fmeta(netdoc(single_arg)) { check_item_argument_parseable }
117                        else { check_item_value_parseable }
118                      }
119                  }
120                  F_SIGNATURE { check_signature_item_parseable }
121                  F_SUBDOC    { check_subdoc_parseable         }
122          }} (
123              ${if F_SIGNATURE { sig_hashes, }}
124          );
125        }}
126        )
127    }}
128
129    // Convert the UnparsedItem (in `item` to the value (to accumulate).
130    // Expands to an expression.
131    ${define ITEM_VALUE_FROM_UNPARSED {
132        ${if fmeta(netdoc(with)) {
133          ${fmeta(netdoc(with)) as path}
134              ::${paste_spanned $fname from_unparsed}
135              (item)?
136        } else if fmeta(netdoc(single_arg)) { {
137          let item = ItemValueParseable::from_unparsed(item)?;
138          let (item,) = item;
139          item
140        } } else {
141          ItemValueParseable::from_unparsed(item)?
142        }}
143    }}
144
145    // Type into which we accumulate value(s) of this field
146    ${define F_ACCUMULATE_TYPE {
147        ${if F_FLATTEN {
148            <$ftype as $P::NetdocParseableFields>::Accumulator
149        } else {
150            Option::<$F_EFFECTIVE_TYPE>
151        }
152    }}}
153
154    // Parse the intro item and bind `$fpatname` accumulator for each field.
155    //
156    // For the intro item, parse it and bind it to $fpatname.
157    //
158    // For other items, set up a mutable $fpatname, initialised to `default()` (normally None).
159    ${define INIT_ACCUMULATE_VARS {
160        $( ${select1 F_INTRO {
161
162          let item = input.next_item()?.ok_or(EP::EmptyDocument)?;
163          dtrace!("intro", item);
164          if !Self::is_intro_item_keyword(item.keyword()) {
165              Err(EP::WrongDocumentType)?;
166          }
167          let $fpatname: $ftype = $ITEM_VALUE_FROM_UNPARSED;
168
169        } F_SKIP {
170
171        } else {
172
173          let mut $fpatname = $F_ACCUMULATE_TYPE::default();
174
175        }})
176    }}
177
178    // Accumulates `item` (which must be `ItemSetMethods::Each`) into `$F_ACCUMULATE_VAR`
179    ${define ACCUMULATE_ITEM_VALUE { {
180        dtrace!($"accumulating $fname", $F_SELECTOR.item_set_debug());
181        $F_SELECTOR.${paste_spanned $fname accumulate}($F_ACCUMULATE_VAR, item)?;
182    } }}
183
184    // Handle a nonstructural field, parsing and accumulating its value
185    //
186    // Looks at `kw` for the keyword.
187    //
188    // Expands to a series of `if ... { ... } else`.
189    // The use site must provide (maybe further arms) and a fallback block!
190    //
191    // If the item is the intro item for this document, evaluates `break` -
192    // so if `f_INTRO` is not trivially false, must be expanded within a field loop.
193    ${define NONSTRUCTURAL_ACCUMULATE_ELSE {
194        ${for fields {
195          ${when not(any(F_FLATTEN, F_SUBDOC, F_SKIP))}
196
197          if kw == $F_KEYWORD {
198            ${select1
199              F_NORMAL {
200                let item = $THIS_ITEM;
201                dtrace!("is normal", item);
202                let item = $ITEM_VALUE_FROM_UNPARSED;
203                $ACCUMULATE_ITEM_VALUE
204              }
205              F_SIGNATURE {
206                let hash_inputs = input
207                      .peek_signature_hash_inputs(signed_doc_body)?
208                      .expect("not eof, we peeked kw");
209
210                let item = $THIS_ITEM;
211                dtrace!("is signature", item);
212                let item = SignatureItemParseable::from_unparsed_and_body(
213                    item,
214                    &hash_inputs,
215                    AsMut::as_mut(sig_hashes),
216                )?;
217                $ACCUMULATE_ITEM_VALUE
218              }
219              F_INTRO {
220                dtrace!("is intro", kw);
221                break;
222              } // start of next similar document
223            }
224          } else
225        }}
226        ${for fields {
227          ${when F_FLATTEN}
228
229          if $ftype::is_item_keyword(kw) {
230              dtrace!(${concat "is flatten in " $fname}, kw);
231              let item = $THIS_ITEM;
232              <$ftype as NetdocParseableFields>::accumulate_item($F_ACCUMULATE_VAR, item)?;
233          } else
234        }}
235    }}
236
237    // Completes a document
238    //
239    // The fields accumulated so far must be in `$fpatname` (as a value, not a ref,
240    // and therefore not in $F_ACCUMULATE_VAR).
241    //
242    // Expands to code which resolves the fields, and ends with `Ok(document value)`.
243    ${define FINISH_RESOLVE {
244        ${for fields {
245            ${select1
246              F_INTRO {}
247              any(F_NORMAL, F_SIGNATURE) {
248                  let $fpatname = $F_SELECTOR.finish($fpatname, $F_KEYWORD_REPORT)?;
249              }
250              F_FLATTEN {
251                  let $fpatname = <$ftype as NetdocParseableFields>::finish($fpatname)?;
252              }
253              F_SUBDOC {
254                  let $fpatname = $F_SELECTOR.finish_subdoc($fpatname)?;
255              }
256              F_SKIP {
257                  #[allow(non_snake_case)]
258                  let $fpatname = Default::default();
259              }
260            }
261        }}
262        $(
263            ${when not(any(F_INTRO, F_SKIP))}
264            // These conditions are mirrored in NetdocSomeItemsEncodableCommon,
265            // which is supposed to recognise netdoc(default) precisely when we do.
266          ${if fmeta(netdoc(default)) {
267            let $fpatname = Option::unwrap_or_default($fpatname);
268          }}
269        )
270        Ok($vpat)
271    }}
272}
273
274//==================== Main whole document parsing impl ====================
275//
276// deftly module ` NetdocParseable`:
277//
278//   * IMPL_NETDOC_PARSEABLE expanding to `impl NetdocParseable { ... }`
279//
280// Much of the heavy lifting is done in the NetdocSomeItemsParseableCommon deftly module.
281
282define_derive_deftly_module! {
283    /// Provides `IMPL_NETDOC_PARSEABLE` which impls `NetdocParseable`
284    ///
285    /// Used by the `NetdocParseable` and `NetdocParseableUnverified` derives.
286    NetdocParseable beta_deftly:
287
288    use NetdocDeriveAnyCommon;
289    use NetdocParseAnyCommon;
290    use NetdocEntireDeriveCommon;
291    use NetdocSomeItemsDeriveCommon;
292    use NetdocSomeItemsParseableCommon;
293
294    ${define F_ACCUMULATE_VAR { (&mut $fpatname) }}
295
296  ${define IMPL_NETDOC_PARSEABLE {
297    impl<$tgens> $P::NetdocParseable for $NETDOC_PARSEABLE_TTYPE {
298        fn doctype_for_error() -> &'static str {
299            ${tmeta(netdoc(doctype_for_error)) as expr,
300              default ${concat ${for fields { ${when F_INTRO} $F_KEYWORD_STR }}}}
301        }
302
303        fn is_intro_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
304            use $P::*;
305
306            ${for fields {
307                ${when F_INTRO}
308                ${loop_exactly_1 "internal error, somehow not exactly one intro item!"}
309                kw == $F_KEYWORD
310            }}
311        }
312
313        fn is_structural_keyword(kw: $P::KeywordRef<'_>) -> Option<$P::IsStructural> {
314            #[allow(unused_imports)] // not used if there are no subdocs
315            use $P::*;
316
317            if Self::is_intro_item_keyword(kw) {
318                return Some(IsStructural)
319            }
320
321            ${for fields {
322                ${when F_SUBDOC}
323                if let y @ Some(_) = $F_SELECTOR_VALUE.is_structural_keyword(kw) {
324                    return y;
325                }
326            }}
327
328            None
329        }
330
331        //##### main parsing function #####
332
333        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
334        fn from_items<'s>(
335            input: &mut $P::ItemStream<'s>,
336            outer_stop: $P::stop_at!(),
337        ) -> $P::Result<Self, $P::ErrorProblem> {
338            use $P::*;
339            $DEFINE_DTRACE
340            $FIELD_ORDERING_CHECK
341
342            //----- prepare item set selectors for every field -----
343            $ITEM_SET_SELECTORS
344            $CHECK_FIELD_TYPES_PARSEABLE
345
346            // Is this an intro item keyword ?
347            //
348            // Expands to an appropriate `is_intro_item_keyword` method invocation,
349            // but *without arguments*.  So, something a bit like an expression of type
350            //    fn(KeywordRef) -> bool
351            ${define F_SUBDOC_IS_INTRO_ITEM_KEYWORD {
352                ${if not(F_SUBDOC) { ${error "internal-error: subdoc kw, but not subdoc field"} }}
353                $F_SELECTOR.is_intro_item_keyword
354            }}
355
356            //----- Helper fragments for parsing individual pieces of the document -----
357
358            // Peeks a keyword, and returns it but only if it's part of this (sub)doc.
359            // Return `None` if it was in outer_stop
360            let peek_keyword = |input: &mut ItemStream<'s>| -> Result<Option<KeywordRef<'s>>, EP> {
361                let Some(kw) = input.peek_keyword()? else {
362                    dtrace!("stopping, because EOF");
363                    return Ok(None)
364                };
365                if outer_stop.stop_at(kw) {
366                    dtrace!("stopping, because peeked", kw);
367                    return Ok(None)
368                }
369                Ok(Some(kw))
370            };
371
372            // Returns the actual item as an UnparsedItem, committing to consuming it.
373            // Can panic if called without previous `peek_keyword`.
374            ${define THIS_ITEM  {
375                input.next_item()?.expect("peeked")
376            }}
377
378            //----- keyword classification closures -----
379
380            // Is this a keyword for one of our sub-documents?
381            let is_subdoc_kw = ${for fields {
382                ${when F_SUBDOC}
383                StopAt(|kw: KeywordRef<'_>| $F_SUBDOC_IS_INTRO_ITEM_KEYWORD(kw)) |
384              }}
385                StopAt(false)
386            ;
387            // Is this a keyword for one of our parents or sub-documents?
388            let inner_stop = outer_stop | is_subdoc_kw;
389
390            //========== actual parsing ==========
391
392            // For each parsing loop/section, where we aren't looking for precisely one thing,
393            // we should explicitly decide what to do with each of:
394            //   - F_INTRO - intro item for this document (maybe next instance in parent)
395            //   - F_NORMAL - normal items
396            //   - subdocuments, is_subdoc_kw and F_SUBDOC
397            //   - our parent's structural keywords, outer_stop
398            //     (this includes signature items for the signed version of this doc)
399            // 5 cases in all.
400
401            //----- Parse the intro item, and introduce bindings for the other items. -----
402
403            dtrace!("looking for intro item");
404            $INIT_ACCUMULATE_VARS
405
406            //----- Parse the normal items -----
407            dtrace!("looking for normal items");
408
409            while let Some(kw) = peek_keyword(input)? {
410                dtrace!("for normal, peeked", kw);
411                if inner_stop.stop_at(kw) {
412                    dtrace!("is inner stop", kw);
413                    break;
414                };
415
416                $NONSTRUCTURAL_ACCUMULATE_ELSE
417                {
418                    dtrace!("is unknown (in normal)");
419                    let _: UnparsedItem = $THIS_ITEM;
420                }
421            }
422
423            //----- Parse the subdocs, in order -----
424            dtrace!("looking for subdocs");
425
426          ${for fields {
427            ${when F_SUBDOC}
428            dtrace!("looking for subdoc", $F_KEYWORD_REPORT);
429
430            loop {
431                let Some(kw) = peek_keyword(input)? else { break };
432                dtrace!("for subdoc, peek", kw);
433
434                if !$F_SUBDOC_IS_INTRO_ITEM_KEYWORD(kw) {
435                    dtrace!("is not this subdoc", kw);
436                    break;
437                };
438
439                $F_SELECTOR.can_accumulate(&mut $fpatname)?;
440
441                dtrace!("is this subdoc", kw);
442                let item = NetdocParseable::from_items(input, inner_stop);
443                dtrace!("parsed this subdoc", item.as_ref().map(|_| ()));
444                let item = item?;
445
446                $ACCUMULATE_ITEM_VALUE
447            }
448          }}
449
450            // Resolve all the fields
451            dtrace!("reached end, resolving");
452
453            $FINISH_RESOLVE_PARSEABLE
454        }
455    }
456  }}
457}
458
459//==================== NetdocParseable user-facing derive macro ====================
460//
461// deftly template `NetdocParseable`:
462//
463//  * main entrypoint for deriving the `NetdocParseable` trait
464//  * docs for the meta attributes we support during document parsing
465//
466// The actual implementation is in  the `NetdocParseable` deftly module, above.
467
468define_derive_deftly! {
469    use NetdocParseable;
470
471    /// Derive [`NetdocParseable`] for a document (or sub-document)
472    ///
473    // NB there is very similar wording in the NetdocEncodable derive docs.
474    // If editing any of this derive's documentation, considering editing that too.
475    //
476    /// ### Expected input structure
477    ///
478    /// Should be applied named-field struct, where each field is
479    /// an Item which may appear in the document,
480    /// or a sub-document.
481    ///
482    /// The first field will be the document's intro Item.
483    /// The expected Keyword for each Item will be kebab-case of the field name.
484    ///
485    /// ### Field type
486    ///
487    /// Each field must be
488    ///  * `impl `[`ItemValueParseable`] for an "exactly once" field,
489    ///  * `Vec<T: ItemValueParseable>` for "zero or more", or
490    ///  * `BTreeSet<T: ItemValueParseable + Ord>`, or
491    ///  * `Option<T: ItemValueParseable>` for "zero or one".
492    ///
493    /// We don't directly support "at least once":
494    /// the parsed network document doesn't imply the invariant
495    /// that at least one such item was present.
496    // We could invent a `NonemptyVec` or something for this.
497    ///
498    /// (This is implemented via types in the [`multiplicity`] module,
499    /// specifically [`ItemSetSelector`].)
500    ///
501    /// ### Signed documents
502    ///
503    /// To handle signed documents define two structures:
504    ///
505    ///  * `Foo`, containing only the content, not the signatures.
506    ///    Derive [`NetdocParseableUnverified`](derive_deftly_template_NetdocUnverified).
507    ///  * `FooSignatures`, containing only the signatures.
508    ///    Derive `NetdocParseableSignatures`.
509    ///
510    /// Don't mix signature items with non-signature items in the same struct.
511    /// (This wouldn't compile, because the field type would implement the wrong trait.)
512    ///
513    /// ### Top-level attributes:
514    ///
515    /// * **`#[deftly(netdoc(doctype_for_error = EXPRESSION))]`**:
516    ///
517    ///   Specifies the value to be returned from
518    ///   [`NetdocParseable::doctype_for_error`].
519    ///
520    ///   Note, must be an expression, so for a literal, nested `""` are needed.
521    ///
522    ///   The default is the intro item keyword.
523    ///
524    /// * **`#[deftly(netdoc(debug))]`**:
525    ///
526    ///   The generated implementation will generate copious debug output
527    ///   to the program's stderr when it is run.
528    ///   Do not enable in production!
529    ///
530    /// ### Field-level attributes:
531    ///
532    /// * **`#[deftly(netdoc(keyword = STR))]`**:
533    ///
534    ///   Use `STR` as the Keyword for this Item.
535    ///
536    /// * **`#[deftly(netdoc(single_arg))]`**:
537    ///
538    ///   The field type implements `ItemArgumentParseable`,
539    ///   instead of `ItemValueParseable`,
540    ///   and is parsed as if `(FIELD_TYPE,)` had been written.
541    ///
542    /// * **`#[deftly(netdoc(with = MODULE))]`**:
543    ///
544    ///   Instead of `ItemValueParseable`, the item is parsed with `MODULE::from_unparsed`,
545    ///   which must have the same signature as [`ItemValueParseable::from_unparsed`].
546    ///
547    ///   (Not supported for sub-documents, signature items, or field collections.)
548    ///
549    /// * **`#[deftly(netdoc(default))]`**:
550    ///
551    ///   This field is optional ("at most once");
552    ///   if not present, `FIELD_TYPE::default()` will be used.
553    ///
554    ///   This is an alternative to declaring the field type as `Option`
555    ///   With `netdoc(default)`, the field value doesn't need unwrapping.
556    ///   With `Option` it is possible to see if the field was provided.
557    ///
558    /// * **`#[deftly(netdoc(flatten))]`**:
559    ///
560    ///   This field is a struct containing further individual normal fields.
561    ///   The Items for those individual fields can appear in *this*
562    ///   outer document in any order, interspersed with other normal fields.
563    ///
564    ///   The field type must implement [`NetdocParseableFields`].
565    ///
566    /// * **`#[deftly(netdoc(skip))]`**:
567    ///
568    ///   This field doesn't really appear in the network document.
569    ///   It won't be recognised during parsing.
570    ///   Instead, `Default::default()` will be used for the field value.
571    ///
572    /// * **`#[deftly(netdoc(subdoc))]`**:
573    ///
574    ///   This field is a sub-document.
575    ///   The value type `T` must implement [`NetdocParseable`]
576    ///   *instead of* `ItemValueParseable`.
577    ///
578    ///   The field name is not used for parsging;
579    ///   the sub-document's intro keyword is used instead.
580    ///
581    ///   Sub-documents are expected to appear after all normal items,
582    ///   in the order presented in the struct definition.
583    ///
584    /// # Example
585    ///
586    /// ```
587    /// use derive_deftly::Deftly;
588    /// use tor_netdoc::derive_deftly_template_AsMutSelf;
589    /// use tor_netdoc::derive_deftly_template_NetdocParseableSignatures;
590    /// use tor_netdoc::derive_deftly_template_NetdocParseableUnverified;
591    /// use tor_netdoc::derive_deftly_template_ItemValueParseable;
592    /// use tor_netdoc::parse2::{
593    ///     parse_netdoc, ErrorProblem, ParseInput, VerifyFailed,
594    ///     SignatureItemParseable, SignatureHashesAccumulator, SignatureHashInputs,
595    /// };
596    ///
597    /// #[derive(Deftly, Debug, Clone)]
598    /// #[derive_deftly(NetdocParseableUnverified)]
599    /// pub struct NdThing {
600    ///     pub thing_start: (),
601    ///     pub value: (String,),
602    /// }
603    ///
604    /// #[derive(Deftly, Debug, Clone)]
605    /// #[derive_deftly(NetdocParseableSignatures)]
606    /// #[deftly(netdoc(signatures(hashes_accu = UseLengthAsFoolishHash)))]
607    /// pub struct NdThingSignatures {
608    ///     pub signature: FoolishSignature,
609    /// }
610    ///
611    /// #[derive(Deftly, Debug, Clone)]
612    /// #[derive_deftly(ItemValueParseable)]
613    /// #[deftly(netdoc(signature(hash_accu = UseLengthAsFoolishHash)))]
614    /// pub struct FoolishSignature {
615    ///     pub doc_len: usize,
616    /// }
617    ///
618    /// #[derive(Deftly, Debug, Default, Clone)]
619    /// #[derive_deftly(AsMutSelf)]
620    /// pub struct UseLengthAsFoolishHash {
621    ///     pub doc_len_actual_pretending_to_be_hash: Option<usize>,
622    /// }
623    /// impl SignatureHashesAccumulator for UseLengthAsFoolishHash {
624    ///     fn update_from_netdoc_body(
625    ///         &mut self,
626    ///         document_body: &SignatureHashInputs<'_>,
627    ///     ) -> Result<(), ErrorProblem> {
628    ///         self
629    ///             .doc_len_actual_pretending_to_be_hash
630    ///             .get_or_insert_with(|| document_body.body().body().len());
631    ///         Ok(())
632    ///     }
633    /// }
634    ///
635    /// let doc_text =
636    /// r#"thing-start
637    /// value something
638    /// signature 28
639    /// "#;
640    ///
641    /// impl NdThingUnverified {
642    ///     pub fn verify_foolish_timeless(self) -> Result<NdThing, VerifyFailed> {
643    ///         let sig = &self.sigs.sigs.signature;
644    ///         let hash = self.sigs.hashes.doc_len_actual_pretending_to_be_hash
645    ///             .as_ref().ok_or(VerifyFailed::Bug)?;
646    ///         if sig.doc_len != *hash {
647    ///             return Err(VerifyFailed::VerifyFailed);
648    ///         }
649    ///         Ok(self.body)
650    ///     }
651    /// }
652    ///
653    /// let input = ParseInput::new(&doc_text, "<input>");
654    /// let doc: NdThingUnverified = parse_netdoc(&input).unwrap();
655    /// let doc = doc.verify_foolish_timeless().unwrap();
656    /// assert_eq!(doc.value.0, "something");
657    /// ```
658    export NetdocParseable for struct, meta_quoted rigorous, expect items, beta_deftly:
659
660    ${define NETDOC_PARSEABLE_TTYPE { $ttype }}
661    ${define FINISH_RESOLVE_PARSEABLE $FINISH_RESOLVE}
662
663    $IMPL_NETDOC_PARSEABLE
664}
665
666//==================== NetdocParseableSignatures user-facing derive macro ====================
667//
668// deftly template `NetdocParseableSignatures`:
669//
670//  * entrypoint for deriving the `NetdocParseableSignatures` trait
671//  * docs for the signatures-section-specific attributes
672//  * implementation of that derive
673//
674// Much of the heavy lifting is done in the NetdocSomeItemsParseableCommon deftly module.
675
676define_derive_deftly! {
677    use NetdocDeriveAnyCommon;
678    use NetdocParseAnyCommon;
679    use NetdocSomeItemsDeriveCommon;
680    use NetdocSomeItemsParseableCommon;
681
682    /// Derive [`NetdocParseable`] for the signatures section of a network document
683    ///
684    /// This type is the signatures section of another document.
685    /// Signature sections have no separate intro keyword:
686    /// every field is structural and they are recognised in any order.
687    ///
688    /// This signatures sub-document will typically be included in a
689    /// `FooUnverified` struct derived with
690    /// [`NetdocUnverified`](derive_deftly_template_NetdocUnverified),
691    /// rather than included anywhere manually.
692    ///
693    /// ### Expected input structure
694    ///
695    /// Should be applied named-field struct, where each field
696    /// implements [`SignatureItemParseable`],
697    /// or is a `SignatureItemParseable` in `Vec` or `BTreeSet` or `Option`.
698    ///
699    /// ### Attributes
700    ///
701    ///  * The following top-level attributes are supported:
702    ///    `#[deftly(netdoc(debug))]`
703    ///
704    ///  * The following field-level attributes are supported:
705    ///    `#[deftly(netdoc(keyword = STR))]`
706    ///    `#[deftly(netdoc(default))]`
707    ///    `#[deftly(netdoc(single_arg))]`
708    ///    `#[deftly(netdoc(with = MODULE))]`
709    ///    `#[deftly(netdoc(flatten))]`
710    ///    `#[deftly(netdoc(skip))]`
711    ///
712    /// ### Signature item ordering, and signatures covering signatures
713    ///
714    /// The derived code does not impose any mutual ordering of signatures.
715    /// If signatures are independent, hashing can be done with [`SignedDocumentBody`]
716    /// (from [`SignatureHashInputs::body`]).
717    ///
718    /// In sane netdoc signature scheme, no signatures would cover other signatures,
719    /// and there would be no ordering requirement on signatures on the same document.
720    ///  A relying party would verify the signatures that they are proposing to rely on
721    /// (which would generally include signatures for *one* algorithm, not several)
722    /// and ignore the others.
723    ///
724    /// (Such a signature, which also does not include any of its own item encoding
725    /// in its hash, is called Orderly.  See [SignedDocumentBody].)
726    ///
727    /// Unfortunately, many Tor netdocs have signature schemes
728    /// which are not sane (by this definition).
729    ///
730    /// When signatures are specified to cover other signatures,
731    /// the signature item implementation must contain ad-hoc code in
732    /// [`SignatureItemParseable::from_unparsed_and_body`].
733    /// to hash not only the body, but also the prior signatures.
734    /// Methods on [`SignatureHashInputs`] are available to get
735    /// the relevant parts of the input document text
736    /// (eg, [`document_sofar`](SignatureHashInputs::document_sofar)).
737    ///
738    /// When the spec states a required ordering on signature items,
739    /// this should be enforced by ad-hoc code in implementation(s) of
740    /// `SignatureItemParseable`.
741    /// The implementation should use
742    /// [`HashAccu`](SignatureItemParseable::HashAccu)
743    /// to store any necessary state.
744    /// Usually, this can be achieved by using the same Rust struct for the
745    /// `HashAccu` of each of the signature items:
746    /// that will make the signature hashes computed so far, for items seen so far,
747    /// visible to subsequent items;
748    /// the subsequent items can check that the prior items filled in the hash,
749    /// thus imposing an ordering.
750    ///
751    /// Alternatively, the ordering could be enforced in the user-supplied
752    /// ad-hoc `verify` function(s) on `FooUUnverified`.
753    ///
754    /// Note that this enforcement should be done for protocol compliance
755    /// and availability reasons, but is not a security issue.
756    /// There is not a security risk from accepting documents some of whose signatures
757    /// aren't covered by other signatures even though the protocol specifies they should be:
758    /// relying parties *verify* the signatures but do not treat them as trusted data.
759    /// So there is no engineered safeguard against failing to implement
760    /// signature item ordering checks.
761    export NetdocParseableSignatures for struct, meta_quoted rigorous, expect items, beta_deftly:
762
763    ${defcond F_INTRO false}
764    ${defcond F_SUBDOC false}
765    ${defcond F_SIGNATURE true}
766
767    // NetdocParseableSignatures::HashesAccu
768    ${define SIGS_HASHES_ACCU_TYPE { ${tmeta(netdoc(signatures(hashes_accu))) as ty} }}
769
770    ${define THIS_ITEM { input.next_item()?.expect("peeked") }}
771    ${define F_ACCUMULATE_VAR { (&mut $fpatname) }}
772
773    impl<$tgens> $P::NetdocParseableSignatures for $ttype {
774        type HashesAccu = $SIGS_HASHES_ACCU_TYPE;
775
776        fn is_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
777            use $P::*;
778            ${for fields {
779                kw == $F_KEYWORD ||
780            }}
781                false
782        }
783
784        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
785        fn from_items<'s>(
786            input: &mut $P::ItemStream<'s>,
787            signed_doc_body: $P::SignedDocumentBody<'s>,
788            sig_hashes: &mut $SIGS_HASHES_ACCU_TYPE,
789            outer_stop: $P::stop_at!(),
790        ) -> $P::Result<$ttype, $P::ErrorProblem> {
791            use $P::*;
792            $DEFINE_DTRACE
793
794            //----- prepare item set selectors for every field -----
795            $ITEM_SET_SELECTORS
796            $CHECK_FIELD_TYPES_PARSEABLE
797            $INIT_ACCUMULATE_VARS
798
799            //----- parse the items -----
800            dtrace!("looking for signature items");
801
802            while let Some(kw) = input.peek_keyword()? {
803                dtrace!("for signatures, peeked", kw);
804                if outer_stop.stop_at(kw) {
805                    dtrace!("is outer stop", kw);
806                    break;
807                };
808
809                $NONSTRUCTURAL_ACCUMULATE_ELSE
810                {
811                    dtrace!("is unknown (in signatures)");
812                    let _: UnparsedItem = $THIS_ITEM;
813                }
814            }
815
816            // Resolve all the fields
817            dtrace!("reached end, resolving");
818
819            $FINISH_RESOLVE
820        }
821    }
822}
823
824//==================== NetdocParseableFields user-facing derive macro ====================
825//
826// deftly template `NetdocParseableFields`
827//
828//  * entrypoint for deriving the `NetdocParseableFields` trait
829//  * docs and implementation for that derive
830//
831// Much of the heavy lifting is done in the NetdocSomeItemsParseableCommon deftly module.
832
833define_derive_deftly! {
834    use NetdocDeriveAnyCommon;
835    use NetdocParseAnyCommon;
836    use NetdocFieldsDeriveCommon;
837    use NetdocSomeItemsDeriveCommon;
838    use NetdocSomeItemsParseableCommon;
839
840    /// Derive [`NetdocParseableFields`] for a struct with individual items
841    ///
842    /// Defines a struct `FooNetdocParseAccumulator` to be the
843    /// `NetdocParseableFields::Accumulator`.
844    ///
845    /// Similar to
846    /// [`#[derive_deftly(NetdocParseable)]`](derive_deftly_template_NetdocParseable),
847    /// but:
848    ///
849    ///  * Derives [`NetdocParseableFields`]
850    $DOC_NETDOC_FIELDS_DERIVE_SUPPORTED
851    ///
852    export NetdocParseableFields for struct , meta_quoted rigorous, expect items, beta_deftly:
853
854    ${define THIS_ITEM item}
855    ${define F_ACCUMULATE_VAR { (&mut acc.$fname) }}
856
857    #[doc = ${concat "Partially parsed `" $tname "`"}]
858    ///
859    /// Used for [`${concat $P::NetdocParseableFields::Accumulator}`].
860    #[derive(Default, Debug)]
861    $tvis struct $<$tname NetdocParseAccumulator><$tdefgens> { $(
862        $fname: $F_ACCUMULATE_TYPE,
863    ) }
864
865    impl<$tgens> $P::NetdocParseableFields for $ttype {
866        type Accumulator = $<$ttype NetdocParseAccumulator>;
867
868        fn is_item_keyword(
869            #[allow(unused_variables)] // If there are no fields, this is unused
870            kw: $P::KeywordRef<'_>,
871        ) -> bool {
872            #[allow(unused_imports)] // false positives in some situations
873            use $P::*;
874
875          ${for fields {
876            ${when not(F_FLATTEN)}
877            ${when not(F_SKIP)}
878            kw == $F_KEYWORD ||
879          }}
880          ${for fields {
881            ${when F_FLATTEN}
882            ${when not(F_SKIP)}
883            <$ftype as NetdocParseableFields>::is_item_keyword(kw) ||
884          }}
885            false
886        }
887
888        #[allow(clippy::redundant_locals)] // let item = $THIS_ITEM, which might be item
889        fn accumulate_item(
890            #[allow(unused_variables)] // If there are no fields, this is unused
891            acc: &mut Self::Accumulator,
892            #[allow(unused_variables)] // If there are no fields, this is unused
893            item: $P::UnparsedItem<'_>,
894        ) -> $P::Result<(), $P::ErrorProblem> {
895            #[allow(unused_imports)] // false positives in some situations
896            use $P::*;
897            $DEFINE_DTRACE
898
899            $ITEM_SET_SELECTORS
900            $CHECK_FIELD_TYPES_PARSEABLE
901
902            #[allow(unused_variables)] // If there are no fields, this is unused
903            let kw = item.keyword();
904
905            $NONSTRUCTURAL_ACCUMULATE_ELSE
906            {
907                panic!("accumulate_item called though is_item_keyword returns false");
908            }
909
910            #[allow(unreachable_code)] // If there are no fields!
911            Ok(())
912        }
913
914        fn finish(
915            #[allow(unused_variables)] // If there are no fields, this is unused
916            acc: Self::Accumulator
917        ) -> $P::Result<Self, $P::ErrorProblem> {
918            #[allow(unused_imports)] // false positives in some situations
919            use $P::*;
920            $DEFINE_DTRACE
921
922            dtrace!("finish, resolving");
923
924            $ITEM_SET_SELECTORS
925
926         $(
927            ${when not(F_SKIP)}
928            let $fpatname = acc.$fname;
929         )
930            $FINISH_RESOLVE
931        }
932    }
933}
934
935//==================== NetdocParseableUnverified user-facing derive macro ====================
936//
937// deftly template `NetdocParseableUnverified`
938//
939//  * entrypoint for deriving the `FooUnverified` struct implementing `NetdocParseable`
940//    (and supporting items such as `FooUnverifiedParsedBody` structs and its impl).
941//  * docs for that derive, including doc-level signatures-related attributes
942//  * implementation glue for those derived impls
943//
944// The principal derived parsing impl on the body type `Foo` is expanded by this macro,
945// but that is implemented via IMPL_NETDOC_PARSEABLE in the NetdocParseable deftly module.
946//
947// The substantive code to implement `NetdocParseable` for `FooUnverified` is
948// in the `ItemStream::parse_signed` helper function; a call to that is expanded here.
949
950define_derive_deftly! {
951    use NetdocParseable;
952
953    /// Derive `NetdocParseable` for a top-level signed document
954    ///
955    /// ### Expected input structure
956    ///
957    /// Apply this derive to the main body struct `Foo`,
958    /// which should meet all the requirements to derive
959    /// [`NetdocParseable`](derive_deftly_template_NetdocParseable).
960    ///
961    /// Usually, the caller will provide suitable ad-hoc `.verify_...` methods
962    /// on `FooUnverified`.
963    ///
964    /// ### Generated code
965    ///
966    /// Supposing your input structure is `Foo`, this macro will
967    /// generate a `**struct FooUnverified`**
968    /// implementing [`NetdocParseable`] and [`NetdocUnverified`]:
969    ///
970    /// ```rust,ignore
971    /// # struct Foo; struct FooSignatures;
972    /// pub struct FooUnverified {
973    ///     body: Foo,
974    ///     pub sigs: SignaturesData<FooUnverified>,
975    /// }
976    /// ```
977    ///
978    /// Also generated is `FooUnverifiedParsedBody`
979    /// and an impl of [`HasUnverifiedParsedBody`] on `Foo`.
980    /// These allow the generated code to call [`ItemStream::parse_signed`]
981    /// and it should not normally be necessary to use them elsewhere.
982    ///
983    /// ### Required top-level attributes:
984    ///
985    /// * **`#[deftly(netdoc(signature = TYPE))]`**:
986    ///   Type of the signature(s) section.
987    ///
988    ///   TYPE must implement `NetdocParseable`,
989    ///   with `is_intro_item_keyword` reporting *every* signature keyword.
990    ///   Normally this is achieved with
991    ///   `#[derive_deftly(NetdocParseable)] #[deftly(netdoc(signatures))]`.
992    ///
993    /// ### Optional attributes
994    ///
995    /// All the attributes supported by the `NetdocParseable` derive are supported.
996    //
997    // We don't make NetdocUnverified a generic struct because
998    //  - the defining module (crate) will want to add verification methods,
999    //    which means they must define the struct
1000    //  - that lets the actual `body` field be private to the defining module.
1001    export NetdocParseableUnverified for struct, meta_quoted rigorous, expect items, beta_deftly:
1002
1003    ${define NETDOC_PARSEABLE_TTYPE { $<$ttype UnverifiedParsedBody> }}
1004    ${define FINISH_RESOLVE_PARSEABLE {
1005        { $FINISH_RESOLVE }
1006        .map(|unverified| $<$tname UnverifiedParsedBody> { unverified })
1007    }}
1008
1009    $IMPL_NETDOC_PARSEABLE
1010
1011    // FooSignatures (type name)
1012    ${define SIGS_TYPE { $< ${tmeta(netdoc(signatures)) as ty, default $<$ttype Signatures>} > }}
1013    ${define SIGS_DATA_TYPE { $P::SignaturesData<$<$ttype Unverified>> }}
1014    ${define SIGS_HASHES_ACCU_TYPE { <$SIGS_TYPE as $P::NetdocParseableSignatures>::HashesAccu }}
1015
1016   $///Signed (unverified) form of [`$tname`]
1017    ///
1018    /// Embodies:
1019    ///
1020   $///  * **[`$tname`]**: document body
1021   $///  * **[`$SIGS_TYPE`]**: signatures
1022    ///
1023    /// If this type was parsed from a document text,
1024    /// the signatures have *not* yet been verified.
1025    ///
1026    /// Use a `.verify_...` method to obtain useable, verified, contents.
1027    #[derive(Debug, Clone)]
1028    $tvis struct $<$ttype Unverified> {
1029        /// The actual body
1030        //
1031        // Misuse is prevented by this field not being public.
1032        // It can be accessed only in this module, where the verification functions are.
1033        body: $ttype,
1034
1035        /// Signatures
1036        $tvis sigs: $SIGS_DATA_TYPE,
1037    }
1038
1039    /// The parsed but unverified body part of a signed network document (working type)
1040    ///
1041   $/// Contains a $tname which has been parsed
1042    /// as part of a signed document,
1043    /// but the signatures aren't embodied here, and have not been verified.
1044    ///
1045    /// Not very useful to callers, who should use the `BodyUnverified` type instead,
1046    /// and its implementation of `NetdocParseable`.
1047    //
1048    // We implement NetdocParseable on FooUnverified using ItemStream::parse_signed.
1049    // ItemStream::parse_signed is a fairly normal but ad-hoc
1050    // implementation of NetdocParseable which uses as subroutines implementations
1051    // of NetdocParseable for the body and NetdocParseableSignatures for the signatures.
1052    //
1053    // We need a newtype because we don't want to implement `NetdocParseable`
1054    // for a type which is just the body.  Such an impl would be usable by mistake,
1055    // via the top-level parse2 functions, and it would then simply discard the signatures
1056    // and return unverified data, bypassing our efforts to prevent such bugs.
1057    //
1058    // Ideally we would have a generic `UnverifiedParsedBody<B>` type or something
1059    // but then this macro, invoked in other crates, couldn't impl NetdocParseable for
1060    // UnverifiedParsedBody<TheirType>, due to trait coherence rules.
1061    //
1062    #[derive(derive_more::From)]
1063    pub struct $NETDOC_PARSEABLE_TTYPE<$tdefgens> {
1064        /// The unverified body
1065        unverified: $ttype,
1066    }
1067
1068    impl<$tgens> $P::NetdocParseable for $<$ttype Unverified> {
1069        fn doctype_for_error() -> &'static str {
1070            $NETDOC_PARSEABLE_TTYPE::doctype_for_error()
1071        }
1072
1073        fn is_intro_item_keyword(kw: $P::KeywordRef<'_>) -> bool {
1074            $NETDOC_PARSEABLE_TTYPE::is_intro_item_keyword(kw)
1075        }
1076
1077        fn is_structural_keyword(kw: $P::KeywordRef<'_>) -> Option<$P::IsStructural> {
1078            $NETDOC_PARSEABLE_TTYPE::is_structural_keyword(kw).or_else(
1079                || <$SIGS_TYPE as $P::NetdocParseableSignatures>
1080                    ::is_item_keyword(kw).then_some($P::IsStructural)
1081            )
1082        }
1083
1084        fn from_items<'s>(
1085            input: &mut $P::ItemStream<'s>,
1086            outer_stop: $P::stop_at!(),
1087        ) -> $P::Result<$<$ttype Unverified>, $P::ErrorProblem> {
1088            $EMIT_DEBUG_PLACEHOLDER
1089            input.parse_signed(outer_stop)
1090        }
1091    }
1092
1093    impl<$tgens> $P::NetdocUnverified for $<$ttype Unverified> {
1094        type Body = $ttype;
1095        type Signatures = $SIGS_TYPE;
1096        fn inspect_unverified(&self) -> (&Self::Body, &$SIGS_DATA_TYPE) {
1097            (&self.body, &self.sigs)
1098        }
1099        fn unwrap_unverified(self) -> (Self::Body, $SIGS_DATA_TYPE) {
1100            (self.body, self.sigs)
1101        }
1102        fn from_parts(body: Self::Body, sigs: $SIGS_DATA_TYPE) -> Self {
1103            Self { body, sigs }
1104        }
1105    }
1106
1107    impl<$tgens> $P::HasUnverifiedParsedBody for $ttype {
1108        type UnverifiedParsedBody = $NETDOC_PARSEABLE_TTYPE;
1109        fn unverified_into_inner_unchecked(unverified: Self::UnverifiedParsedBody) -> Self {
1110            unverified.unverified
1111        }
1112    }
1113}
1114
1115//==================== ItemValueParseable user-facing derive macro ====================
1116//
1117// deftly template `ItemValueParseable`
1118//
1119//  * entrypoint for deriving the `ItemValueParseable` and `SignatureItemParseable` traits
1120//  * docs for the meta attributes we support during *item* parsing
1121//  * implementation of those derives
1122
1123define_derive_deftly! {
1124    use NetdocDeriveAnyCommon;
1125    use NetdocParseAnyCommon;
1126    use NetdocItemDeriveCommon;
1127
1128    /// Derive `ItemValueParseable` (or `SignatureItemParseable`)
1129    ///
1130    // NB there is very similar wording in the ItemValueEncodable derive docs.
1131    // If editing any of this derive's documentation, considering editing that too.
1132    //
1133    /// Fields in the struct are parsed from the keyword line arguments,
1134    /// in the order they appear in the struct.
1135    ///
1136    /// ### Field type
1137    ///
1138    /// Each field should be:
1139    ///
1140    ///  * `impl `[`ItemArgumentParseable`] (one argument),
1141    ///  * `Option<impl ItemArgumentParseable>` (one optional argument),
1142    ///  * `Vec<impl ItemArgumentParseable>` (zero or more arguments), or
1143    ///  * `BTreeSet<impl ItemArgumentParseable + Ord>` (zero or more arguments).
1144    ///
1145    /// `ItemArgumentParseable` can be implemented via `impl FromStr`,
1146    /// by writing `impl NormalItemArgument`.
1147    ///
1148    /// For `Option` or `Vec`, we expect that *if* there are any further arguments,
1149    /// they are for this field.
1150    /// So absence of any optional argument means absence of following arguments,
1151    /// and no arguments can follow a `Vec`.
1152    ///
1153    /// Some Tor netdocs have optional arguments followed by other data,
1154    /// with unclear/ambiguous parsing rules.
1155    /// These cases typically require manual implementation of [`ItemValueParseable`].
1156    ///
1157    /// (Multiplicity is implemented via types in the [`multiplicity`] module,
1158    /// specifically [`ArgumentSetSelector`] and [`ArgumentSetMethods`].)
1159    ///
1160    /// ### Top-level attributes:
1161    ///
1162    ///  * **`#[deftly(netdoc(no_extra_args))]**:
1163    ///
1164    ///    Reject, rather than ignore, additional arguments found in the document
1165    ///    which aren't described by the struct.
1166    ///
1167    ///  * **`#[deftly(netdoc(signature(hash_accu = HASH_ACCU))]**:
1168    ///
1169    ///    This item is a signature item.
1170    ///    [`SignatureItemParseable`] will be implemented instead of [`ItemValueParseable`].
1171    ///
1172    ///    **`HASH_ACCU`** is the type in which the hash(es) for this item will be accumulated,
1173    ///    and must implement [`SignatureHashesAccumulator`].
1174    ///    It is used as [`SignatureItemParseable::HashAccu`].
1175    ///
1176    /// * **`#[deftly(netdoc(debug))]`**:
1177    ///
1178    ///   Currently implemented only as a placeholder
1179    ///
1180    ///   The generated implementation may in future generate copious debug output
1181    ///   to the program's stderr when it is run.
1182    ///   Do not enable in production!
1183    ///
1184    $DOC_DEBUG_PLACEHOLDER
1185    ///
1186    /// ### Field-level attributes:
1187    ///
1188    ///  * **`#[deftly(netdoc(rest))]**:
1189    ///
1190    ///    The field is the whole rest of the line.
1191    ///    Must come after any other normal argument fields.
1192    ///    Only allowed once.
1193    ///
1194    ///    The field type must implement `FromStr`.
1195    ///    (I.e. `Vec` , `Option` etc., are not allowed, and `ItemArgumentParseable` is not used.)
1196    ///
1197    ///  * **`#[deftly(netdoc(object))]**:
1198    ///
1199    ///    The field is the Object.
1200    ///    It must implement [`ItemObjectParseable`]
1201    ///    (or be `Option<impl ItemObjectParseable>`).
1202    ///
1203    ///    Only allowed once.
1204    ///    If omittted, any object is rejected.
1205    ///
1206    ///  * **`#[deftly(netdoc(object(label = "LABEL")))]**:
1207    ///
1208    ///    Sets the expected label for an Object.
1209    ///    If not supplied, uses [`ItemObjectParseable::check_label`].
1210    ///
1211    ///  * **`#[deftly(netdoc(with = MODULE)]**:
1212    ///
1213    ///    Instead of `ItemArgumentParseable`, the argument is parsed with `MODULE::from_args`,
1214    ///    which must have the same signature as [`ItemArgumentParseable::from_args`].
1215    ///
1216    ///    With `#[deftly(netdoc(rest))]`, the argument is parsed with `MODULE::from_args_rest`,
1217    ///    must have the signature
1218    ///    `fn from_args_rest(s: &str) -> Result<FIELD, _>`).
1219    ///    and replaces `<FIELD as FromStr>::from_str`.
1220    ///
1221    ///    With `#[deftly(netdoc(object))]`, uses `MODULE::try_from`
1222    ///    which must have the signature `fn(Vec<u8>) -> Result<OBJECT, _>;
1223    ///    like `TryFrom::<Vec<u8>>>::try_from`.
1224    ///    LABEL must also be specified
1225    ///    unless the object also implements `ItemObjectParseable`.
1226    ///    Errors from parsing will all be collapsed into
1227    ///    [`ErrorProblem::ObjectInvalidData`].
1228    ///
1229    ///  * **`#[deftly(netdoc(skip))]**:
1230    ///
1231    ///    Do not parse this field; fill it in with `Default::default()` instead.
1232    export ItemValueParseable for struct, meta_quoted rigorous, expect items, beta_deftly:
1233
1234    ${define TRAIT ${if T_IS_SIGNATURE { SignatureItemParseable } else { ItemValueParseable }}}
1235    ${define METHOD ${if T_IS_SIGNATURE { from_unparsed_and_body } else { from_unparsed }}}
1236
1237    // SignatureItemParseable::HashAccu
1238    ${define SIG_HASH_ACCU_TYPE ${tmeta(netdoc(signature(hash_accu))) as ty}}
1239
1240    impl<$tgens> $P::$TRAIT for $ttype {
1241      ${if T_IS_SIGNATURE {
1242        type HashAccu = $SIG_HASH_ACCU_TYPE;
1243      }}
1244
1245        fn $METHOD<'s>(
1246            mut input: $P::UnparsedItem<'s>,
1247          ${if T_IS_SIGNATURE {
1248            document_body: &SignatureHashInputs<'_>,
1249            hash_accu: &mut $SIG_HASH_ACCU_TYPE,
1250          }}
1251        ) -> $P::Result<Self, $P::EP>
1252        {
1253            #[allow(unused_imports)] // false positive when macro is used with prelude in scope
1254            use $P::*;
1255
1256            $DEFINE_DTRACE
1257
1258            dtrace!(
1259                "item start",
1260                input.keyword().as_str(),
1261                input.args_copy().into_remaining(),
1262                input.object().map(|o| o.label()),
1263            );
1264
1265            ${if T_IS_SIGNATURE {
1266                <$SIG_HASH_ACCU_TYPE as SignatureHashesAccumulator>::update_from_netdoc_body(
1267                    hash_accu,
1268                    document_body
1269                )?;
1270            }}
1271
1272            let object = input.object();
1273            #[allow(unused)]
1274            let mut args = input.args_mut();
1275          $(
1276            #[allow(non_snake_case)]
1277            let $fpatname = ${select1
1278              F_NORMAL { {
1279                  let selector = MultiplicitySelector::<$ftype>::default();
1280                  dtrace!(
1281                      $"field $fname, normal",
1282                      selector.argument_set_debug(),
1283                      args.clone().into_remaining(),
1284                  );
1285                ${if not(fmeta(netdoc(with))) {
1286                  selector.${paste_spanned $fname check_argument_value_parseable}();
1287                }}
1288                  selector.parse_with(
1289                      &mut args,
1290                      ${fmeta(netdoc(with))
1291                        as path,
1292                        default { ItemArgumentParseable }}::${paste_spanned $fname from_args},
1293                  ).map_err(args.error_handler(stringify!($fname)))?
1294              } }
1295              F_OBJECT { {
1296                  let selector = MultiplicitySelector::<$ftype>::default();
1297                  dtrace!(
1298                      $"field $fname, object",
1299                      selector.object_set_debug(),
1300                      object.as_ref().map(|o| (o.label(), o.decode_data().map(|d| d.len()))),
1301                  );
1302                  let object = object.map(|object| {
1303                      let data = object.decode_data()?;
1304                      ${if fmeta(netdoc(object(label))) {
1305                          if object.label() != ${fmeta(netdoc(object(label))) as str} {
1306                              return Err(EP::ObjectIncorrectLabel)
1307                          }
1308                      } else {
1309                          selector.check_label(object.label())?;
1310                      }}
1311                      ${if fmeta(netdoc(with)) {
1312                          ${fmeta(netdoc(with)) as path}::${paste_spanned $fname try_from}
1313                              (data)
1314                              .map_err(|_| EP::ObjectInvalidData)
1315                      } else {
1316                          selector.${paste_spanned $fname check_object_parseable}();
1317                          ItemObjectParseable::from_bytes(&data)
1318                      }}
1319                  }).transpose()?;
1320                  selector.resolve_option(object)?
1321              } }
1322              F_REST { {
1323                  dtrace!($"field $fname, rest", args.clone().into_remaining());
1324                  // consumes `args`, leading to compile error if the rest field
1325                  // isn't last (or is combined with no_extra_args).
1326                  let args_consume = args;
1327                  ${if fmeta(netdoc(with)) {
1328                      ${fmeta(netdoc(with)) as path}::${paste_spanned $fname from_args_rest}
1329                  } else {
1330                      <$ftype as FromStr>::from_str
1331                  }}
1332                      (args_consume.into_remaining())
1333                      .map_err(|_| AE::Invalid)
1334                      .map_err(args_consume.error_handler(stringify!($fname)))?
1335              } }
1336              F_SKIP { {
1337                  <$ftype as Default>::default()
1338              } }
1339            };
1340          )
1341          ${if approx_equal({}, $( ${when F_OBJECT} $fname )) {
1342            if object.is_some() {
1343                return Err(EP::ObjectUnexpected);
1344            }
1345          }}
1346          ${if tmeta(netdoc(no_extra_args)) {
1347            args.reject_extra_args()?;
1348          }}
1349            dtrace!("item complete Ok");
1350            Ok($tname { $( $fname: $fpatname, ) })
1351        }
1352    }
1353}