Skip to main content

tor_netdoc/parse2/
multiplicity.rs

1//! Multiplicity of fields (Items and Arguments)
2//!
3//! This module supports type-based handling of multiplicity,
4//! of Items (within Documents) and Arguments (in Item keyword lines).
5//!
6//! It is **for use by macros**, rather than directly.
7//!
8//! See also `encode::multiplicity` which is the corresponding module for encoding.
9//!
10//! # Explanation
11//!
12//! We use autoref specialisation to allow macros to dispatch to
13//! trait impls for `Vec<T: ItemValueParseable>`, `Option<T>` etc.
14//! as well as simply unadorned `T`.
15//!
16//! We implement traits on a helper type `struct `[`MultiplicitySelector<Field>`].
17//!
18//! For Items we have `trait `[`ItemSetMethods`].
19//!
20//! `ItemSetMethods` is implemented for `MultiplicitySelector<Field>`
21//! for each supported `Field`.
22//! So, for `MultiplicitySelector<T>`, `MultiplicitySelector<Option<T>>`, and `MultiplicitySelector<Vec<T>>`.
23//! *But*, for just `T`, the impl is on `&MultiplicitySelector<T>`.
24//!
25//! When methods on `MultiplicitySelector` are called, the compiler finds
26//! the specific implementation for `MultiplicitySelector<Option<_>>` or `..Vec<_>`,
27//! or, failing that, derefs and finds the blanket impl on `&MultiplicitySelector<T>`.
28//!
29//! For Arguments we have [`ArgumentSetMethods`],
30//! and for Objects, [`ObjectSetMethods`],
31//! which work similarly.
32//!
33//! (We need separate traits for each of the kinds of netdoc element,
34//! for good support of inference in the derive macro.
35//! Type inference is particularly difficult during parsing, since we need the type
36//! information to flow from the field type, which is the *destination*
37//!  to which a value is going to be stored.)
38
39use super::*;
40use crate::types::RetainedOrderVec;
41
42#[cfg(doc)]
43use crate::encode;
44
45/// Helper type that allows us to select an impl of `ItemSetMethods` etc.
46///
47/// **For use by macros**.
48///
49/// See the [module-level docs](multiplicity).
50///
51/// This is distinct from `encode::MultiplicitySelector`,
52/// principally because it has the opposite variance.
53#[derive(Educe)]
54#[educe(Clone, Copy, Default)]
55pub struct MultiplicitySelector<Field>(PhantomData<fn() -> Field>);
56
57/// Helper type that allows us to implement Debug
58///
59/// Returned by [`ItemSetMethods::item_set_debug`] etc.,
60/// using information from [`ItemSetMethods::debug_core`] etc.
61#[derive(derive_more::Debug)]
62#[debug("{}={}", self.0, self.1)]
63#[allow(dead_code)] // yes, they are only read by the Debug impl - that's what they're for!
64struct DebugHelper(
65    /// scope, eg `items`
66    &'static str,
67    /// multiplicity type pattern, eg `Vec<_>` or `1`
68    &'static str,
69);
70
71/// Methods for handling some multiplicity of Items, during parsing
72///
73/// **For use by macros**.
74///
75/// During parsing, we accumulate into a value of type `Option<Self::Field>`.
76/// The semantics of this are item-set-implementation-dependent;
77/// using a type which is generic over the field type in a simple way
78/// allows the partially-parsed accumulation state for a whole netdoc to have a concrete type.
79///
80/// See the [module-level docs](multiplicity), and
81/// [Field type in `NetdocParseable`](derive_deftly_template_NetdocParseable#field-type).
82///
83/// # Example
84///
85/// The code in the (derive) macro output is roughly like this:
86///
87/// ```
88/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ItemSetMethods as _};
89///
90/// let selector = MultiplicitySelector::<Vec<i32>>::default();
91/// let mut accum = None;
92/// selector.accumulate(&mut accum, 12).unwrap();
93/// let out = selector.finish(accum, "item-set").unwrap();
94///
95/// assert_eq!(out, [12]);
96/// ```
97//
98// When implementing this, update the documentation in the `NetdocParseable` derive.
99pub trait ItemSetMethods: Copy + Sized {
100    /// The value for each Item.
101    ///
102    /// Should match the corresponding
103    /// [`encode::MultiplicityMethods::Each`].
104    /// (See docs there for rationale.)
105    type Each: Sized;
106
107    /// The output type: the type of the field in the netdoc struct.
108    type Field: Sized;
109
110    /// Can we accumulate another item ?
111    ///
112    /// Can be used to help predict whether `accumulate` will throw.
113    fn can_accumulate(self, acc: &Option<Self::Field>) -> Result<(), EP>;
114
115    /// Accumulate one value into the accumulator.
116    fn accumulate(self, acc: &mut Option<Self::Field>, one: Self::Each) -> Result<(), EP>;
117
118    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output, core
119    ///
120    /// Should generally be in a form like `Vec<_>`.
121    ///
122    /// See also [`ItemSetMethods::item_set_debug`], which is what the derives call.
123    //
124    // This can't be a `Debug` supertrait, because that won't work
125    // with the `&'_ MultiplicitySelector<T>` impl.
126    fn debug_core(self) -> &'static str;
127
128    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output
129    ///
130    /// This adds a bit framing and type-fu that allows the derive macro's
131    /// call to be as simple as possible.
132    ///
133    /// See also [`ItemSetMethods::debug_core`], which is what each multiplicity implements.
134    //
135    // dtrace!, which we use for debugging in the parser macros, doesn't print variable names,
136    // thinking things are probably obvious enough.  But for the elector here we want to
137    // include `items=`.
138    fn item_set_debug(self) -> impl Debug {
139        DebugHelper("items", self.debug_core())
140    }
141
142    /// Resolve the accumulator into the output.
143    fn finish(
144        self,
145        acc: Option<Self::Field>,
146        item_keyword: &'static str,
147    ) -> Result<Self::Field, EP>;
148
149    /// If the contained type is a sub-document, call its `is_intro_item_keyword`.
150    fn is_intro_item_keyword(self, kw: KeywordRef<'_>) -> bool
151    where
152        Self::Each: NetdocParseable,
153    {
154        Self::Each::is_intro_item_keyword(kw)
155    }
156
157    /// If the contained type is a sub-document, call its `is_structural_keyword`.
158    fn is_structural_keyword(self, kw: KeywordRef<'_>) -> Option<IsStructural>
159    where
160        Self::Each: NetdocParseable,
161    {
162        Self::Each::is_structural_keyword(kw)
163    }
164
165    /// `finish` for if the contained type is a wsub-document
166    ///
167    /// Obtain the sub-document's intro keyword from its `doctype_for_error`.
168    fn finish_subdoc(self, acc: Option<Self::Field>) -> Result<Self::Field, EP>
169    where
170        Self::Each: NetdocParseable,
171    {
172        self.finish(acc, Self::Each::doctype_for_error())
173    }
174
175    /// Check that the element type is an Item
176    ///
177    /// For providing better error messages when struct fields don't implement the right trait.
178    /// See `derive.rs`, and search for this method name.
179    fn check_item_value_parseable(self)
180    where
181        Self::Each: ItemValueParseable,
182    {
183    }
184    /// Check that the element type is a Signature
185    fn check_signature_item_parseable<H>(self, _: &mut H)
186    where
187        Self::Each: SignatureItemParseable,
188        H: AsMut<<Self::Each as SignatureItemParseable>::HashAccu>,
189    {
190    }
191    /// Check that the element type is a sub-document
192    fn check_subdoc_parseable(self)
193    where
194        Self::Each: NetdocParseable,
195    {
196    }
197    /// Check that the element type is an argument
198    fn check_item_argument_parseable(self)
199    where
200        Self::Each: ItemArgumentParseable,
201    {
202    }
203}
204impl<T> ItemSetMethods for MultiplicitySelector<Vec<T>> {
205    type Each = T;
206    type Field = Vec<T>;
207    // We always have None, or Some(nonempty)
208    fn can_accumulate(self, _acc: &Option<Vec<T>>) -> Result<(), EP> {
209        Ok(())
210    }
211    fn accumulate(self, acc: &mut Option<Vec<T>>, item: T) -> Result<(), EP> {
212        acc.get_or_insert_default().push(item);
213        Ok(())
214    }
215    fn finish(self, acc: Option<Vec<T>>, _keyword: &'static str) -> Result<Vec<T>, EP> {
216        Ok(acc.unwrap_or_default())
217    }
218    fn debug_core(self) -> &'static str {
219        "Vec<_>"
220    }
221}
222impl<T> ItemSetMethods for MultiplicitySelector<RetainedOrderVec<T>> {
223    type Each = T;
224    type Field = RetainedOrderVec<T>;
225    // We always have None, or Some(nonempty)
226    fn can_accumulate(self, _acc: &Option<RetainedOrderVec<T>>) -> Result<(), EP> {
227        Ok(())
228    }
229    fn accumulate(self, acc: &mut Option<RetainedOrderVec<T>>, item: T) -> Result<(), EP> {
230        acc.get_or_insert_default().0.push(item);
231        Ok(())
232    }
233    fn finish(
234        self,
235        acc: Option<RetainedOrderVec<T>>,
236        _keyword: &'static str,
237    ) -> Result<RetainedOrderVec<T>, EP> {
238        Ok(acc.unwrap_or_default())
239    }
240    fn debug_core(self) -> &'static str {
241        "RetainedOrderVec<_>"
242    }
243}
244impl<T: Ord> ItemSetMethods for MultiplicitySelector<BTreeSet<T>> {
245    type Each = T;
246    type Field = BTreeSet<T>;
247    // We always have None, or Some(nonempty)
248    fn can_accumulate(self, _acc: &Option<BTreeSet<T>>) -> Result<(), EP> {
249        Ok(())
250    }
251    fn accumulate(self, acc: &mut Option<BTreeSet<T>>, item: T) -> Result<(), EP> {
252        if !acc.get_or_insert_default().insert(item) {
253            return Err(EP::ItemRepeated);
254        }
255        Ok(())
256    }
257    fn finish(self, acc: Option<BTreeSet<T>>, _keyword: &'static str) -> Result<BTreeSet<T>, EP> {
258        Ok(acc.unwrap_or_default())
259    }
260    fn debug_core(self) -> &'static str {
261        "BTreeSet<_>"
262    }
263}
264impl<T> ItemSetMethods for MultiplicitySelector<Option<T>> {
265    type Each = T;
266    type Field = Option<T>;
267    // We always have None, or Some(Some(_))
268    fn can_accumulate(self, acc: &Option<Option<T>>) -> Result<(), EP> {
269        if acc.is_some() {
270            Err(EP::ItemRepeated)?;
271        }
272        Ok(())
273    }
274    // We always have None, or Some(Some(_))
275    fn accumulate(self, acc: &mut Option<Option<T>>, item: T) -> Result<(), EP> {
276        self.can_accumulate(acc)?;
277        *acc = Some(Some(item));
278        Ok(())
279    }
280    fn finish(self, acc: Option<Option<T>>, _keyword: &'static str) -> Result<Option<T>, EP> {
281        Ok(acc.flatten())
282    }
283    fn debug_core(self) -> &'static str {
284        "Option<_>"
285    }
286}
287impl<T> ItemSetMethods for &'_ MultiplicitySelector<T> {
288    type Each = T;
289    type Field = T;
290    fn can_accumulate(self, acc: &Option<T>) -> Result<(), EP> {
291        if acc.is_some() {
292            Err(EP::ItemRepeated)?;
293        }
294        Ok(())
295    }
296    fn accumulate(self, acc: &mut Option<T>, item: T) -> Result<(), EP> {
297        self.can_accumulate(acc)?;
298        *acc = Some(item);
299        Ok(())
300    }
301    fn finish(self, acc: Option<T>, keyword: &'static str) -> Result<T, EP> {
302        acc.ok_or(EP::MissingItem { keyword })
303    }
304    fn debug_core(self) -> &'static str {
305        // This appears in #[deftly(netdoc(debug))] output for singleton fields.
306        // We probably don't want the macros' users to have to think about our
307        // autoref-specialisation.  So we don't write anything about `&` here.
308        "1"
309    }
310}
311
312/// Method for handling some multiplicity of Arguments
313///
314/// **For use by macros**.
315///
316/// See the [module-level docs](multiplicity), and
317/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
318///
319/// # Example
320///
321/// The code in the (derive) macro output is roughly like this:
322///
323/// ```
324/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ArgumentSetMethods as _};
325/// use tor_netdoc::parse2::{ItemArgumentParseable, ItemStream, ParseInput};
326/// let doc = "intro-item 12 66\n";
327/// let input = ParseInput::new(doc, "<literal>");
328/// let mut items = ItemStream::new(&input).unwrap();
329/// let mut item = items.next().unwrap().unwrap();
330///
331/// let args = MultiplicitySelector::<Vec<i32>>::default()
332///     .parse_with(item.args_mut(), ItemArgumentParseable::from_args)
333///     .unwrap();
334/// assert_eq!(args, [12, 66]);
335/// ```
336//
337// When implementing this, update the documentation in the `ItemValueParseable` derive.
338pub trait ArgumentSetMethods: Copy + Sized {
339    /// The value for each Item.
340    ///
341    /// Should match the corresponding
342    /// [`encode::MultiplicityMethods::Each`].
343    /// (See docs there for rationale.)
344    type Each: Sized;
345
346    /// The output type: the type of the field in the Item struct.
347    ///
348    /// This is *not* the type of an individual netdoc argument;
349    /// that is not explicitly represented in the trait.
350    type Field: Sized;
351
352    /// Parse zero or more argument(s) into `Self::Field`.
353    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
354    where
355        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>;
356
357    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output, core
358    ///
359    /// Should generally be in a form like `Vec<_>`.
360    ///
361    /// See [`ItemSetMethods::debug_core`] and [`ArgumentSetMethods::argument_set_debug`].
362    fn debug_core(self) -> &'static str;
363
364    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output
365    ///
366    /// See [`ItemSetMethods::item_set_debug`] and [`ArgumentSetMethods::debug_core`].
367    fn argument_set_debug(self) -> impl Debug {
368        DebugHelper("args", self.debug_core())
369    }
370
371    /// Check that the element type is an Argument
372    ///
373    /// For providing better error messages when struct fields don't implement the right trait.
374    /// See `derive.rs`, and search for this method name.
375    fn check_argument_value_parseable(self)
376    where
377        Self::Each: ItemArgumentParseable,
378    {
379    }
380}
381impl<T> ArgumentSetMethods for MultiplicitySelector<Vec<T>> {
382    type Each = T;
383    type Field = Vec<T>;
384    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
385    where
386        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
387    {
388        let mut acc = vec![];
389        while args.something_to_yield() {
390            acc.push(parser(args)?);
391        }
392        Ok(acc)
393    }
394    fn debug_core(self) -> &'static str {
395        "Vec<_>"
396    }
397}
398impl<T: Ord> ArgumentSetMethods for MultiplicitySelector<BTreeSet<T>> {
399    type Each = T;
400    type Field = BTreeSet<T>;
401    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
402    where
403        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
404    {
405        let mut acc = BTreeSet::new();
406        while args.something_to_yield() {
407            if !acc.insert(parser(args)?) {
408                return Err(AE::Invalid);
409            }
410        }
411        Ok(acc)
412    }
413    fn debug_core(self) -> &'static str {
414        "BTreeSet<_>"
415    }
416}
417impl<T> ArgumentSetMethods for MultiplicitySelector<Option<T>> {
418    type Each = T;
419    type Field = Option<T>;
420    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
421    where
422        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
423    {
424        if !args.something_to_yield() {
425            return Ok(None);
426        }
427        Ok(Some(parser(args)?))
428    }
429    fn debug_core(self) -> &'static str {
430        "Option<_>"
431    }
432}
433impl<T> ArgumentSetMethods for &MultiplicitySelector<T> {
434    type Each = T;
435    type Field = T;
436    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
437    where
438        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
439    {
440        parser(args)
441    }
442    fn debug_core(self) -> &'static str {
443        "1"
444    }
445}
446
447/// Method for handling some multiplicity of Objects
448///
449/// **For use by macros**.
450///
451/// See the [module-level docs](multiplicity), and
452/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
453///
454/// # Example
455///
456/// The code in the (derive) macro output is roughly like this:
457///
458/// ```
459/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ObjectSetMethods as _};
460/// use tor_netdoc::parse2::{ItemStream, ParseInput};
461/// let doc = "intro-item\n-----BEGIN OBJECT-----\naGVsbG8=\n-----END OBJECT-----\n";
462/// let input = ParseInput::new(doc, "<literal>");
463/// let mut items = ItemStream::new(&input).unwrap();
464/// let mut item = items.next().unwrap().unwrap();
465///
466/// let selector = MultiplicitySelector::<Option<String>>::default();
467/// let obj = item.object().map(|obj| {
468///     let data = obj.decode_data().unwrap();
469///     String::from_utf8(data)
470/// }).transpose().unwrap();
471/// let obj = selector.resolve_option(obj).unwrap();
472/// assert_eq!(obj, Some("hello".to_owned()));
473/// ```
474pub trait ObjectSetMethods: Copy + Sized {
475    /// The value for each Item.
476    ///
477    /// Should match the corresponding
478    /// [`encode::OptionalityMethods::Each`].
479    /// (See [`encode::MultiplicityMethods::Each`] for rationale.)
480    type Each: Sized;
481
482    /// The output type: the type of the field in the Item struct.
483    type Field: Sized;
484
485    /// Parse zero or more argument(s) into `Self::Field`.
486    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP>;
487
488    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output, core
489    ///
490    /// Should generally be in a form like `Option<_>`.
491    ///
492    /// See [`ItemSetMethods::debug_core`] and [`ObjectSetMethods::object_set_debug`].
493    fn debug_core(self) -> &'static str;
494
495    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output
496    ///
497    /// See [`ItemSetMethods::item_set_debug`] and [`ObjectSetMethods::debug_core`].
498    fn object_set_debug(self) -> impl Debug {
499        DebugHelper("object", self.debug_core())
500    }
501
502    /// If the contained type is `ItemObjectParseable`, call its `check_label`
503    fn check_label(self, label: &str) -> Result<(), EP>
504    where
505        Self::Each: ItemObjectParseable,
506    {
507        Self::Each::check_label(label)
508    }
509
510    /// Check that the contained type can be parsed as an object
511    fn check_object_parseable(self)
512    where
513        Self::Each: ItemObjectParseable,
514    {
515    }
516}
517impl<T> ObjectSetMethods for MultiplicitySelector<Option<T>> {
518    type Field = Option<T>;
519    type Each = T;
520    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
521        Ok(found)
522    }
523    fn debug_core(self) -> &'static str {
524        "Option<_>"
525    }
526}
527impl<T> ObjectSetMethods for &MultiplicitySelector<T> {
528    type Field = T;
529    type Each = T;
530    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
531        found.ok_or(EP::MissingObject)
532    }
533    fn debug_core(self) -> &'static str {
534        "1"
535    }
536}