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
#[cfg(doc)]
43
use crate::encode;
44

            
45
/// Helper type that allows us to select an impl of `ItemSetMethods` etc.
46
///
47
/// **For use by macros**.
48
///
49
/// See the [module-level docs](multiplicity).
50
///
51
/// This is distinct from `encode::MultiplicitySelector`,
52
/// principally because it has the opposite variance.
53
#[derive(Educe)]
54
#[educe(Clone, Copy, Default)]
55
pub struct MultiplicitySelector<Field>(PhantomData<fn() -> Field>);
56

            
57
/// Helper type that allows us to implement Debug
58
///
59
/// Returned by [`ItemSetMethods::item_set_debug`] etc.,
60
/// using information from [`ItemSetMethods::debug_core`] etc.
61
#[derive(derive_more::Debug)]
62
#[debug("{}={}", self.0, self.1)]
63
#[allow(dead_code)] // yes, they are only read by the Debug impl - that's what they're for!
64
struct DebugHelper(
65
    /// scope, eg `items`
66
    &'static str,
67
    /// multiplicity type pattern, eg `Vec<_>` or `1`
68
    &'static str,
69
);
70

            
71
/// Methods for handling some multiplicity of Items, during parsing
72
///
73
/// **For use by macros**.
74
///
75
/// During parsing, we accumulate into a value of type `Option<Self::Field>`.
76
/// The semantics of this are item-set-implementation-dependent;
77
/// using a type which is generic over the field type in a simple way
78
/// allows the partially-parsed accumulation state for a whole netdoc to have a concrete type.
79
///
80
/// See the [module-level docs](multiplicity), and
81
/// [Field type in `NetdocParseable`](derive_deftly_template_NetdocParseable#field-type).
82
///
83
/// # Example
84
///
85
/// The code in the (derive) macro output is roughly like this:
86
///
87
/// ```
88
/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ItemSetMethods as _};
89
///
90
/// let selector = MultiplicitySelector::<Vec<i32>>::default();
91
/// let mut accum = None;
92
/// selector.accumulate(&mut accum, 12).unwrap();
93
/// let out = selector.finish(accum, "item-set").unwrap();
94
///
95
/// assert_eq!(out, [12]);
96
/// ```
97
//
98
// When implementing this, update the documentation in the `NetdocParseable` derive.
99
pub trait ItemSetMethods: Copy + Sized {
100
    /// The value for each Item.
101
    ///
102
    /// Should match the corresponding
103
    /// [`encode::MultiplicityMethods::Each`].
104
    /// (See docs there for rationale.)
105
    type Each: Sized;
106

            
107
    /// The output type: the type of the field in the netdoc struct.
108
    type Field: Sized;
109

            
110
    /// Can we accumulate another item ?
111
    ///
112
    /// Can be used to help predict whether `accumulate` will throw.
113
    fn can_accumulate(self, acc: &Option<Self::Field>) -> Result<(), EP>;
114

            
115
    /// Accumulate one value into the accumulator.
116
    fn accumulate(self, acc: &mut Option<Self::Field>, one: Self::Each) -> Result<(), EP>;
117

            
118
    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output, core
119
    ///
120
    /// Should generally be in a form like `Vec<_>`.
121
    ///
122
    /// See also [`ItemSetMethods::item_set_debug`], which is what the derives call.
123
    //
124
    // This can't be a `Debug` supertrait, because that won't work
125
    // with the `&'_ MultiplicitySelector<T>` impl.
126
    fn debug_core(self) -> &'static str;
127

            
128
    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output
129
    ///
130
    /// This adds a bit framing and type-fu that allows the derive macro's
131
    /// call to be as simple as possible.
132
    ///
133
    /// See also [`ItemSetMethods::debug_core`], which is what each multiplicity implements.
134
    //
135
    // dtrace!, which we use for debugging in the parser macros, doesn't print variable names,
136
    // thinking things are probably obvious enough.  But for the elector here we want to
137
    // include `items=`.
138
    fn item_set_debug(self) -> impl Debug {
139
        DebugHelper("items", self.debug_core())
140
    }
141

            
142
    /// Resolve the accumulator into the output.
143
    fn finish(
144
        self,
145
        acc: Option<Self::Field>,
146
        item_keyword: &'static str,
147
    ) -> Result<Self::Field, EP>;
148

            
149
    /// If the contained type is a sub-document, call its `is_intro_item_keyword`.
150
7564
    fn is_intro_item_keyword(self, kw: KeywordRef<'_>) -> bool
151
7564
    where
152
7564
        Self::Each: NetdocParseable,
153
    {
154
7564
        Self::Each::is_intro_item_keyword(kw)
155
7564
    }
156

            
157
    /// If the contained type is a sub-document, call its `is_structural_keyword`.
158
218
    fn is_structural_keyword(self, kw: KeywordRef<'_>) -> Option<IsStructural>
159
218
    where
160
218
        Self::Each: NetdocParseable,
161
    {
162
218
        Self::Each::is_structural_keyword(kw)
163
218
    }
164

            
165
    /// `finish` for if the contained type is a wsub-document
166
    ///
167
    /// Obtain the sub-document's intro keyword from its `doctype_for_error`.
168
132
    fn finish_subdoc(self, acc: Option<Self::Field>) -> Result<Self::Field, EP>
169
132
    where
170
132
        Self::Each: NetdocParseable,
171
    {
172
132
        self.finish(acc, Self::Each::doctype_for_error())
173
132
    }
174

            
175
    /// Check that the element type is an Item
176
    ///
177
    /// For providing better error messages when struct fields don't implement the right trait.
178
    /// See `derive.rs`, and search for this method name.
179
6604
    fn check_item_value_parseable(self)
180
6604
    where
181
6604
        Self::Each: ItemValueParseable,
182
    {
183
6604
    }
184
    /// Check that the element type is a Signature
185
958
    fn check_signature_item_parseable<H>(self, _: &mut H)
186
958
    where
187
958
        Self::Each: SignatureItemParseable,
188
958
        H: AsMut<<Self::Each as SignatureItemParseable>::HashAccu>,
189
    {
190
958
    }
191
    /// Check that the element type is a sub-document
192
276
    fn check_subdoc_parseable(self)
193
276
    where
194
276
        Self::Each: NetdocParseable,
195
    {
196
276
    }
197
    /// Check that the element type is an argument
198
5714
    fn check_item_argument_parseable(self)
199
5714
    where
200
5714
        Self::Each: ItemArgumentParseable,
201
    {
202
5714
    }
203
}
204
impl<T> ItemSetMethods for MultiplicitySelector<Vec<T>> {
205
    type Each = T;
206
    type Field = Vec<T>;
207
    // We always have None, or Some(nonempty)
208
88
    fn can_accumulate(self, _acc: &Option<Vec<T>>) -> Result<(), EP> {
209
88
        Ok(())
210
88
    }
211
284
    fn accumulate(self, acc: &mut Option<Vec<T>>, item: T) -> Result<(), EP> {
212
284
        acc.get_or_insert_default().push(item);
213
284
        Ok(())
214
284
    }
215
242
    fn finish(self, acc: Option<Vec<T>>, _keyword: &'static str) -> Result<Vec<T>, EP> {
216
242
        Ok(acc.unwrap_or_default())
217
242
    }
218
    fn debug_core(self) -> &'static str {
219
        "Vec<_>"
220
    }
221
}
222
impl<T> ItemSetMethods for MultiplicitySelector<RetainedOrderVec<T>> {
223
    type Each = T;
224
    type Field = RetainedOrderVec<T>;
225
    // We always have None, or Some(nonempty)
226
    fn can_accumulate(self, _acc: &Option<RetainedOrderVec<T>>) -> Result<(), EP> {
227
        Ok(())
228
    }
229
2
    fn accumulate(self, acc: &mut Option<RetainedOrderVec<T>>, item: T) -> Result<(), EP> {
230
2
        acc.get_or_insert_default().0.push(item);
231
2
        Ok(())
232
2
    }
233
2
    fn finish(
234
2
        self,
235
2
        acc: Option<RetainedOrderVec<T>>,
236
2
        _keyword: &'static str,
237
2
    ) -> Result<RetainedOrderVec<T>, EP> {
238
2
        Ok(acc.unwrap_or_default())
239
2
    }
240
    fn debug_core(self) -> &'static str {
241
        "RetainedOrderVec<_>"
242
    }
243
}
244
impl<T: Ord> ItemSetMethods for MultiplicitySelector<BTreeSet<T>> {
245
    type Each = T;
246
    type Field = BTreeSet<T>;
247
    // We always have None, or Some(nonempty)
248
    fn can_accumulate(self, _acc: &Option<BTreeSet<T>>) -> Result<(), EP> {
249
        Ok(())
250
    }
251
    fn accumulate(self, acc: &mut Option<BTreeSet<T>>, item: T) -> Result<(), EP> {
252
        if !acc.get_or_insert_default().insert(item) {
253
            return Err(EP::ItemRepeated);
254
        }
255
        Ok(())
256
    }
257
    fn finish(self, acc: Option<BTreeSet<T>>, _keyword: &'static str) -> Result<BTreeSet<T>, EP> {
258
        Ok(acc.unwrap_or_default())
259
    }
260
    fn debug_core(self) -> &'static str {
261
        "BTreeSet<_>"
262
    }
