solverforge_scoring/stream/
collection_extract.rs1pub trait CollectionExtract<S>: Send + Sync {
30 type Item;
32
33 fn extract<'s>(&self, s: &'s S) -> &'s [Self::Item];
35
36 fn contains(&self, _s: &S, _item: &Self::Item) -> bool {
38 true
39 }
40
41 fn change_source(&self) -> ChangeSource {
45 ChangeSource::Unknown
46 }
47}
48
49#[doc(hidden)]
53pub struct FilteredExtract<E, F> {
54 extractor: E,
55 filter: F,
56}
57
58impl<E, F> FilteredExtract<E, F> {
59 pub fn new(extractor: E, filter: F) -> Self {
60 Self { extractor, filter }
61 }
62}
63
64impl<S, E, F> CollectionExtract<S> for FilteredExtract<E, F>
65where
66 E: CollectionExtract<S>,
67 F: super::filter::UniFilter<S, E::Item>,
68{
69 type Item = E::Item;
70
71 fn extract<'s>(&self, s: &'s S) -> &'s [Self::Item] {
72 self.extractor.extract(s)
73 }
74
75 fn contains(&self, s: &S, item: &Self::Item) -> bool {
76 self.extractor.contains(s, item) && self.filter.test(s, item)
77 }
78
79 fn change_source(&self) -> ChangeSource {
80 self.extractor.change_source()
81 }
82}
83
84#[doc(hidden)]
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum ChangeSource {
87 Unknown,
88 Static,
89 Descriptor(usize),
90}
91
92impl ChangeSource {
93 #[inline]
94 pub fn reacts_to(self, descriptor_index: usize) -> bool {
95 match self {
96 Self::Unknown => true,
97 Self::Static => false,
98 Self::Descriptor(index) => index == descriptor_index,
99 }
100 }
101
102 #[inline]
103 pub fn owns_descriptor(self, descriptor_index: usize) -> bool {
104 matches!(self, Self::Descriptor(index) if index == descriptor_index)
105 }
106
107 #[inline]
108 pub fn is_unknown(self) -> bool {
109 matches!(self, Self::Unknown)
110 }
111
112 #[inline]
113 pub fn same_index_domain(self, other: Self) -> bool {
114 matches!((self, other), (Self::Descriptor(left), Self::Descriptor(right)) if left == right)
115 }
116
117 #[inline]
118 pub fn assert_localizes(self, descriptor_index: usize, constraint_name: &str) -> bool {
119 if self.owns_descriptor(descriptor_index) {
120 return true;
121 }
122 if self.reacts_to(descriptor_index) {
123 panic!(
124 "constraint `{constraint_name}` received descriptor {descriptor_index}, but source {self:?} cannot localize entity indexes"
125 );
126 }
127 false
128 }
129}
130
131pub trait FlattenExtract<P>: Send + Sync {
132 type Item;
133
134 fn extract<'s>(&self, parent: &'s P) -> &'s [Self::Item];
135}
136
137impl<S, A, F> CollectionExtract<S> for F
138where
139 F: for<'a> Fn(&'a S) -> &'a [A] + Send + Sync,
140{
141 type Item = A;
142
143 #[inline]
144 fn extract<'s>(&self, s: &'s S) -> &'s [A] {
145 self(s)
146 }
147}
148
149impl<P, B, F> FlattenExtract<P> for F
150where
151 F: for<'a> Fn(&'a P) -> &'a [B] + Send + Sync,
152{
153 type Item = B;
154
155 #[inline]
156 fn extract<'s>(&self, parent: &'s P) -> &'s [B] {
157 self(parent)
158 }
159}
160
161#[derive(Clone, Copy)]
162pub struct FlattenVecExtract<F>(pub F);
163
164impl<P, B, F> FlattenExtract<P> for FlattenVecExtract<F>
165where
166 F: for<'a> Fn(&'a P) -> &'a Vec<B> + Send + Sync,
167{
168 type Item = B;
169
170 #[inline]
171 fn extract<'s>(&self, parent: &'s P) -> &'s [B] {
172 (self.0)(parent).as_slice()
173 }
174}
175
176#[doc(hidden)]
177#[derive(Clone, Copy)]
178pub struct SourceExtract<E> {
179 extractor: E,
180 change_source: ChangeSource,
181}
182
183impl<E> SourceExtract<E> {
184 pub fn new(extractor: E, change_source: ChangeSource) -> Self {
185 Self {
186 extractor,
187 change_source,
188 }
189 }
190
191 pub fn extractor(&self) -> &E {
192 &self.extractor
193 }
194}
195
196impl<S, E> CollectionExtract<S> for SourceExtract<E>
197where
198 E: CollectionExtract<S>,
199{
200 type Item = E::Item;
201
202 #[inline]
203 fn extract<'s>(&self, s: &'s S) -> &'s [Self::Item] {
204 self.extractor.extract(s)
205 }
206
207 #[inline]
208 fn contains(&self, s: &S, item: &Self::Item) -> bool {
209 self.extractor.contains(s, item)
210 }
211
212 fn change_source(&self) -> ChangeSource {
213 self.change_source
214 }
215}
216
217pub struct VecExtract<F>(pub F);
222
223impl<S, A, F> CollectionExtract<S> for VecExtract<F>
224where
225 F: for<'a> Fn(&'a S) -> &'a Vec<A> + Send + Sync,
226{
227 type Item = A;
228
229 #[inline]
230 fn extract<'s>(&self, s: &'s S) -> &'s [A] {
231 (self.0)(s).as_slice()
232 }
233}
234
235pub fn vec<S, A, F>(f: F) -> VecExtract<F>
254where
255 F: for<'a> Fn(&'a S) -> &'a Vec<A> + Send + Sync,
256{
257 VecExtract(f)
258}
259
260#[doc(hidden)]
261pub fn source<E>(extractor: E, change_source: ChangeSource) -> SourceExtract<E> {
262 SourceExtract::new(extractor, change_source)
263}