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::*;
40
41/// Helper type that allows us to select an impl of `ItemSetMethods` etc.
42///
43/// **For use by macros**.
44///
45/// See the [module-level docs](multiplicity).
46///
47/// This is distinct from `encode::MultiplicitySelector`,
48/// principally because it has the opposite variance.
49#[derive(Educe)]
50#[educe(Clone, Copy, Default)]
51pub struct MultiplicitySelector<Field>(PhantomData<fn() -> Field>);
52
53/// Methods for handling some multiplicity of Items, during parsing
54///
55/// **For use by macros**.
56///
57/// During parsing, we accumulate into a value of type `Option<Self::Field>`.
58/// The semantics of this are item-set-implementation-dependent;
59/// using a type which is generic over the field type in a simple way
60/// allows the partially-parsed accumulation state for a whole netdoc to have a concrete type.
61///
62/// See the [module-level docs](multiplicity), and
63/// [Field type in `NetdocParseable`](derive_deftly_template_NetdocParseable#field-type).
64///
65/// # Example
66///
67/// The code in the (derive) macro output is roughly like this:
68///
69/// ```
70/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ItemSetMethods as _};
71///
72/// let selector = MultiplicitySelector::<Vec<i32>>::default();
73/// let mut accum = None;
74/// selector.accumulate(&mut accum, 12).unwrap();
75/// let out = selector.finish(accum, "item-set").unwrap();
76///
77/// assert_eq!(out, [12]);
78/// ```
79//
80// When implementing this, update the documentation in the `NetdocParseable` derive.
81pub trait ItemSetMethods: Copy + Sized {
82    /// The value for each Item.
83    type Each: Sized;
84
85    /// The output type: the type of the field in the netdoc struct.
86    type Field: Sized;
87
88    /// Can we accumulate another item ?
89    ///
90    /// Can be used to help predict whether `accumulate` will throw.
91    fn can_accumulate(self, acc: &Option<Self::Field>) -> Result<(), EP>;
92
93    /// Accumulate one value into the accumulator.
94    fn accumulate(self, acc: &mut Option<Self::Field>, one: Self::Each) -> Result<(), EP>;
95
96    /// Resolve the accumulator into the output.
97    fn finish(
98        self,
99        acc: Option<Self::Field>,
100        item_keyword: &'static str,
101    ) -> Result<Self::Field, EP>;
102
103    /// If the contained type is a sub-document, call its `is_intro_item_keyword`.
104    fn is_intro_item_keyword(self, kw: KeywordRef<'_>) -> bool
105    where
106        Self::Each: NetdocParseable,
107    {
108        Self::Each::is_intro_item_keyword(kw)
109    }
110
111    /// If the contained type is a sub-document, call its `is_structural_keyword`.
112    fn is_structural_keyword(self, kw: KeywordRef<'_>) -> Option<IsStructural>
113    where
114        Self::Each: NetdocParseable,
115    {
116        Self::Each::is_structural_keyword(kw)
117    }
118
119    /// `finish` for if the contained type is a wsub-document
120    ///
121    /// Obtain the sub-document's intro keyword from its `doctype_for_error`.
122    fn finish_subdoc(self, acc: Option<Self::Field>) -> Result<Self::Field, EP>
123    where
124        Self::Each: NetdocParseable,
125    {
126        self.finish(acc, Self::Each::doctype_for_error())
127    }
128
129    /// Check that the element type is an Item
130    ///
131    /// For providing better error messages when struct fields don't implement the right trait.
132    /// See `derive.rs`, and search for this method name.
133    fn check_item_value_parseable(self)
134    where
135        Self::Each: ItemValueParseable,
136    {
137    }
138    /// Check that the element type is a Signature
139    fn check_signature_item_parseable(self)
140    where
141        Self::Each: SignatureItemParseable,
142    {
143    }
144    /// Check that the element type is a sub-document
145    fn check_subdoc_parseable(self)
146    where
147        Self::Each: NetdocParseable,
148    {
149    }
150    /// Check that the element type is an argument
151    fn check_item_argument_parseable(self)
152    where
153        Self::Each: ItemArgumentParseable,
154    {
155    }
156}
157impl<T> ItemSetMethods for MultiplicitySelector<Vec<T>> {
158    type Each = T;
159    type Field = Vec<T>;
160    // We always have None, or Some(nonempty)
161    fn can_accumulate(self, _acc: &Option<Vec<T>>) -> Result<(), EP> {
162        Ok(())
163    }
164    fn accumulate(self, acc: &mut Option<Vec<T>>, item: T) -> Result<(), EP> {
165        acc.get_or_insert_default().push(item);
166        Ok(())
167    }
168    fn finish(self, acc: Option<Vec<T>>, _keyword: &'static str) -> Result<Vec<T>, EP> {
169        Ok(acc.unwrap_or_default())
170    }
171}
172impl<T: Ord> ItemSetMethods for MultiplicitySelector<BTreeSet<T>> {
173    type Each = T;
174    type Field = BTreeSet<T>;
175    // We always have None, or Some(nonempty)
176    fn can_accumulate(self, _acc: &Option<BTreeSet<T>>) -> Result<(), EP> {
177        Ok(())
178    }
179    fn accumulate(self, acc: &mut Option<BTreeSet<T>>, item: T) -> Result<(), EP> {
180        if !acc.get_or_insert_default().insert(item) {
181            return Err(EP::ItemRepeated);
182        }
183        Ok(())
184    }
185    fn finish(self, acc: Option<BTreeSet<T>>, _keyword: &'static str) -> Result<BTreeSet<T>, EP> {
186        Ok(acc.unwrap_or_default())
187    }
188}
189impl<T> ItemSetMethods for MultiplicitySelector<Option<T>> {
190    type Each = T;
191    type Field = Option<T>;
192    // We always have None, or Some(Some(_))
193    fn can_accumulate(self, acc: &Option<Option<T>>) -> Result<(), EP> {
194        if acc.is_some() {
195            Err(EP::ItemRepeated)?;
196        }
197        Ok(())
198    }
199    // We always have None, or Some(Some(_))
200    fn accumulate(self, acc: &mut Option<Option<T>>, item: T) -> Result<(), EP> {
201        self.can_accumulate(acc)?;
202        *acc = Some(Some(item));
203        Ok(())
204    }
205    fn finish(self, acc: Option<Option<T>>, _keyword: &'static str) -> Result<Option<T>, EP> {
206        Ok(acc.flatten())
207    }
208}
209impl<T> ItemSetMethods for &'_ MultiplicitySelector<T> {
210    type Each = T;
211    type Field = T;
212    fn can_accumulate(self, acc: &Option<T>) -> Result<(), EP> {
213        if acc.is_some() {
214            Err(EP::ItemRepeated)?;
215        }
216        Ok(())
217    }
218    fn accumulate(self, acc: &mut Option<T>, item: T) -> Result<(), EP> {
219        self.can_accumulate(acc)?;
220        *acc = Some(item);
221        Ok(())
222    }
223    fn finish(self, acc: Option<T>, keyword: &'static str) -> Result<T, EP> {
224        acc.ok_or(EP::MissingItem { keyword })
225    }
226}
227
228/// Method for handling some multiplicity of Arguments
229///
230/// **For use by macros**.
231///
232/// See the [module-level docs](multiplicity), and
233/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
234///
235/// # Example
236///
237/// The code in the (derive) macro output is roughly like this:
238///
239/// ```
240/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ArgumentSetMethods as _};
241/// use tor_netdoc::parse2::{ItemArgumentParseable, ItemStream, ParseInput};
242/// let doc = "intro-item 12 66\n";
243/// let input = ParseInput::new(doc, "<literal>");
244/// let mut items = ItemStream::new(&input).unwrap();
245/// let mut item = items.next().unwrap().unwrap();
246///
247/// let args = MultiplicitySelector::<Vec<i32>>::default()
248///     .parse_with(item.args_mut(), ItemArgumentParseable::from_args)
249///     .unwrap();
250/// assert_eq!(args, [12, 66]);
251/// ```
252//
253// When implementing this, update the documentation in the `ItemValueParseable` derive.
254pub trait ArgumentSetMethods: Copy + Sized {
255    /// The value for each Item.
256    type Each: Sized;
257
258    /// The output type: the type of the field in the Item struct.
259    ///
260    /// This is *not* the type of an individual netdoc argument;
261    /// that is not explicity represented in the trait.
262    type Field: Sized;
263
264    /// Parse zero or more argument(s) into `Self::Field`.
265    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
266    where
267        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>;
268
269    /// Check that the element type is an Argument
270    ///
271    /// For providing better error messages when struct fields don't implement the right trait.
272    /// See `derive.rs`, and search for this method name.
273    fn check_argument_value_parseable(self)
274    where
275        Self::Each: ItemArgumentParseable,
276    {
277    }
278}
279impl<T> ArgumentSetMethods for MultiplicitySelector<Vec<T>> {
280    type Each = T;
281    type Field = Vec<T>;
282    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
283    where
284        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
285    {
286        let mut acc = vec![];
287        while args.something_to_yield() {
288            acc.push(parser(args)?);
289        }
290        Ok(acc)
291    }
292}
293impl<T: Ord> ArgumentSetMethods for MultiplicitySelector<BTreeSet<T>> {
294    type Each = T;
295    type Field = BTreeSet<T>;
296    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
297    where
298        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
299    {
300        let mut acc = BTreeSet::new();
301        while args.something_to_yield() {
302            if !acc.insert(parser(args)?) {
303                return Err(AE::Invalid);
304            }
305        }
306        Ok(acc)
307    }
308}
309impl<T> ArgumentSetMethods for MultiplicitySelector<Option<T>> {
310    type Each = T;
311    type Field = Option<T>;
312    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
313    where
314        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
315    {
316        if !args.something_to_yield() {
317            return Ok(None);
318        }
319        Ok(Some(parser(args)?))
320    }
321}
322impl<T> ArgumentSetMethods for &MultiplicitySelector<T> {
323    type Each = T;
324    type Field = T;
325    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
326    where
327        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
328    {
329        parser(args)
330    }
331}
332
333/// Method for handling some multiplicity of Objects
334///
335/// **For use by macros**.
336///
337/// See the [module-level docs](multiplicity), and
338/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
339///
340/// # Example
341///
342/// The code in the (derive) macro output is roughly like this:
343///
344/// ```
345/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ObjectSetMethods as _};
346/// use tor_netdoc::parse2::{ItemStream, ParseInput};
347/// let doc = "intro-item\n-----BEGIN OBJECT-----\naGVsbG8=\n-----END OBJECT-----\n";
348/// let input = ParseInput::new(doc, "<literal>");
349/// let mut items = ItemStream::new(&input).unwrap();
350/// let mut item = items.next().unwrap().unwrap();
351///
352/// let selector = MultiplicitySelector::<Option<String>>::default();
353/// let obj = item.object().map(|obj| {
354///     let data = obj.decode_data().unwrap();
355///     String::from_utf8(data)
356/// }).transpose().unwrap();
357/// let obj = selector.resolve_option(obj).unwrap();
358/// assert_eq!(obj, Some("hello".to_owned()));
359/// ```
360pub trait ObjectSetMethods: Copy + Sized {
361    /// The value for each Item.
362    type Each: Sized;
363
364    /// The output type: the type of the field in the Item struct.
365    type Field: Sized;
366
367    /// Parse zero or more argument(s) into `Self::Field`.
368    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP>;
369
370    /// If the contained type is `ItemObjectParseable`, call its `check_label`
371    fn check_label(self, label: &str) -> Result<(), EP>
372    where
373        Self::Each: ItemObjectParseable,
374    {
375        Self::Each::check_label(label)
376    }
377
378    /// Check that the contained type can be parsed as an object
379    fn check_object_parseable(self)
380    where
381        Self::Each: ItemObjectParseable,
382    {
383    }
384}
385impl<T> ObjectSetMethods for MultiplicitySelector<Option<T>> {
386    type Field = Option<T>;
387    type Each = T;
388    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
389        Ok(found)
390    }
391}
392impl<T> ObjectSetMethods for &MultiplicitySelector<T> {
393    type Field = T;
394    type Each = T;
395    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
396        found.ok_or(EP::MissingObject)
397    }
398}