1
//! Multiplicity for encoding netdoc elements, via ad-hoc deref specialisation.
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 `parse2::multiplicity` which is the corresponding module for parsing.
9
//!
10
//! # Explanation
11
//!
12
//! We use autoref specialisation to allow macros to dispatch to
13
//! trait impls for `Vec<T>`, `Option<T>` etc. as well as simply unadorned `T`.
14
//!
15
//! When methods on `MultiplicitySelector` are called, the compiler finds
16
//! the specific implementation for `MultiplicitySelector<Option<_>>` or `..Vec<_>`,
17
//! or, failing that, derefs and finds the blanket impl on `&MultiplicitySelector<T>`.
18
//!
19
//! For Objects, where only `T` and `Option<T>` are allowed,
20
//! we use `OptionalityMethods`.
21
//!
22
//! We implement traits on helper types `struct `[`MultiplicitySelector<Field>`],
23
//! [`DeterminedMultiplicitySelector`] and [`SingletonMultiplicitySelector`].
24
//!
25
//! The three selector types allow us to force the compiler to nail down the multiplicity,
26
//! during type inference, before considering whether the "each" type implements the
27
//! required trait.
28
//!
29
//! This is done by calling the `.selector()` method:
30
//! deref specialisation and inherent method vs trait method priority selects
31
//! the appropriate `.selector()` method, giving *another* selector,
32
//! so that the compiler only considers other selector's `MultiplicityMethods`,
33
//! when `.check_...` methods are used.
34
//! Otherwise, when a field has type (say) `Vec<NotItemValueParseable>`,
35
//! a call to `.check_item_value_encodable` could be resolved by autoref
36
//! so the compiler reports that **`Vec<..>`** doesn't implement the needed trait.
37
//! We prevent this by having
38
//! [`MultiplicitySelector::<Vec<_>>::default().selector()`](MultiplicitySelector::<Vec<T>>::selector)
39
//! be an inherent method returning [`DeterminedMultiplicitySelector`].
40
//!
41
//! `SingletonMultiplicitySelector` is used explicitly in the derive when we
42
//! know that we want to encode exactly one element:
43
//! for example, a document's intro item cannot be repeated or omitted.
44

            
45
use super::*;
46
use crate::types::RetainedOrderVec;
47

            
48
#[cfg(doc)]
49
use crate::parse2;
50

            
51
/// Helper type that allows us to select an impl of `MultiplicityMethods`
52
///
53
/// **For use by macros**.
54
///
55
/// This is distinct from `parse2::MultiplicitySelector`,
56
/// principally because it has the opposite variance.
57
#[derive(Educe)]
58
#[educe(Clone, Copy, Default)]
59
pub struct MultiplicitySelector<Field>(PhantomData<fn(Field)>);
60

            
61
/// Helper type implementing `MultiplicityMethods`, after the multiplicity is determined
62
///
63
/// **For use by macros**.
64
#[derive(Educe)]
65
#[educe(Clone, Copy, Default)]
66
pub struct DeterminedMultiplicitySelector<Field>(PhantomData<fn(Field)>);
67

            
68
/// Helper type implementing `MultiplicityMethods`, when a field is statically a singleton
69
///
70
/// **For use by macros**.
71
#[derive(Educe)]
72
#[educe(Clone, Copy, Default)]
73
pub struct SingletonMultiplicitySelector<Field>(PhantomData<fn(Field)>);
74

            
75
/// Methods for handling some multiplicity of netdoc elements, during encoding
76
///
77
/// **For use by macros**.
78
///
79
/// Each multiplicity impl allows us to iterate over the element(s).
80
///
81
/// Methods are also provided for typechecking, which are used by the derive macro to
82
/// produce reasonable error messages when a trait impl is missing.
83
//
84
// When adding features here, for example by implementing this trait,
85
// update the documentation in the `NetdocEncodable` and `ItemValueEncodable` derives.
86
pub trait MultiplicityMethods<'f>: Copy + Sized {
87
    /// The value for each thing.
88
    ///
89
    /// Should match the corresponding
90
    /// [`parse2::multiplicity::ItemSetMethods::Each`],
91
    /// [`parse2::multiplicity::ArgumentSetMethods::Each`],
92
    /// for consistency, and for the benefit of `with =` attributes referring to type names.
93
    //
94
    // For example, if these Each types don't match, then if you want to say
95
    //  `with = ns_type( Each, SomethingSpecial, ... )`
96
    // so that the plain consensus just uses the normal parsing, it doesn't
97
    // work, because `Each` has to match both `parse2::multiplicity::ItemSetSelector::Each`
98
    // and `encode::MultiplicityMethods::Each`, or the derived parsing code gets type errors.
99
    //
100
    // Having them different is anomalous, anyway.
101
    type Each: Sized + 'f;
102

            
103
    /// The input type: the type of the field in the netdoc or item struct.
104
    type Field: Sized;
105

            
106
    /// Return the appropriate implementor of `MultiplicityMethods`
