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

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

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

            
72
/// Methods for handling some multiplicity of netdoc elements, during encoding
73
///
74
/// **For use by macros**.
75
///
76
/// Each multiplicity impl allows us to iterate over the element(s).
77
///
78
/// Methods are also provided for typechecking, which are used by the derive macro to
79
/// produce reasonable error messages when a trait impl is missing.
80
//
81
// When adding features here, for example by implementing this trait,
82
// update the documentation in the `NetdocEncodable` and `ItemValueEncodable` derives.
83
pub trait MultiplicityMethods<'f>: Copy + Sized {
84
    /// The value for each thing.
85
    type Each: Sized + 'f;
86

            
87
    /// The input type: the type of the field in the netdoc or item struct.
88
    type Field: Sized;
89

            
90
    /// Return the appropriate implementor of `MultiplicityMethods`
91
254
    fn selector(self) -> Self {
92
254
        self
93
254
    }
94

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

            
98
    /// Cause a compiler error if the element is not `NetdocEncodable`
99
28
    fn check_netdoc_encodable(self)
100
28
    where
101
28
        Self::Each: NetdocEncodable,
102
    {
103
28
    }
104
    /// Cause a compiler error if the element is not `ItemValueEncodable`
105
128
    fn check_item_value_encodable(self)
106
128
    where
107
128
        Self::Each: ItemValueEncodable,
108
    {
109
128
    }
110
    /// Cause a compiler error if the element is not `ItemArgument`
111
64
    fn check_item_argument_encodable(self)
112
64
    where
113
64
        Self::Each: ItemArgument,
114
    {
115
64
    }
116
    /// Cause a compiler error if the element is not `ItemObjectEncodable`
117
8
    fn check_item_object_encodable(self)
118
8
    where
119
8
        Self::Each: ItemObjectEncodable,
120
    {
121
8
    }
122
}
123

            
124
impl<T> MultiplicitySelector<Vec<T>> {
125
    /// Return the appropriate implementor of `MultiplicityMethods`
126
    ///
127
    /// This is an inherent method so that it doesn't need the `EncodeOrd` bounds:
128
    /// that way if `EncodeOrd` is not implemented, we get a message about that,
129
    /// rather than a complaint that `ItemValueEncodable` isn't impl for `Vec<T>`.
130
44
    pub fn selector(self) -> DeterminedMultiplicitySelector<Vec<T>> {
131
44
        DeterminedMultiplicitySelector::default()
132
44
    }
133
}
134
impl<'f, T: EncodeOrd + 'f> MultiplicityMethods<'f> for DeterminedMultiplicitySelector<Vec<T>> {
135
    type Each = T;
136
    type Field = Vec<T>;
137
44
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> {
138
44
        let mut v = f.iter().collect_vec();
139
44
        v.sort_by(|a, b| a.encode_cmp(*b));
140
44
        v.into_iter()
141
44
    }
142
}
143
impl<'f, T: 'f> MultiplicityMethods<'f> for MultiplicitySelector<RetainedOrderVec<T>> {
144
    type Each = T;
145
    type Field = RetainedOrderVec<T>;
146
2
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> {
147
2
        f.0.iter()
148
2
    }
149
}
150
impl<'f, T: 'f> MultiplicityMethods<'f> for MultiplicitySelector<BTreeSet<T>> {
151
    type Each = T;
152
    type Field = BTreeSet<T>;
153
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> {
154
        f.iter()
155
    }
156
}
157
impl<'f, T: 'f> MultiplicityMethods<'f> for MultiplicitySelector<Option<T>> {
158
    type Each = T;
159
    type Field = Option<T>;
160
156
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> + 'f {
161
156
        f.iter()
162
156
    }
163
}
164
impl<'f, T: 'f> MultiplicityMethods<'f> for &'_ MultiplicitySelector<T> {
165
    type Each = T;
166
    type Field = T;
167
90
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> + 'f {
168
90
        iter::once(f)
169
90
    }
170
}
171
impl<'f, T: 'f> MultiplicityMethods<'f> for SingletonMultiplicitySelector<T> {
172
    type Each = T;
173
    type Field = T;
174
    fn iter_ordered(self, f: &'f Self::Field) -> impl Iterator<Item = &'f Self::Each> + 'f {
175
        iter::once(f)
176
    }
177
}
178

            
179
/// Methods for handling optionality of a netdoc Object, during encoding
180
///
181
// This could be used for things other than Object, if there were any thing
182
// that supported Option but not Vec.
183
//
184
/// **For use by macros**.
185
///
186
/// Each impl allows us to visit an optional element.
187
pub trait OptionalityMethods: Copy + Sized {
188
    /// The possibly-present element.
189
    type Each: Sized + 'static;
190

            
191
    /// The input type: the type of the field in the item struct.
192
    type Field: Sized;
193

            
194
    /// Yield the element, if there is one
195
    fn as_option<'f>(self, f: &'f Self::Field) -> Option<&'f Self::Each>;
196
}
197
impl<T: 'static> OptionalityMethods for MultiplicitySelector<Option<T>> {
198
    type Each = T;
199
    type Field = Option<T>;
200
12
    fn as_option<'f>(self, f: &'f Self::Field) -> Option<&'f Self::Each> {
201
12
        f.as_ref()
202
12
    }
203
}
204
impl<T: 'static> OptionalityMethods for &'_ MultiplicitySelector<T> {
205
    type Each = T;
206
    type Field = T;
207
10
    fn as_option<'f>(self, f: &'f Self::Field) -> Option<&'f Self::Each> {
208
10
        Some(f)
209
10
    }
210
}