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