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