263
}
264
impl<T> ItemSetMethods for MultiplicitySelector<Option<T>> {
265
    type Each = T;
266
    type Field = Option<T>;
267
    // We always have None, or Some(Some(_))
268
632
    fn can_accumulate(self, acc: &Option<Option<T>>) -> Result<(), EP> {
269
632
        if acc.is_some() {
270
4
            Err(EP::ItemRepeated)?;
271
628
        }
272
628
        Ok(())
273
632
    }
274
    // We always have None, or Some(Some(_))
275
582
    fn accumulate(self, acc: &mut Option<Option<T>>, item: T) -> Result<(), EP> {
276
582
        self.can_accumulate(acc)?;
277
578
        *acc = Some(Some(item));
278
578
        Ok(())
279
582
    }
280
1936
    fn finish(self, acc: Option<Option<T>>, _keyword: &'static str) -> Result<Option<T>, EP> {
281
1936
        Ok(acc.flatten())
282
1936
    }
283
    fn debug_core(self) -> &'static str {
284
        "Option<_>"
285
    }
286
}
287
impl<T> ItemSetMethods for &'_ MultiplicitySelector<T> {
288
    type Each = T;
289
    type Field = T;
290
8288
    fn can_accumulate(self, acc: &Option<T>) -> Result<(), EP> {
291
8288
        if acc.is_some() {
292
2
            Err(EP::ItemRepeated)?;
293
8286
        }
294
8286
        Ok(())
295
8288
    }
