Skip to main content

graphrecords_query/operations/argument/
collection.rs

1use crate::{
2    Explain, QueryResult, ValueDomain,
3    execution::EvaluationCache,
4    explain::ExplainFormatter,
5    operations::{Prepare, SetSource},
6    optimizer::{Estimate, Estimated, PlanIdentity, PlanInputs, Stats},
7};
8use graphrecords_core::GraphRecord;
9use graphrecords_utils::aliases::GrHashSet;
10use std::{
11    collections::HashSet,
12    fmt::{self, Display, Write},
13    hash::{BuildHasher, DefaultHasher, Hash, Hasher},
14};
15
16impl<T: Display> Explain for Vec<T> {
17    fn describe<'a>(&'a self, formatter: &mut ExplainFormatter<'a, '_>) -> fmt::Result {
18        formatter.write_char('[')?;
19
20        for (position, member) in self.iter().enumerate() {
21            if position > 0 {
22                formatter.write_str(", ")?;
23            }
24
25            write!(formatter, "{member}")?;
26        }
27
28        formatter.write_char(']')
29    }
30}
31
32impl<T: PartialEq + Hash> PlanIdentity for Vec<T> {
33    fn identity_eq(&self, other: &Self) -> bool {
34        self == other
35    }
36
37    fn identity_hash<H: Hasher>(&self, state: &mut H) {
38        self.hash(state);
39    }
40}
41
42impl<T: Clone> PlanInputs for Vec<T> {}
43
44impl<T: 'static + Send + Sync> Prepare for Vec<T> {
45    type Prepared<'a> = &'a [T];
46
47    fn prepare<'a>(
48        &'a self,
49        _graphrecord: &'a GraphRecord,
50        _cache: &'a EvaluationCache<'a>,
51    ) -> QueryResult<Self::Prepared<'a>> {
52        Ok(self)
53    }
54}
55
56impl<T> Estimated for Vec<T> {
57    fn estimate(&self, _stats: &Stats) -> Estimate {
58        Estimate {
59            elements: Some(self.len()),
60            ..Estimate::UNKNOWN
61        }
62    }
63}
64
65impl<T, V> SetSource<V> for Vec<T>
66where
67    T: 'static + Clone + Eq + Hash + Display + Send + Sync,
68    for<'a> V: ValueDomain<Value<'a> = T>,
69{
70    fn set<'a>(prepared: Self::Prepared<'a>) -> QueryResult<GrHashSet<V::Value<'a>>>
71    where
72        Self: 'a,
73    {
74        Ok(prepared.iter().cloned().collect())
75    }
76}
77
78impl<T: Display, const N: usize> Explain for [T; N] {
79    fn describe<'a>(&'a self, formatter: &mut ExplainFormatter<'a, '_>) -> fmt::Result {
80        formatter.write_char('[')?;
81
82        for (position, member) in self.iter().enumerate() {
83            if position > 0 {
84                formatter.write_str(", ")?;
85            }
86
87            write!(formatter, "{member}")?;
88        }
89
90        formatter.write_char(']')
91    }
92}
93
94impl<T: PartialEq + Hash, const N: usize> PlanIdentity for [T; N] {
95    fn identity_eq(&self, other: &Self) -> bool {
96        self == other
97    }
98
99    fn identity_hash<H: Hasher>(&self, state: &mut H) {
100        self.hash(state);
101    }
102}
103
104impl<T: Clone, const N: usize> PlanInputs for [T; N] {}
105
106impl<T: 'static + Send + Sync, const N: usize> Prepare for [T; N] {
107    type Prepared<'a> = &'a [T];
108
109    fn prepare<'a>(
110        &'a self,
111        _graphrecord: &'a GraphRecord,
112        _cache: &'a EvaluationCache<'a>,
113    ) -> QueryResult<Self::Prepared<'a>> {
114        Ok(self)
115    }
116}
117
118impl<T, const N: usize> Estimated for [T; N] {
119    fn estimate(&self, _stats: &Stats) -> Estimate {
120        Estimate {
121            elements: Some(N),
122            ..Estimate::UNKNOWN
123        }
124    }
125}
126
127impl<T, V, const N: usize> SetSource<V> for [T; N]
128where
129    T: 'static + Clone + Eq + Hash + Display + Send + Sync,
130    for<'a> V: ValueDomain<Value<'a> = T>,
131{
132    fn set<'a>(prepared: Self::Prepared<'a>) -> QueryResult<GrHashSet<V::Value<'a>>>
133    where
134        Self: 'a,
135    {
136        Ok(prepared.iter().cloned().collect())
137    }
138}
139
140impl<T: Display> Explain for GrHashSet<T> {
141    fn describe<'a>(&'a self, formatter: &mut ExplainFormatter<'a, '_>) -> fmt::Result {
142        let mut members: Vec<_> = self.iter().map(ToString::to_string).collect();
143        members.sort_unstable();
144
145        formatter.write_char('[')?;
146
147        for (position, member) in members.iter().enumerate() {
148            if position > 0 {
149                formatter.write_str(", ")?;
150            }
151
152            formatter.write_str(member)?;
153        }
154
155        formatter.write_char(']')
156    }
157}
158
159impl<T: Eq + Hash> PlanIdentity for GrHashSet<T> {
160    fn identity_eq(&self, other: &Self) -> bool {
161        self == other
162    }
163
164    fn identity_hash<H: Hasher>(&self, state: &mut H) {
165        state.write_usize(self.len());
166
167        let combined = self
168            .iter()
169            .map(|member| {
170                let mut hasher = DefaultHasher::new();
171                member.hash(&mut hasher);
172                hasher.finish()
173            })
174            .fold(0_u64, u64::wrapping_add);
175
176        state.write_u64(combined);
177    }
178}
179
180impl<T: Clone> PlanInputs for GrHashSet<T> {}
181
182impl<T: 'static + Send + Sync> Prepare for GrHashSet<T> {
183    type Prepared<'a> = &'a Self;
184
185    fn prepare<'a>(
186        &'a self,
187        _graphrecord: &'a GraphRecord,
188        _cache: &'a EvaluationCache<'a>,
189    ) -> QueryResult<Self::Prepared<'a>> {
190        Ok(self)
191    }
192}
193
194impl<T> Estimated for GrHashSet<T> {
195    fn estimate(&self, _stats: &Stats) -> Estimate {
196        Estimate::values(self.len(), self.len())
197    }
198}
199
200impl<T, V> SetSource<V> for GrHashSet<T>
201where
202    T: 'static + Clone + Eq + Hash + Display + Send + Sync,
203    for<'a> V: ValueDomain<Value<'a> = T>,
204{
205    fn set<'a>(prepared: Self::Prepared<'a>) -> QueryResult<GrHashSet<V::Value<'a>>>
206    where
207        Self: 'a,
208    {
209        Ok(prepared.clone())
210    }
211}
212
213impl<T: Display, S> Explain for HashSet<T, S> {
214    fn describe<'a>(&'a self, formatter: &mut ExplainFormatter<'a, '_>) -> fmt::Result {
215        let mut members: Vec<_> = self.iter().map(ToString::to_string).collect();
216        members.sort_unstable();
217
218        formatter.write_char('[')?;
219
220        for (position, member) in members.iter().enumerate() {
221            if position > 0 {
222                formatter.write_str(", ")?;
223            }
224
225            formatter.write_str(member)?;
226        }
227
228        formatter.write_char(']')
229    }
230}
231
232impl<T: Eq + Hash, S: BuildHasher> PlanIdentity for HashSet<T, S> {
233    fn identity_eq(&self, other: &Self) -> bool {
234        self == other
235    }
236
237    fn identity_hash<H: Hasher>(&self, state: &mut H) {
238        state.write_usize(self.len());
239
240        let combined = self
241            .iter()
242            .map(|member| {
243                let mut hasher = DefaultHasher::new();
244                member.hash(&mut hasher);
245                hasher.finish()
246            })
247            .fold(0_u64, u64::wrapping_add);
248
249        state.write_u64(combined);
250    }
251}
252
253impl<T: Clone, S: Clone> PlanInputs for HashSet<T, S> {}
254
255impl<T: 'static + Send + Sync, S: 'static + Send + Sync> Prepare for HashSet<T, S> {
256    type Prepared<'a> = &'a Self;
257
258    fn prepare<'a>(
259        &'a self,
260        _graphrecord: &'a GraphRecord,
261        _cache: &'a EvaluationCache<'a>,
262    ) -> QueryResult<Self::Prepared<'a>> {
263        Ok(self)
264    }
265}
266
267impl<T, S> Estimated for HashSet<T, S> {
268    fn estimate(&self, _stats: &Stats) -> Estimate {
269        Estimate::values(self.len(), self.len())
270    }
271}
272
273impl<T, S, V> SetSource<V> for HashSet<T, S>
274where
275    T: 'static + Clone + Eq + Hash + Display + Send + Sync,
276    for<'a> V: ValueDomain<Value<'a> = T>,
277    S: 'static + Clone + BuildHasher + Send + Sync,
278{
279    fn set<'a>(prepared: Self::Prepared<'a>) -> QueryResult<GrHashSet<V::Value<'a>>>
280    where
281        Self: 'a,
282    {
283        Ok(prepared.iter().cloned().collect())
284    }
285}