107
890
    fn selector(self) -> Self {
108
890
        self
109
890
    }
110

            
111
    /// Yield the items, in a stable order
112
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> + 'f;
113

            
114
    /// Cause a compiler error if the element is not `NetdocEncodable`
115
40
    fn check_netdoc_encodable(self)
116
40
    where
117
40
        Self::Each: NetdocEncodable,
118
    {
119
40
    }
120
    /// Cause a compiler error if the element is not `ItemValueEncodable`
121
316
    fn check_item_value_encodable(self)
122
316
    where
123
316
        Self::Each: ItemValueEncodable,
124
    {
125
316
    }
126
    /// Cause a compiler error if the element is not `ItemArgument`
127
416
    fn check_item_argument_encodable(self)
128
416
    where
129
416
        Self::Each: ItemArgument,
130
    {
131
416
    }
132
    /// Cause a compiler error if the element is not `ItemObjectEncodable`
133
8
    fn check_item_object_encodable(self)
134
8
    where
135
8
        Self::Each: ItemObjectEncodable,
136
    {
137
8
    }
138
}
139

            
140
impl<T> MultiplicitySelector<Vec<T>> {
141
    /// Return the appropriate implementor of `MultiplicityMethods`
142
    ///
143
    /// This is an inherent method so that it doesn't need the `EncodeOrd` bounds:
144
    /// that way if `EncodeOrd` is not implemented, we get a message about that,
145
    /// rather than a complaint that `ItemValueEncodable` isn't impl for `Vec<T>`.
146
80
    pub fn selector(self) -> DeterminedMultiplicitySelector<Vec<T>> {
147
80
        DeterminedMultiplicitySelector::default()
148
80
    }
149
}
150
impl<'f, T: EncodeOrd + 'f> MultiplicityMethods<'f> for DeterminedMultiplicitySelector<Vec<T>> {
151
    type Each = T;
152
    type Field = Vec<T>;
153
80
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> {
154
80
        let mut v = f.iter().collect_vec();
155
80
        v.sort_by(|a, b| a.encode_cmp(*b));
156
80
        v.into_iter()
157
80
    }
158
}
159
impl<'f, T: 'f> MultiplicityMethods<'f> for MultiplicitySelector<RetainedOrderVec<T>> {
160
    type Each = T;
161
    type Field = RetainedOrderVec<T>;
162
2
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> {
163
2
        f.0.iter()
164
2
    }
165
}
166
impl<'f, T: 'f> MultiplicityMethods<'f> for MultiplicitySelector<BTreeSet<T>> {
167
    type Each = T;
168
    type Field = BTreeSet<T>;
169
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> {
170
        f.iter()
171
    }
172
}
173
impl<'f, T: 'f> MultiplicityMethods<'f> for MultiplicitySelector<Option<T>> {
174
    type Each = T;
175
    type Field = Option<T>;
176
214
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> + 'f {
177
214
        f.iter()
178
214
    }
179
}
180
impl<'f, T: 'f> MultiplicityMethods<'f> for &'_ MultiplicitySelector<T> {
181
    type Each = T;
182
    type Field = T;
183
562
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> + 'f {
184
562
        iter::once(f)
185
562
    }
186
}
187
impl<'f, T: 'f> MultiplicityMethods<'f> for SingletonMultiplicitySelector<T> {
188
    type Each = T;
189
    type Field = T;
190
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> + 'f {
191
        iter::once(f)
192
    }
193
}
194

            
195
/// Methods for handling optionality of a netdoc Object, during encoding
196
///
197
// This could be used for things other than Object, if there were any thing
198
// that supported Option but not Vec.
199
//
200
/// **For use by macros**.
201
///
202
/// Each impl allows us to visit an optional element.
203
pub trait OptionalityMethods: Copy + Sized {
204
    /// The possibly-present element.
205
    ///
206
    /// Should match the corresponding
207
    /// [`parse2::multiplicity::ObjectSetMethods::Each`].
208
    /// (See [`MultiplicityMethods::Each`] for rationale.)
209
    type Each: Sized + 'static;
210

            
211
    /// The input type: the type of the field in the item struct.
212
    type Field: Sized;
213

            
214
    /// Yield the element, if there is one
215
    fn as_option<'f>(self, f: &'f Self::Field) -> Option<&'f Self::Each>;
216
}
217
impl<T: 'static> OptionalityMethods for MultiplicitySelector<Option<T>> {
218
    type Each = T;
219
    type Field = Option<T>;
220
12
    fn as_option<'f>(self, f: &'f Self::Field) -> Option<&'f Self::Each> {
221
12
        f.as_ref()
222
12
    }
223
}
224
impl<T: 'static> OptionalityMethods for &'_ MultiplicitySelector<T> {
225
    type Each = T;
226
    type Field = T;
227
26
    fn as_option<'f>(self, f: &'f Self::Field) -> Option<&'f Self::Each> {
228
26
        Some(f)
229
26
    }
230
}