296
8210
    fn accumulate(self, acc: &mut Option<T>, item: T) -> Result<(), EP> {
297
8210
        self.can_accumulate(acc)?;
298
8210
        *acc = Some(item);
299
8210
        Ok(())
300
8210
    }
301
8210
    fn finish(self, acc: Option<T>, keyword: &'static str) -> Result<T, EP> {
302
8210
        acc.ok_or(EP::MissingItem { keyword })
303
8210
    }
304
    fn debug_core(self) -> &'static str {
305
        // This appears in #[deftly(netdoc(debug))] output for singleton fields.
306
        // We probably don't want the macros' users to have to think about our
307
        // autoref-specialisation.  So we don't write anything about `&` here.
308
        "1"
309
    }
310
}
311

            
312
/// Method for handling some multiplicity of Arguments
313
///
314
/// **For use by macros**.
315
///
316
/// See the [module-level docs](multiplicity), and
317
/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
318
///
319
/// # Example
320
///
321
/// The code in the (derive) macro output is roughly like this:
322
///
323
/// ```
324
/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ArgumentSetMethods as _};
325
/// use tor_netdoc::parse2::{ItemArgumentParseable, ItemStream, ParseInput};
326
/// let doc = "intro-item 12 66\n";
327
/// let input = ParseInput::new(doc, "<literal>");
328
/// let mut items = ItemStream::new(&input).unwrap();
329
/// let mut item = items.next().unwrap().unwrap();
330
///
331
/// let args = MultiplicitySelector::<Vec<i32>>::default()
332
///     .parse_with(item.args_mut(), ItemArgumentParseable::from_args)
333
///     .unwrap();
334
/// assert_eq!(args, [12, 66]);
335
/// ```
336
//
337
// When implementing this, update the documentation in the `ItemValueParseable` derive.
338
pub trait ArgumentSetMethods: Copy + Sized {
339
    /// The value for each Item.
340
    ///
341
    /// Should match the corresponding
342
    /// [`encode::MultiplicityMethods::Each`].
343
    /// (See docs there for rationale.)
344
    type Each: Sized;
345

            
346
    /// The output type: the type of the field in the Item struct.
347
    ///
348
    /// This is *not* the type of an individual netdoc argument;
349
    /// that is not explicitly represented in the trait.
350
    type Field: Sized;
351

            
352
    /// Parse zero or more argument(s) into `Self::Field`.
353
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
354
    where
355
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>;
356

            
357
    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output, core
358
    ///
359
    /// Should generally be in a form like `Vec<_>`.
360
    ///
361
    /// See [`ItemSetMethods::debug_core`] and [`ArgumentSetMethods::argument_set_debug`].
362
    fn debug_core(self) -> &'static str;
363

            
364
    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output
365
    ///
366
    /// See [`ItemSetMethods::item_set_debug`] and [`ArgumentSetMethods::debug_core`].
367
54
    fn argument_set_debug(self) -> impl Debug {
368
54
        DebugHelper("args", self.debug_core())
369
54
    }
370

            
371
    /// Check that the element type is an Argument
372
    ///
373
    /// For providing better error messages when struct fields don't implement the right trait.
374
    /// See `derive.rs`, and search for this method name.
375
19552
    fn check_argument_value_parseable(self)
376
19552
    where
377
19552
        Self::Each: ItemArgumentParseable,
378
    {
379
19552
    }
380
}
381
impl<T> ArgumentSetMethods for MultiplicitySelector<Vec<T>> {
382
    type Each = T;
383
    type Field = Vec<T>;
384
38
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
385
38
    where
386
38
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
387
    {
388
38
        let mut acc = vec![];
389
86
        while args.something_to_yield() {
390
48
            acc.push(parser(args)?);
391
        }
392
38
        Ok(acc)
393
38
    }
394
18
    fn debug_core(self) -> &'static str {
395
18
        "Vec<_>"
396
18
    }
