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

            
39
use 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)]
51
pub 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.
81
pub 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
7666
    fn is_intro_item_keyword(self, kw: KeywordRef<'_>) -> bool
105
7666
    where
106
7666
        Self::Each: NetdocParseable,
107
    {
108
7666
        Self::Each::is_intro_item_keyword(kw)
109
7666
    }
110

            
111
    /// If the contained type is a sub-document, call its `is_structural_keyword`.
112
176
    fn is_structural_keyword(self, kw: KeywordRef<'_>) -> Option<IsStructural>
113
176
    where
114
176
        Self::Each: NetdocParseable,
115
    {
116
176
        Self::Each::is_structural_keyword(kw)
117
176
    }
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
132
    fn finish_subdoc(self, acc: Option<Self::Field>) -> Result<Self::Field, EP>
123
132
    where
124
132
        Self::Each: NetdocParseable,
125
    {
126
132
        self.finish(acc, Self::Each::doctype_for_error())
127
132
    }
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
4587
    fn check_item_value_parseable(self)
134
4587
    where
135
4587
        Self::Each: ItemValueParseable,
136
    {
137
4587
    }
138
    /// Check that the element type is a Signature
139
935
    fn check_signature_item_parseable<H>(self, _: &mut H)
140
935
    where
141
935
        Self::Each: SignatureItemParseable,
142
935
        H: AsMut<<Self::Each as SignatureItemParseable>::HashAccu>,
143
    {
144
935
    }
145
    /// Check that the element type is a sub-document
146
276
    fn check_subdoc_parseable(self)
147
276
    where
148
276
        Self::Each: NetdocParseable,
149
    {
150
276
    }
151
    /// Check that the element type is an argument
152
5365
    fn check_item_argument_parseable(self)
153
5365
    where
154
5365
        Self::Each: ItemArgumentParseable,
155
    {
156
5365
    }
157
}
158
impl<T> ItemSetMethods for MultiplicitySelector<Vec<T>> {
159
    type Each = T;
160
    type Field = Vec<T>;
161
    // We always have None, or Some(nonempty)
162
82
    fn can_accumulate(self, _acc: &Option<Vec<T>>) -> Result<(), EP> {
163
82
        Ok(())
164
82
    }
165
280
    fn accumulate(self, acc: &mut Option<Vec<T>>, item: T) -> Result<(), EP> {
166
280
        acc.get_or_insert_default().push(item);
167
280
        Ok(())
168
280
    }
169
232
    fn finish(self, acc: Option<Vec<T>>, _keyword: &'static str) -> Result<Vec<T>, EP> {
170
232
        Ok(acc.unwrap_or_default())
171
232
    }
172
}
173
impl<T: Ord> ItemSetMethods for MultiplicitySelector<BTreeSet<T>> {
174
    type Each = T;
175
    type Field = BTreeSet<T>;
176
    // We always have None, or Some(nonempty)
177
    fn can_accumulate(self, _acc: &Option<BTreeSet<T>>) -> Result<(), EP> {
178
        Ok(())
179
    }
180
    fn accumulate(self, acc: &mut Option<BTreeSet<T>>, item: T) -> Result<(), EP> {
181
        if !acc.get_or_insert_default().insert(item) {
182
            return Err(EP::ItemRepeated);
183
        }
184
        Ok(())
185
    }
186
    fn finish(self, acc: Option<BTreeSet<T>>, _keyword: &'static str) -> Result<BTreeSet<T>, EP> {
187
        Ok(acc.unwrap_or_default())
188
    }
189
}
190
impl<T> ItemSetMethods for MultiplicitySelector<Option<T>> {
191
    type Each = T;
192
    type Field = Option<T>;
193
    // We always have None, or Some(Some(_))
194
324
    fn can_accumulate(self, acc: &Option<Option<T>>) -> Result<(), EP> {
195
324
        if acc.is_some() {
196
            Err(EP::ItemRepeated)?;
197
324
        }
198
324
        Ok(())
199
324
    }
200
    // We always have None, or Some(Some(_))
201
274
    fn accumulate(self, acc: &mut Option<Option<T>>, item: T) -> Result<(), EP> {
202
274
        self.can_accumulate(acc)?;
203
274
        *acc = Some(Some(item));
204
274
        Ok(())
205
274
    }
206
1565
    fn finish(self, acc: Option<Option<T>>, _keyword: &'static str) -> Result<Option<T>, EP> {
207
1565
        Ok(acc.flatten())
208
1565
    }
209
}
210
impl<T> ItemSetMethods for &'_ MultiplicitySelector<T> {
211
    type Each = T;
212
    type Field = T;
213
6939
    fn can_accumulate(self, acc: &Option<T>) -> Result<(), EP> {
214
6939
        if acc.is_some() {
215
2
            Err(EP::ItemRepeated)?;
216
6937
        }
217
6937
        Ok(())
218
6939
    }
219
6861
    fn accumulate(self, acc: &mut Option<T>, item: T) -> Result<(), EP> {
220
6861
        self.can_accumulate(acc)?;
221
6861
        *acc = Some(item);
222
6861
        Ok(())
223
6861
    }
224
6861
    fn finish(self, acc: Option<T>, keyword: &'static str) -> Result<T, EP> {
225
6861
        acc.ok_or(EP::MissingItem { keyword })
226
6861
    }
227
}
228

            
229
/// Method for handling some multiplicity of Arguments
230
///
231
/// **For use by macros**.
232
///
233
/// See the [module-level docs](multiplicity), and
234
/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
235
///
236
/// # Example
237
///
238
/// The code in the (derive) macro output is roughly like this:
239
///
240
/// ```
241
/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ArgumentSetMethods as _};
242
/// use tor_netdoc::parse2::{ItemArgumentParseable, ItemStream, ParseInput};
243
/// let doc = "intro-item 12 66\n";
244
/// let input = ParseInput::new(doc, "<literal>");
245
/// let mut items = ItemStream::new(&input).unwrap();
246
/// let mut item = items.next().unwrap().unwrap();
247
///
248
/// let args = MultiplicitySelector::<Vec<i32>>::default()
249
///     .parse_with(item.args_mut(), ItemArgumentParseable::from_args)
250
///     .unwrap();
251
/// assert_eq!(args, [12, 66]);
252
/// ```
253
//
254
// When implementing this, update the documentation in the `ItemValueParseable` derive.
255
pub trait ArgumentSetMethods: Copy + Sized {
256
    /// The value for each Item.
257
    type Each: Sized;
258

            
259
    /// The output type: the type of the field in the Item struct.
260
    ///
261
    /// This is *not* the type of an individual netdoc argument;
262
    /// that is not explicitly represented in the trait.
263
    type Field: Sized;
264

            
265
    /// Parse zero or more argument(s) into `Self::Field`.
266
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
267
    where
268
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>;
269

            
270
    /// Check that the element type is an Argument
271
    ///
272
    /// For providing better error messages when struct fields don't implement the right trait.
273
    /// See `derive.rs`, and search for this method name.
274
6876
    fn check_argument_value_parseable(self)
275
6876
    where
276
6876
        Self::Each: ItemArgumentParseable,
277
    {
278
6876
    }
279
}
280
impl<T> ArgumentSetMethods for MultiplicitySelector<Vec<T>> {
281
    type Each = T;
282
    type Field = Vec<T>;
283
42
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
284
42
    where
285
42
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
286
    {
287
42
        let mut acc = vec![];
288
78
        while args.something_to_yield() {
289
36
            acc.push(parser(args)?);
290
        }
291
42
        Ok(acc)
292
42
    }
293
}
294
impl<T: Ord> ArgumentSetMethods for MultiplicitySelector<BTreeSet<T>> {
295
    type Each = T;
296
    type Field = BTreeSet<T>;
297
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
298
    where
299
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
300
    {
301
        let mut acc = BTreeSet::new();
302
        while args.something_to_yield() {
303
            if !acc.insert(parser(args)?) {
304
                return Err(AE::Invalid);
305
            }
306
        }
307
        Ok(acc)
308
    }
309
}
310
impl<T> ArgumentSetMethods for MultiplicitySelector<Option<T>> {
311
    type Each = T;
312
    type Field = Option<T>;
313
28
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
314
28
    where
315
28
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
316
    {
317
28
        if !args.something_to_yield() {
318
6
            return Ok(None);
319
22
        }
320
22
        Ok(Some(parser(args)?))
321
28
    }
322
}
323
impl<T> ArgumentSetMethods for &MultiplicitySelector<T> {
324
    type Each = T;
325
    type Field = T;
326
7308
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
327
7308
    where
328
7308
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
329
    {
330
7308
        parser(args)
331
7308
    }
332
}
333

            
334
/// Method for handling some multiplicity of Objects
335
///
336
/// **For use by macros**.
337
///
338
/// See the [module-level docs](multiplicity), and
339
/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
340
///
341
/// # Example
342
///
343
/// The code in the (derive) macro output is roughly like this:
344
///
345
/// ```
346
/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ObjectSetMethods as _};
347
/// use tor_netdoc::parse2::{ItemStream, ParseInput};
348
/// let doc = "intro-item\n-----BEGIN OBJECT-----\naGVsbG8=\n-----END OBJECT-----\n";
349
/// let input = ParseInput::new(doc, "<literal>");
350
/// let mut items = ItemStream::new(&input).unwrap();
351
/// let mut item = items.next().unwrap().unwrap();
352
///
353
/// let selector = MultiplicitySelector::<Option<String>>::default();
354
/// let obj = item.object().map(|obj| {
355
///     let data = obj.decode_data().unwrap();
356
///     String::from_utf8(data)
357
/// }).transpose().unwrap();
358
/// let obj = selector.resolve_option(obj).unwrap();
359
/// assert_eq!(obj, Some("hello".to_owned()));
360
/// ```
361
pub trait ObjectSetMethods: Copy + Sized {
362
    /// The value for each Item.
363
    type Each: Sized;
364

            
365
    /// The output type: the type of the field in the Item struct.
366
    type Field: Sized;
367

            
368
    /// Parse zero or more argument(s) into `Self::Field`.
369
    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP>;
370

            
371
    /// If the contained type is `ItemObjectParseable`, call its `check_label`
372
2797
    fn check_label(self, label: &str) -> Result<(), EP>
373
2797
    where
374
2797
        Self::Each: ItemObjectParseable,
375
    {
376
2797
        Self::Each::check_label(label)
377
2797
    }
378

            
379
    /// Check that the contained type can be parsed as an object
380
2795
    fn check_object_parseable(self)
381
2795
    where
382
2795
        Self::Each: ItemObjectParseable,
383
    {
384
2795
    }
385
}
386
impl<T> ObjectSetMethods for MultiplicitySelector<Option<T>> {
387
    type Field = Option<T>;
388
    type Each = T;
389
36
    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
390
36
        Ok(found)
391
36
    }
392
}
393
impl<T> ObjectSetMethods for &MultiplicitySelector<T> {
394
    type Field = T;
395
    type Each = T;
396
3708
    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
397
3708
        found.ok_or(EP::MissingObject)
398
3708
    }
399
}