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
use 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)]
52
pub 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!
61
struct 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.
96
pub 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
7564
    fn is_intro_item_keyword(self, kw: KeywordRef<'_>) -> bool
144
7564
    where
145
7564
        Self::Each: NetdocParseable,
146
    {
147
7564
        Self::Each::is_intro_item_keyword(kw)
148
7564
    }
149

            
150
    /// If the contained type is a sub-document, call its `is_structural_keyword`.
151
218
    fn is_structural_keyword(self, kw: KeywordRef<'_>) -> Option<IsStructural>
152
218
    where
153
218
        Self::Each: NetdocParseable,
154
    {
155
218
        Self::Each::is_structural_keyword(kw)
156
218
    }
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
132
    fn finish_subdoc(self, acc: Option<Self::Field>) -> Result<Self::Field, EP>
162
132
    where
163
132
        Self::Each: NetdocParseable,
164
    {
165
132
        self.finish(acc, Self::Each::doctype_for_error())
166
132
    }
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
5259
    fn check_item_value_parseable(self)
173
5259
    where
174
5259
        Self::Each: ItemValueParseable,
175
    {
176
5259
    }
177
    /// Check that the element type is a Signature
178
941
    fn check_signature_item_parseable<H>(self, _: &mut H)
179
941
    where
180
941
        Self::Each: SignatureItemParseable,
181
941
        H: AsMut<<Self::Each as SignatureItemParseable>::HashAccu>,
182
    {
183
941
    }
184
    /// Check that the element type is a sub-document
185
276
    fn check_subdoc_parseable(self)
186
276
    where
187
276
        Self::Each: NetdocParseable,
188
    {
189
276
    }
190
    /// Check that the element type is an argument
191
5507
    fn check_item_argument_parseable(self)
192
5507
    where
193
5507
        Self::Each: ItemArgumentParseable,
194
    {
195
5507
    }
196
}
197
impl<T> ItemSetMethods for MultiplicitySelector<Vec<T>> {
198
    type Each = T;
199
    type Field = Vec<T>;
200
    // We always have None, or Some(nonempty)
201
88
    fn can_accumulate(self, _acc: &Option<Vec<T>>) -> Result<(), EP> {
202
88
        Ok(())
203
88
    }
204
276
    fn accumulate(self, acc: &mut Option<Vec<T>>, item: T) -> Result<(), EP> {
205
276
        acc.get_or_insert_default().push(item);
206
276
        Ok(())
207
276
    }
208
240
    fn finish(self, acc: Option<Vec<T>>, _keyword: &'static str) -> Result<Vec<T>, EP> {
209
240
        Ok(acc.unwrap_or_default())
210
240
    }
211
    fn debug_core(self) -> &'static str {
212
        "Vec<_>"
213
    }
214
}
215
impl<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
2
    fn accumulate(self, acc: &mut Option<RetainedOrderVec<T>>, item: T) -> Result<(), EP> {
223
2
        acc.get_or_insert_default().0.push(item);
224
2
        Ok(())
225
2
    }
226
2
    fn finish(
227
2
        self,
228
2
        acc: Option<RetainedOrderVec<T>>,
229
2
        _keyword: &'static str,
230
2
    ) -> Result<RetainedOrderVec<T>, EP> {
231
2
        Ok(acc.unwrap_or_default())
232
2
    }
233
    fn debug_core(self) -> &'static str {
234
        "RetainedOrderVec<_>"
235
    }
236
}
237
impl<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
}
257
impl<T> ItemSetMethods for MultiplicitySelector<Option<T>> {
258
    type Each = T;
259
    type Field = Option<T>;
260
    // We always have None, or Some(Some(_))
261
352
    fn can_accumulate(self, acc: &Option<Option<T>>) -> Result<(), EP> {
262
352
        if acc.is_some() {
263
            Err(EP::ItemRepeated)?;
264
352
        }
265
352
        Ok(())
266
352
    }
267
    // We always have None, or Some(Some(_))
268
302
    fn accumulate(self, acc: &mut Option<Option<T>>, item: T) -> Result<(), EP> {
269
302
        self.can_accumulate(acc)?;
270
302
        *acc = Some(Some(item));
271
302
        Ok(())
272
302
    }
273
1639
    fn finish(self, acc: Option<Option<T>>, _keyword: &'static str) -> Result<Option<T>, EP> {
274
1639
        Ok(acc.flatten())
275
1639
    }
276
    fn debug_core(self) -> &'static str {
277
        "Option<_>"
278
    }