397
}
398
impl<T: Ord> ArgumentSetMethods for MultiplicitySelector<BTreeSet<T>> {
399
    type Each = T;
400
    type Field = BTreeSet<T>;
401
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
402
    where
403
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
404
    {
405
        let mut acc = BTreeSet::new();
406
        while args.something_to_yield() {
407
            if !acc.insert(parser(args)?) {
408
                return Err(AE::Invalid);
409
            }
410
        }
411
        Ok(acc)
412
    }
413
    fn debug_core(self) -> &'static str {
414
        "BTreeSet<_>"
415
    }
416
}
417
impl<T> ArgumentSetMethods for MultiplicitySelector<Option<T>> {
418
    type Each = T;
419
    type Field = Option<T>;
420
36
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
421
36
    where
422
36
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
423
    {
424
36
        if !args.something_to_yield() {
425
14
            return Ok(None);
426
22
        }
427
22
        Ok(Some(parser(args)?))
428
36
    }
429
18
    fn debug_core(self) -> &'static str {
430
18
        "Option<_>"
431
18
    }
432
}
433
impl<T> ArgumentSetMethods for &MultiplicitySelector<T> {
434
    type Each = T;
435
    type Field = T;
436
21460
    fn parse_with<P>(self, args: &mut ArgumentStream<'_>, parser: P) -> Result<Self::Field, AE>
437
21460
    where
438
21460
        P: for<'s> Fn(&mut ArgumentStream<'s>) -> Result<Self::Each, AE>,
439
    {
440
21460
        parser(args)
441
21460
    }
442
18
    fn debug_core(self) -> &'static str {
443
18
        "1"
444
18
    }
