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
5450
    fn is_intro_item_keyword(self, kw: KeywordRef<'_>) -> bool
105
5450
    where
106
5450
        Self::Each: NetdocParseable,
107
    {
108
5450
        Self::Each::is_intro_item_keyword(kw)
109
5450
    }
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
108
    fn finish_subdoc(self, acc: Option<Self::Field>) -> Result<Self::Field, EP>
123
108
    where
124
108
        Self::Each: NetdocParseable,
125
    {
126
108
        self.finish(acc, Self::Each::doctype_for_error())
127
108
    }
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
2125
    fn check_item_value_parseable(self)
134
2125
    where
135
2125
        Self::Each: ItemValueParseable,
136
    {
137
2125
    }
138
    /// Check that the element type is a Signature
139
128
    fn check_signature_item_parseable(self)
140
128
    where
141
128
        Self::Each: SignatureItemParseable,
142
    {
143
128
    }
144
    /// Check that the element type is a sub-document
145
252
    fn check_subdoc_parseable(self)
146
252
    where
147
252
        Self::Each: NetdocParseable,
148
    {
149
252
    }
150
    /// Check that the element type is an argument
151
1579
    fn check_item_argument_parseable(self)
152
1579
    where
153
1579
        Self::Each: ItemArgumentParseable,
154
    {
155
1579
    }
156
}
157
impl<T> ItemSetMethods for MultiplicitySelector<Vec<T>> {
158
    type Each = T;
159
    type Field = Vec<T>;
160
    // We always have None, or Some(nonempty)
161
66
    fn can_accumulate(self, _acc: &Option<Vec<T>>) -> Result<(), EP> {
162
66
        Ok(())
163
66
    }
164
184
    fn accumulate(self, acc: &mut Option<Vec<T>>, item: T) -> Result<(), EP> {
165
184
        acc.get_or_insert_default().push(item);
166
184
        Ok(())
167
184
    }
168
200
    fn finish(self, acc: Option<Vec<T>>, _keyword: &'static str) -> Result<Vec<T>, EP> {
169
200
        Ok(acc.unwrap_or_default())
170
200
    }
171
}
172
impl<T: Ord> ItemSetMethods for MultiplicitySelector<BTreeSet<T>> {
173
    type Each = T;
174
    type Field = BTreeSet<T>;
175
    // We always have None, or Some(nonempty)
176
    fn can_accumulate(self, _acc: &Option<BTreeSet<T>>) -> Result<(), EP> {
177
        Ok(())
178
    }
179
    fn accumulate(self, acc: &mut Option<BTreeSet<T>>, item: T) -> Result<(), EP> {
180
        if !acc.get_or_insert_default().insert(item) {
181
            return Err(EP::ItemRepeated);
182
        }
183
        Ok(())
184
    }
185
    fn finish(self, acc: Option<BTreeSet<T>>, _keyword: &'static str) -> Result<BTreeSet<T>, EP> {
186
        Ok(acc.unwrap_or_default())
187
    }
188
}
189
impl<T> ItemSetMethods for MultiplicitySelector<Option<T>> {
190
    type Each = T;
191
    type Field = Option<T>;
192
    // We always have None, or Some(Some(_))
193
284
    fn can_accumulate(self, acc: &Option<Option<T>>) -> Result<(), EP> {
194
284
        if acc.is_some() {
195
            Err(EP::ItemRepeated)?;
196
284
        }
197
284
        Ok(())
198
284
    }
199
    // We always have None, or Some(Some(_))
200
242
    fn accumulate(self, acc: &mut Option<Option<T>>, item: T) -> Result<(), EP> {
201
242
        self.can_accumulate(acc)?;
202
242
        *acc = Some(Some(item));
203
242
        Ok(())
204
242
    }
205
722
    fn finish(self, acc: Option<Option<T>>, _keyword: &'static str) -> Result<Option<T>, EP> {
206
722
        Ok(acc.flatten())
207
722
    }
208
}
209
impl<T> ItemSetMethods for &'_ MultiplicitySelector<T> {
210
    type Each = T;
211
    type Field = T;
212
1222
    fn can_accumulate(self, acc: &Option<T>) -> Result<(), EP> {
213
1222
        if acc.is_some() {
214
2
            Err(EP::ItemRepeated)?;
215
1220
        }
216
1220
        Ok(())
217
1222
    }
218
1152
    fn accumulate(self, acc: &mut Option<T>, item: T) -> Result<(), EP> {
219
1152
        self.can_accumulate(acc)?;
220
1152
        *acc = Some(item);
221
1152
        Ok(())
222
1152
    }
223
1152
    fn finish(self, acc: Option<T>, keyword: &'static str) -> Result<T, EP> {
224
1152
        acc.ok_or(EP::MissingItem { keyword })
225
1152
    }
226
}
227

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

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

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

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

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

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

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

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

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