279
}
280
impl<T> ItemSetMethods for &'_ MultiplicitySelector<T> {
281
    type Each = T;
282
    type Field = T;
283
8021
    fn can_accumulate(self, acc: &Option<T>) -> Result<(), EP> {
284
8021
        if acc.is_some() {
285
2
            Err(EP::ItemRepeated)?;
286
8019
        }
287
8019
        Ok(())
288
8021
    }
289
7943
    fn accumulate(self, acc: &mut Option<T>, item: T) -> Result<(), EP> {
290
7943
        self.can_accumulate(acc)?;
291
7943
        *acc = Some(item);
292
7943
        Ok(())
293
7943
    }
294
7943
    fn finish(self, acc: Option<T>, keyword: &'static str) -> Result<T, EP> {
295
7943
        acc.ok_or(EP::MissingItem { keyword })
296
7943
    }
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.
331
pub 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
54
    fn argument_set_debug(self) -> impl Debug {
357
54
        DebugHelper("args", self.debug_core())
358
54
    }
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
14716
    fn check_argument_value_parseable(self)
365
14716
    where
366
14716
        Self::Each: ItemArgumentParseable,
367
    {
368
14716
    }
369
}
370
impl<T> ArgumentSetMethods for MultiplicitySelector<Vec<T>> {
371
    type Each = T;
372
    type Field = Vec<T>;
373
38
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
374
38
    where
375
38
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
376
    {
377
38
        let mut acc = vec![];
378
86
        while args.something_to_yield() {
379
48
            acc.push(parser(args)?);
380
        }
381
38
        Ok(acc)
382
38
    }
383
18
    fn debug_core(self) -> &'static str {
384
18
        "Vec<_>"
385
18
    }
386
}
387
impl<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
}
406
impl<T> ArgumentSetMethods for MultiplicitySelector<Option<T>> {
407
    type Each = T;
408
    type Field = Option<T>;
409
28
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
410
28
    where
411
28
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
412
    {
413
28
        if !args.something_to_yield() {
414
6
            return Ok(None);
415
22
        }
416
22
        Ok(Some(parser(args)?))
417
28
    }
418
18
    fn debug_core(self) -> &'static str {
419
18
        "Option<_>"
420
18
    }
421
}
422
impl<T> ArgumentSetMethods for &MultiplicitySelector<T> {
423
    type Each = T;
424
    type Field = T;
425
15148
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
426
15148
    where
427
15148
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
428
    {
429
15148
        parser(args)
430
15148
    }
431
18
    fn debug_core(self) -> &'static str {
432
18
        "1"
433
18
    }
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
/// ```
463
pub 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
18
    fn object_set_debug(self) -> impl Debug {
484
18
        DebugHelper("object", self.debug_core())
485
18
    }
486

            
487
    /// If the contained type is `ItemObjectParseable`, call its `check_label`
488
2825
    fn check_label(self, label: &str) -> Result<(), EP>
489
2825
    where
490
2825
        Self::Each: ItemObjectParseable,
491
    {
492
2825
        Self::Each::check_label(label)
493
2825
    }
494

            
495
    /// Check that the contained type can be parsed as an object
496
2823
    fn check_object_parseable(self)
497
2823
    where
498
2823
        Self::Each: ItemObjectParseable,
499
    {
500
2823
    }
501
}
502
impl<T> ObjectSetMethods for MultiplicitySelector<Option<T>> {
503
    type Field = Option<T>;
504
    type Each = T;
505
52
    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
506
52
        Ok(found)
507
52
    }
508
    fn debug_core(self) -> &'static str {
509
        "Option<_>"
510
    }
511
}
512
impl<T> ObjectSetMethods for &MultiplicitySelector<T> {
513
    type Field = T;
514
    type Each = T;
515
3724
    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
516
3724
        found.ok_or(EP::MissingObject)
517
3724
    }
518
18
    fn debug_core(self) -> &'static str {
519
18
        "1"
520
18
    }
521
}