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 change_source(&self) -> ChangeSource {
40 ChangeSource::Unknown
41 }
42}
43
44#[doc(hidden)]
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum ChangeSource {
47 Unknown,
48 Static,
49 Descriptor(usize),
50}
51
52impl ChangeSource {
53 #[inline]
54 pub fn reacts_to(self, descriptor_index: usize) -> bool {
55 match self {
56 Self::Unknown => true,
57 Self::Static => false,
58 Self::Descriptor(index) => index == descriptor_index,
59 }
60 }
61
62 #[inline]
63 pub fn owns_descriptor(self, descriptor_index: usize) -> bool {
64 matches!(self, Self::Descriptor(index) if index == descriptor_index)
65 }
66
67 #[inline]
68 pub fn is_unknown(self) -> bool {
69 matches!(self, Self::Unknown)
70 }
71
72 #[inline]
73 pub fn same_index_domain(self, other: Self) -> bool {
74 matches!((self, other), (Self::Descriptor(left), Self::Descriptor(right)) if left == right)
75 }
76
77 #[inline]
78 pub fn assert_localizes(self, descriptor_index: usize, constraint_name: &str) -> bool {
79 if self.owns_descriptor(descriptor_index) {
80 return true;
81 }
82 if self.reacts_to(descriptor_index) {
83 panic!(
84 "constraint `{constraint_name}` received descriptor {descriptor_index}, but source {self:?} cannot localize entity indexes"
85 );
86 }
87 false
88 }
89}
90
91pub trait FlattenExtract<P>: Send + Sync {
92 type Item;
93
94 fn extract<'s>(&self, parent: &'s P) -> &'s [Self::Item];
95}
96
97impl<S, A, F> CollectionExtract<S> for F
98where
99 F: for<'a> Fn(&'a S) -> &'a [A] + Send + Sync,
100{
101 type Item = A;
102
103 #[inline]
104 fn extract<'s>(&self, s: &'s S) -> &'s [A] {
105 self(s)
106 }
107}
108
109impl<P, B, F> FlattenExtract<P> for F
110where
111 F: for<'a> Fn(&'a P) -> &'a [B] + Send + Sync,
112{
113 type Item = B;
114
115 #[inline]
116 fn extract<'s>(&self, parent: &'s P) -> &'s [B] {
117 self(parent)
118 }
119}
120
121#[derive(Clone, Copy)]
122pub struct FlattenVecExtract<F>(pub F);
123
124impl<P, B, F> FlattenExtract<P> for FlattenVecExtract<F>
125where
126 F: for<'a> Fn(&'a P) -> &'a Vec<B> + Send + Sync,
127{
128 type Item = B;
129
130 #[inline]
131 fn extract<'s>(&self, parent: &'s P) -> &'s [B] {
132 (self.0)(parent).as_slice()
133 }
134}
135
136#[doc(hidden)]
137#[derive(Clone, Copy)]
138pub struct SourceExtract<E> {
139 extractor: E,
140 change_source: ChangeSource,
141}
142
143impl<E> SourceExtract<E> {
144 pub fn new(extractor: E, change_source: ChangeSource) -> Self {
145 Self {
146 extractor,
147 change_source,
148 }
149 }
150
151 pub fn extractor(&self) -> &E {
152 &self.extractor
153 }
154}
155
156impl<S, E> CollectionExtract<S> for SourceExtract<E>
157where
158 E: CollectionExtract<S>,
159{
160 type Item = E::Item;
161
162 #[inline]
163 fn extract<'s>(&self, s: &'s S) -> &'s [Self::Item] {
164 self.extractor.extract(s)
165 }
166
167 fn change_source(&self) -> ChangeSource {
168 self.change_source
169 }
170}
171
172pub struct VecExtract<F>(pub F);
177
178impl<S, A, F> CollectionExtract<S> for VecExtract<F>
179where
180 F: for<'a> Fn(&'a S) -> &'a Vec<A> + Send + Sync,
181{
182 type Item = A;
183
184 #[inline]
185 fn extract<'s>(&self, s: &'s S) -> &'s [A] {
186 (self.0)(s).as_slice()
187 }
188}
189
190pub fn vec<S, A, F>(f: F) -> VecExtract<F>
209where
210 F: for<'a> Fn(&'a S) -> &'a Vec<A> + Send + Sync,
211{
212 VecExtract(f)
213}
214
215#[doc(hidden)]
216pub fn source<E>(extractor: E, change_source: ChangeSource) -> SourceExtract<E> {
217 SourceExtract::new(extractor, change_source)
218}