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    /// `finish` for if the contained type is a wsub-document
112    ///
113    /// Obtain the sub-document's intro keyword from its `doctype_for_error`.
114    fn finish_subdoc(self, acc: Option<Self::Field>) -> Result<Self::Field, EP>
115    where
116        Self::Each: NetdocParseable,
117    {
118        self.finish(acc, Self::Each::doctype_for_error())
119    }
120
121    /// Check that the element type is an Item
122    ///
123    /// For providing better error messages when struct fields don't implement the right trait.
124    /// See `derive.rs`, and search for this method name.
125    fn check_item_value_parseable(self)
126    where
127        Self::Each: ItemValueParseable,
128    {
129    }
130    /// Check that the element type is a Signature
131    fn check_signature_item_parseable(self)
132    where
133        Self::Each: SignatureItemParseable,
134    {
135    }
136    /// Check that the element type is a sub-document
137    fn check_subdoc_parseable(self)
138    where
139        Self::Each: NetdocParseable,
140    {
141    }
142    /// Check that the element type is an argument
143    fn check_item_argument_parseable(self)
144    where
145        Self::Each: ItemArgumentParseable,
146    {
147    }
148}
149impl<T> ItemSetMethods for MultiplicitySelector<Vec<T>> {
150    type Each = T;
151    type Field = Vec<T>;
152    // We always have None, or Some(nonempty)
153    fn can_accumulate(self, _acc: &Option<Vec<T>>) -> Result<(), EP> {
154        Ok(())
155    }
156    fn accumulate(self, acc: &mut Option<Vec<T>>, item: T) -> Result<(), EP> {
157        acc.get_or_insert_default().push(item);
158        Ok(())
159    }
160    fn finish(self, acc: Option<Vec<T>>, _keyword: &'static str) -> Result<Vec<T>, EP> {
161        Ok(acc.unwrap_or_default())
162    }
163}
164impl<T: Ord> ItemSetMethods for MultiplicitySelector<BTreeSet<T>> {
165    type Each = T;
166    type Field = BTreeSet<T>;
167    // We always have None, or Some(nonempty)
168    fn can_accumulate(self, _acc: &Option<BTreeSet<T>>) -> Result<(), EP> {
169        Ok(())
170    }
171    fn accumulate(self, acc: &mut Option<BTreeSet<T>>, item: T) -> Result<(), EP> {
172        if !acc.get_or_insert_default().insert(item) {
173            return Err(EP::ItemRepeated);
174        }
175        Ok(())
176    }
177    fn finish(self, acc: Option<BTreeSet<T>>, _keyword: &'static str) -> Result<BTreeSet<T>, EP> {
178        Ok(acc.unwrap_or_default())
179    }
180}
181impl<T> ItemSetMethods for MultiplicitySelector<Option<T>> {
182    type Each = T;
183    type Field = Option<T>;
184    // We always have None, or Some(Some(_))
185    fn can_accumulate(self, acc: &Option<Option<T>>) -> Result<(), EP> {
186        if acc.is_some() {
187            Err(EP::ItemRepeated)?;
188        }
189        Ok(())
190    }
191    // We always have None, or Some(Some(_))
192    fn accumulate(self, acc: &mut Option<Option<T>>, item: T) -> Result<(), EP> {
193        self.can_accumulate(acc)?;
194        *acc = Some(Some(item));
195        Ok(())
196    }
197    fn finish(self, acc: Option<Option<T>>, _keyword: &'static str) -> Result<Option<T>, EP> {
198        Ok(acc.flatten())
199    }
200}
201impl<T> ItemSetMethods for &'_ MultiplicitySelector<T> {
202    type Each = T;
203    type Field = T;
204    fn can_accumulate(self, acc: &Option<T>) -> Result<(), EP> {
205        if acc.is_some() {
206            Err(EP::ItemRepeated)?;
207        }
208        Ok(())
209    }
210    fn accumulate(self, acc: &mut Option<T>, item: T) -> Result<(), EP> {
211        self.can_accumulate(acc)?;
212        *acc = Some(item);
213        Ok(())
214    }
215    fn finish(self, acc: Option<T>, keyword: &'static str) -> Result<T, EP> {
216        acc.ok_or(EP::MissingItem { keyword })
217    }
218}
219
220/// Method for handling some multiplicity of Arguments
221///
222/// **For use by macros**.
223///
224/// See the [module-level docs](multiplicity), and
225/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
226///
227/// # Example
228///
229/// The code in the (derive) macro output is roughly like this:
230///
231/// ```
232/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ArgumentSetMethods as _};
233/// use tor_netdoc::parse2::{ItemArgumentParseable, ItemStream, ParseInput};
234/// let doc = "intro-item 12 66\n";
235/// let input = ParseInput::new(doc, "<literal>");
236/// let mut items = ItemStream::new(&input).unwrap();
237/// let mut item = items.next().unwrap().unwrap();
238///
239/// let args = MultiplicitySelector::<Vec<i32>>::default()
240///     .parse_with(item.args_mut(), ItemArgumentParseable::from_args)
241///     .unwrap();
242/// assert_eq!(args, [12, 66]);
243/// ```
244//
245// When implementing this, update the documentation in the `ItemValueParseable` derive.
246pub trait ArgumentSetMethods: Copy + Sized {
247    /// The value for each Item.
248    type Each: Sized;
249
250    /// The output type: the type of the field in the Item struct.
251    ///
252    /// This is *not* the type of an individual netdoc argument;
253    /// that is not explicity represented in the trait.
254    type Field: Sized;
255
256    /// Parse zero or more argument(s) into `Self::Field`.
257    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
258    where
259        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>;
260
261    /// Check that the element type is an Argument
262    ///
263    /// For providing better error messages when struct fields don't implement the right trait.
264    /// See `derive.rs`, and search for this method name.
265    fn check_argument_value_parseable(self)
266    where
267        Self::Each: ItemArgumentParseable,
268    {
269    }
270}
271impl<T> ArgumentSetMethods for MultiplicitySelector<Vec<T>> {
272    type Each = T;
273    type Field = Vec<T>;
274    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
275    where
276        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
277    {
278        let mut acc = vec![];
279        while args.something_to_yield() {
280            acc.push(parser(args)?);
281        }
282        Ok(acc)
283    }
284}
285impl<T: Ord> ArgumentSetMethods for MultiplicitySelector<BTreeSet<T>> {
286    type Each = T;
287    type Field = BTreeSet<T>;
288    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
289    where
290        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
291    {
292        let mut acc = BTreeSet::new();
293        while args.something_to_yield() {
294            if !acc.insert(parser(args)?) {
295                return Err(AE::Invalid);
296            }
297        }
298        Ok(acc)
299    }
300}
301impl<T> ArgumentSetMethods for MultiplicitySelector<Option<T>> {
302    type Each = T;
303    type Field = Option<T>;
304    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
305    where
306        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
307    {
308        if !args.something_to_yield() {
309            return Ok(None);
310        }
311        Ok(Some(parser(args)?))
312    }
313}
314impl<T> ArgumentSetMethods for &MultiplicitySelector<T> {
315    type Each = T;
316    type Field = T;
317    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
318    where
319        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
320    {
321        parser(args)
322    }
323}
324
325/// Method for handling some multiplicity of Objects
326///
327/// **For use by macros**.
328///
329/// See the [module-level docs](multiplicity), and
330/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
331///
332/// # Example
333///
334/// The code in the (derive) macro output is roughly like this:
335///
336/// ```
337/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ObjectSetMethods as _};
338/// use tor_netdoc::parse2::{ItemStream, ParseInput};
339/// let doc = "intro-item\n-----BEGIN OBJECT-----\naGVsbG8=\n-----END OBJECT-----\n";
340/// let input = ParseInput::new(doc, "<literal>");
341/// let mut items = ItemStream::new(&input).unwrap();
342/// let mut item = items.next().unwrap().unwrap();
343///
344/// let selector = MultiplicitySelector::<Option<String>>::default();
345/// let obj = item.object().map(|obj| {
346///     let data = obj.decode_data().unwrap();
347///     String::from_utf8(data)
348/// }).transpose().unwrap();
349/// let obj = selector.resolve_option(obj).unwrap();
350/// assert_eq!(obj, Some("hello".to_owned()));
351/// ```
352pub trait ObjectSetMethods: Copy + Sized {
353    /// The value for each Item.
354    type Each: Sized;
355
356    /// The output type: the type of the field in the Item struct.
357    type Field: Sized;
358
359    /// Parse zero or more argument(s) into `Self::Field`.
360    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP>;
361
362    /// If the contained type is `ItemObjectParseable`, call its `check_label`
363    fn check_label(self, label: &str) -> Result<(), EP>
364    where
365        Self::Each: ItemObjectParseable,
366    {
367        Self::Each::check_label(label)
368    }
369
370    /// Check that the contained type can be parsed as an object
371    fn check_object_parseable(self)
372    where
373        Self::Each: ItemObjectParseable,
374    {
375    }
376}
377impl<T> ObjectSetMethods for MultiplicitySelector<Option<T>> {
378    type Field = Option<T>;
379    type Each = T;
380    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
381        Ok(found)
382    }
383}
384impl<T> ObjectSetMethods for &MultiplicitySelector<T> {
385    type Field = T;
386    type Each = T;
387    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
388        found.ok_or(EP::MissingObject)
389    }
390}