445
}
446

            
447
/// Method for handling some multiplicity of Objects
448
///
449
/// **For use by macros**.
450
///
451
/// See the [module-level docs](multiplicity), and
452
/// [Field type in `ItemValueParseable`](derive_deftly_template_ItemValueParseable#field-type).
453
///
454
/// # Example
455
///
456
/// The code in the (derive) macro output is roughly like this:
457
///
458
/// ```
459
/// use tor_netdoc::parse2::multiplicity::{MultiplicitySelector, ObjectSetMethods as _};
460
/// use tor_netdoc::parse2::{ItemStream, ParseInput};
461
/// let doc = "intro-item\n-----BEGIN OBJECT-----\naGVsbG8=\n-----END OBJECT-----\n";
462
/// let input = ParseInput::new(doc, "<literal>");
463
/// let mut items = ItemStream::new(&input).unwrap();
464
/// let mut item = items.next().unwrap().unwrap();
465
///
466
/// let selector = MultiplicitySelector::<Option<String>>::default();
467
/// let obj = item.object().map(|obj| {
468
///     let data = obj.decode_data().unwrap();
469
///     String::from_utf8(data)
470
/// }).transpose().unwrap();
471
/// let obj = selector.resolve_option(obj).unwrap();
472
/// assert_eq!(obj, Some("hello".to_owned()));
473
/// ```
474
pub trait ObjectSetMethods: Copy + Sized {
475
    /// The value for each Item.
476
    ///
477
    /// Should match the corresponding
478
    /// [`encode::OptionalityMethods::Each`].
479
    /// (See [`encode::MultiplicityMethods::Each`] for rationale.)
480
    type Each: Sized;
481

            
482
    /// The output type: the type of the field in the Item struct.
483
    type Field: Sized;
484

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

            
488
    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output, core
489
    ///
490
    /// Should generally be in a form like `Option<_>`.
491
    ///
492
    /// See [`ItemSetMethods::debug_core`] and [`ObjectSetMethods::object_set_debug`].
493
    fn debug_core(self) -> &'static str;
494

            
495
    /// Multiplicity representation for `#[deftly(netdoc(debug))]` output
496
    ///
497
    /// See [`ItemSetMethods::item_set_debug`] and [`ObjectSetMethods::debug_core`].
498
18
    fn object_set_debug(self) -> impl Debug {
499
18
        DebugHelper("object", self.debug_core())
500
18
    }
501

            
502
    /// If the contained type is `ItemObjectParseable`, call its `check_label`
503
2916
    fn check_label(self, label: &str) -> Result<(), EP>
504
2916
    where
505
2916
        Self::Each: ItemObjectParseable,
506
    {
507
2916
        Self::Each::check_label(label)
508
2916
    }
509

            
510
    /// Check that the contained type can be parsed as an object
511
2912
    fn check_object_parseable(self)
512
2912
    where
513
2912
        Self::Each: ItemObjectParseable,
514
    {
515
2912
    }
516
}
517
impl<T> ObjectSetMethods for MultiplicitySelector<Option<T>> {
518
    type Field = Option<T>;
519
    type Each = T;
520
52
    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
521
52
        Ok(found)
522
52
    }
523
    fn debug_core(self) -> &'static str {
524
        "Option<_>"
525
    }
526
}
527
impl<T> ObjectSetMethods for &MultiplicitySelector<T> {
528
    type Field = T;
529
    type Each = T;
530
5794
    fn resolve_option(self, found: Option<Self::Each>) -> Result<Self::Field, EP> {
531
5794
        found.ok_or(EP::MissingObject)
532
5794
    }
533
18
    fn debug_core(self) -> &'static str {
534
18
        "1"
535
18
    }
536
}