Skip to main content

dag/
set.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8//! # set
9//!
10//! See [`Set`] for the main structure.
11
12use std::any::Any;
13use std::borrow::Cow;
14use std::cmp;
15use std::fmt;
16use std::fmt::Debug;
17use std::ops::Add;
18use std::ops::BitAnd;
19use std::ops::BitOr;
20use std::ops::Deref;
21use std::ops::Sub;
22use std::pin::Pin;
23use std::sync::Arc;
24
25use futures::future::BoxFuture;
26use futures::Stream;
27use futures::StreamExt;
28use nonblocking::non_blocking;
29
30use crate::default_impl;
31use crate::ops::DagAlgorithm;
32use crate::ops::IdConvert;
33use crate::ops::IdMapSnapshot;
34use crate::ops::Parents;
35use crate::Id;
36use crate::IdList;
37use crate::IdSet;
38use crate::Result;
39use crate::Vertex;
40
41pub mod difference;
42pub mod hints;
43pub mod id_lazy;
44pub mod id_static;
45pub mod intersection;
46pub mod lazy;
47#[cfg(any(test, feature = "indexedlog-backend"))]
48pub mod legacy;
49pub mod meta;
50pub mod reverse;
51pub mod slice;
52pub mod r#static;
53pub mod union;
54
55use self::hints::Flags;
56use self::hints::Hints;
57use self::id_static::BasicIterationOrder;
58use self::id_static::IdStaticSet;
59use self::meta::MetaSet;
60use self::reverse::ReverseSet;
61use self::r#static::StaticSet;
62
63/// A [`Set`] contains an immutable list of names.
64///
65/// It provides order-preserving iteration and set operations,
66/// and is cheaply clonable.
67#[derive(Clone)]
68pub struct Set(Arc<dyn AsyncSetQuery>);
69
70impl Set {
71    pub(crate) fn from_query(query: impl AsyncSetQuery) -> Self {
72        Self(Arc::new(query))
73    }
74
75    /// Creates an empty set.
76    pub fn empty() -> Self {
77        Self::from_query(r#static::StaticSet::empty())
78    }
79
80    /// Creates from a (short) list of known names.
81    pub fn from_static_names(names: impl IntoIterator<Item = Vertex>) -> Set {
82        Self::from_query(r#static::StaticSet::from_names(names))
83    }
84
85    /// Creates from a (lazy) iterator of names.
86    pub fn from_iter<I>(iter: I, hints: Hints) -> Set
87    where
88        I: IntoIterator<Item = Result<Vertex>> + 'static,
89        <I as IntoIterator>::IntoIter: Send + Sync,
90    {
91        Self::from_query(lazy::LazySet::from_iter(iter, hints))
92    }
93
94    /// Creates from a (lazy) stream of names with hints.
95    pub fn from_stream(stream: BoxVertexStream, hints: Hints) -> Set {
96        Self::from_query(lazy::LazySet::from_stream(stream, hints))
97    }
98
99    /// Creates from a (lazy) iterator of Ids, an IdMap, and a Dag.
100    pub fn from_id_iter_idmap_dag<I>(
101        iter: I,
102        map: Arc<dyn IdConvert + Send + Sync>,
103        dag: Arc<dyn DagAlgorithm + Send + Sync>,
104    ) -> Set
105    where
106        I: IntoIterator<Item = Result<Id>> + 'static,
107        <I as IntoIterator>::IntoIter: Send + Sync,
108    {
109        Self::from_query(id_lazy::IdLazySet::from_iter_idmap_dag(iter, map, dag))
110    }
111
112    /// Creates from a (lazy) iterator of Ids and a struct with snapshot abilities.
113    pub fn from_id_iter_dag<I>(iter: I, dag: &(impl DagAlgorithm + IdMapSnapshot)) -> Result<Set>
114    where
115        I: IntoIterator<Item = Result<Id>> + 'static,
116        <I as IntoIterator>::IntoIter: Send + Sync,
117    {
118        let map = dag.id_map_snapshot()?;
119        let dag = dag.dag_snapshot()?;
120        Ok(Self::from_id_iter_idmap_dag(iter, map, dag))
121    }
122
123    /// Creates from [`IdSet`], [`IdMap`] and [`DagAlgorithm`].
124    /// Callsite must make sure `spans`, `map`, `dag` are using the same `Id` mappings.
125    /// Prefer `from_id_set_dag` if possible.
126    pub fn from_id_set_idmap_dag(
127        spans: IdSet,
128        map: Arc<dyn IdConvert + Send + Sync>,
129        dag: Arc<dyn DagAlgorithm + Send + Sync>,
130    ) -> Set {
131        Self::from_id_set_idmap_dag_order(spans, map, dag, None)
132    }
133
134    /// Creates from [`IdSet`], [`IdMap`], [`DagAlgorithm`], and [`BasicIterationOrder`].
135    /// Callsite must make sure `spans`, `map`, `dag` are using the same `Id` mappings.
136    pub fn from_id_set_idmap_dag_order(
137        spans: IdSet,
138        map: Arc<dyn IdConvert + Send + Sync>,
139        dag: Arc<dyn DagAlgorithm + Send + Sync>,
140        iteration_order: Option<BasicIterationOrder>,
141    ) -> Set {
142        let mut set = IdStaticSet::from_id_set_idmap_dag(spans, map, dag);
143        if let Some(order) = iteration_order {
144            set.set_iteration_order(order);
145        }
146        Self::from_query(set)
147    }
148
149    /// Creates from [`IdSet`] and a struct with snapshot abilities.
150    /// Callsite must make sure `spans`, `dag` are using the same `Id` mappings.
151    pub fn from_id_set_dag(
152        spans: IdSet,
153        dag: &(impl DagAlgorithm + IdMapSnapshot),
154    ) -> Result<Self> {
155        let map = dag.id_map_snapshot()?;
156        let dag = dag.dag_snapshot()?;
157        Ok(Self::from_id_set_idmap_dag(spans, map, dag))
158    }
159
160    /// Creates from [`IdList`] and a struct with snapshot abilities.
161    /// Unlike [`Self::from_id_set_dag`], the iteration order of `list` will be preserved.
162    /// Callsite must make sure `list`, `dag` are using the same `Id` mappings.
163    pub fn from_id_list_dag(
164        list: IdList,
165        dag: &(impl DagAlgorithm + IdMapSnapshot),
166    ) -> Result<Self> {
167        let map = dag.id_map_snapshot()?;
168        let dag = dag.dag_snapshot()?;
169        let set = IdStaticSet::from_id_list_idmap_dag(list, map, dag);
170        Ok(Self::from_query(set))
171    }
172
173    /// Creates from a function that evaluates to a [`Set`], and a
174    /// `contains` fast path.
175    pub fn from_evaluate_contains<C>(
176        evaluate: impl Fn() -> Result<Set> + Send + Sync + 'static,
177        contains: C,
178        hints: Hints,
179    ) -> Set
180    where
181        C: for<'a> Fn(&'a MetaSet, &'a Vertex) -> Result<bool>,
182        C: Send + Sync + 'static,
183    {
184        let evaluate = move || -> BoxFuture<_> {
185            let result = evaluate();
186            Box::pin(async move { result })
187        };
188        let contains = Arc::new(contains);
189        Self::from_async_evaluate_contains(
190            Box::new(evaluate),
191            Box::new(move |m, v| {
192                let contains = contains.clone();
193                Box::pin(async move { contains(m, v) })
194            }),
195            hints,
196        )
197    }
198
199    /// Creates from an async function that evaluates to a [`Set`], and a
200    /// async `contains` fast path.
201    pub fn from_async_evaluate_contains(
202        evaluate: Box<dyn Fn() -> BoxFuture<'static, Result<Set>> + Send + Sync>,
203        contains: Box<
204            dyn for<'a> Fn(&'a MetaSet, &'a Vertex) -> BoxFuture<'a, Result<bool>> + Send + Sync,
205        >,
206        hints: Hints,
207    ) -> Set {
208        Self::from_query(MetaSet::from_evaluate_hints(evaluate, hints).with_contains(contains))
209    }
210
211    /// Reverse the iteration order of the `Set`.
212    pub fn reverse(&self) -> Set {
213        match self.0.specialized_reverse() {
214            Some(set) => set,
215            None => Self::from_query(ReverseSet::new(self.clone())),
216        }
217    }
218
219    /// Calculates the subset that is only in self, not in other.
220    pub fn difference(&self, other: &Set) -> Set {
221        if other.hints().contains(Flags::FULL)
222            && other.hints().dag_version() >= self.hints().dag_version()
223            && self.hints().dag_version() > None
224        {
225            tracing::debug!(
226                target: "dag::algo::difference",
227                "difference(x={:.6?}, y={:.6?}) = () (fast path 1)",
228                self,
229                other
230            );
231            return Self::empty();
232        }
233        if self.hints().contains(Flags::EMPTY) || other.hints().contains(Flags::EMPTY) {
234            tracing::debug!(
235                target: "dag::algo::difference",
236                "difference(x={:.6?}, y={:.6?}) = x (fast path 2)",
237                self,
238                other
239            );
240            return self.clone();
241        }
242        if let (Some(this), Some(other)) = (
243            self.as_any().downcast_ref::<IdStaticSet>(),
244            // xs - ys; the order of ys does not matter
245            other.specialized_flatten_id(),
246        ) {
247            let order = this.map.map_version().partial_cmp(other.map.map_version());
248            if let (Some(_order), Some(this_id_set)) = (order, this.id_set_try_preserving_order()) {
249                // Fast path for IdStaticSet.
250                // The order is preserved, `this.is_id_sorted` is true.
251                let result = Self::from_id_set_idmap_dag_order(
252                    this_id_set.difference(other.id_set_losing_order()),
253                    this.map.clone(),
254                    this.dag.clone(),
255                    this.iteration_order(),
256                );
257                tracing::debug!(
258                    target: "dag::algo::difference",
259                    "difference(x={:.6?}, y={:.6?}) = {:.6?} (fast path 3)",
260                    self,
261                    other,
262                    &result
263                );
264                return result;
265            }
266        }
267        tracing::warn!(
268                target: "dag::algo::difference",
269            "difference(x={:.6?}, y={:.6?}) (slow path)", self, other);
270        Self::from_query(difference::DifferenceSet::new(self.clone(), other.clone()))
271    }
272
273    /// Calculates the intersection of two sets.
274    pub fn intersection(&self, other: &Set) -> Set {
275        if self.hints().contains(Flags::FULL)
276            && self.hints().dag_version() >= other.hints().dag_version()
277            && other.hints().dag_version() > None
278        {
279            tracing::debug!(
280                target: "dag::algo::intersection",
281                "intersection(x={:.6?}, y={:.6?}) = y (fast path 1)",
282                self,
283                other
284            );
285            return other.clone();
286        }
287        if other.hints().contains(Flags::FULL)
288            && other.hints().dag_version() >= self.hints().dag_version()
289            && self.hints().dag_version() > None
290        {
291            tracing::debug!(
292                target: "dag::algo::intersection",
293                "intersection(x={:.6?}, y={:.6?}) = x (fast path 2)",
294                self,
295                other
296            );
297            return self.clone();
298        }
299        if self.hints().contains(Flags::EMPTY) || other.hints().contains(Flags::EMPTY) {
300            tracing::debug!(
301                target: "dag::algo::intersection",
302                "intersection(x={:.6?}, y={:.6?}) = () (fast path 3)",
303                self,
304                other
305            );
306            return Self::empty();
307        }
308        if let (Some(this), Some(other)) = (
309            self.as_any().downcast_ref::<IdStaticSet>(),
310            // xs & ys; the order of ys does not matter
311            other.specialized_flatten_id(),
312        ) {
313            let order = this.map.map_version().partial_cmp(other.map.map_version());
314            if let (Some(order), Some(this_id_set)) = (order, this.id_set_try_preserving_order()) {
315                // Fast path for IdStaticSet
316                let result = Self::from_id_set_idmap_dag_order(
317                    this_id_set.intersection(other.id_set_losing_order()),
318                    pick(order, &this.map, &other.map).clone(),
319                    pick(order, &this.dag, &other.dag).clone(),
320                    this.iteration_order(),
321                );
322                tracing::debug!(
323                    target: "dag::algo::intersection",
324                    "intersection(x={:.6?}, y={:.6?}) = {:?} (IdStatic fast path)",
325                    self,
326                    other,
327                    &result
328                );
329                return result;
330            }
331        }
332        tracing::warn!(
333            target: "dag::algo::intersection",
334            "intersection(x={:.6?}, y={:.6?}) (slow path)", self, other);
335        Self::from_query(intersection::IntersectionSet::new(
336            self.clone(),
337            other.clone(),
338        ))
339    }
340
341    /// Union fast paths. Handles when one set is "FULL" or "EMPTY".
342    fn union_fast_paths(&self, other: &Self) -> Option<Self> {
343        if (self.hints().contains(Flags::FULL)
344            && self.hints().dag_version() >= other.hints().dag_version()
345            && other.hints().dag_version() > None)
346            || other.hints().contains(Flags::EMPTY)
347        {
348            tracing::debug!(
349                target: "dag::algo::union",
350                "union(x={:.6?}, y={:.6?}) = x (fast path 1)", self, other);
351            return Some(self.clone());
352        }
353        if self.hints().contains(Flags::EMPTY)
354            || (other.hints().contains(Flags::FULL)
355                && other.hints().dag_version() >= self.hints().dag_version()
356                && self.hints().dag_version() > None)
357        {
358            tracing::debug!(
359                target: "dag::algo::union",
360                "union(x={:.6?}, y={:.6?}) = y (fast path 2)", self, other);
361            return Some(other.clone());
362        }
363        None
364    }
365
366    /// Calculates the union of two sets. Iteration order might get lost.
367    pub fn union(&self, other: &Set) -> Set {
368        if let Some(set) = self.union_fast_paths(other) {
369            return set;
370        }
371
372        // This fast path aggressively flatten the sets. It does not preserve order.
373        if let (Some(this), Some(other)) = (
374            self.specialized_flatten_id(),
375            other.specialized_flatten_id(),
376        ) {
377            let order = this.map.map_version().partial_cmp(other.map.map_version());
378            if let Some(order) = order {
379                // Fast path for IdStaticSet
380                let result = Self::from_id_set_idmap_dag_order(
381                    this.id_set_losing_order()
382                        .union(other.id_set_losing_order()),
383                    pick(order, &this.map, &other.map).clone(),
384                    pick(order, &this.dag, &other.dag).clone(),
385                    this.iteration_order(),
386                );
387                tracing::debug!(
388                    target: "dag::algo::union",
389                    "union(x={:.6?}, y={:.6?}) = {:.6?} (fast path 3)",
390                    self,
391                    other,
392                    &result
393                );
394                return result;
395            }
396        }
397        tracing::warn!(
398            target: "dag::algo::union",
399            "union(x={:.6?}, y={:.6?}) (slow path)", self, other);
400        Self::from_query(union::UnionSet::new(self.clone(), other.clone()))
401    }
402
403    /// Union, but preserve the iteration order (self first, other next).
404    pub fn union_preserving_order(&self, other: &Self) -> Self {
405        if let Some(set) = self.union_fast_paths(other) {
406            return set;
407        }
408        tracing::debug!(target: "dag::algo::union_preserving_order", "union(x={:.6?}, y={:.6?})", self, other);
409        Self::from_query(union::UnionSet::new(self.clone(), other.clone()))
410    }
411
412    /// Similar to `union`, but without showfast paths, and force a "flatten zip" order.
413    /// For example `[1,2,3,4].union_zip([5,6])` produces this order: `[1,5,2,6,3,4]`.
414    pub fn union_zip(&self, other: &Set) -> Set {
415        tracing::debug!(
416            target: "dag::algo::union_zip",
417            "union_zip(x={:.6?}, y={:.6?}) (slow path)", self, other);
418        Self::from_query(
419            union::UnionSet::new(self.clone(), other.clone()).with_order(union::UnionOrder::Zip),
420        )
421    }
422
423    /// Filter using the given async function. If `filter_func` returns `true`
424    /// for a vertex, then the vertex will be taken, other it will be skipped.
425    pub fn filter(
426        &self,
427        filter_func: Box<dyn Fn(&Vertex) -> BoxFuture<Result<bool>> + Send + Sync + 'static>,
428    ) -> Self {
429        let filter_func = Arc::new(filter_func);
430        let this = self.clone();
431        let hints = {
432            // Drop ANCESTORS | FULL and add FILTER.
433            let hints = self.hints().clone();
434            hints.update_flags_with(|f| (f - Flags::ANCESTORS - Flags::FULL) | Flags::FILTER);
435            hints
436        };
437        let result = Self::from_async_evaluate_contains(
438            Box::new({
439                let filter_func = filter_func.clone();
440                let this = this.clone();
441                let hints = hints.clone();
442                move || {
443                    let filter_func = filter_func.clone();
444                    let this = this.clone();
445                    let hints = hints.clone();
446                    Box::pin(async move {
447                        let stream = this.0.iter().await?;
448                        let stream = stream.filter_map(move |v| {
449                            let filter_func = filter_func.clone();
450                            async move {
451                                match v {
452                                    Ok(v) => match filter_func(&v).await {
453                                        Ok(true) => Some(Ok(v)),
454                                        Ok(false) => None,
455                                        Err(e) => Some(Err(e)),
456                                    },
457                                    Err(e) => Some(Err(e)),
458                                }
459                            }
460                        });
461                        Ok(Self::from_stream(Box::pin(stream), hints))
462                    })
463                }
464            }),
465            Box::new(move |_, v| {
466                let filter_func = filter_func.clone();
467                let this = this.clone();
468                Box::pin(async move { Ok(this.0.contains(v).await? && filter_func(v).await?) })
469            }),
470            hints,
471        );
472        result.hints().add_flags(Flags::FILTER);
473        result
474    }
475
476    /// Convert the set to a graph containing only the vertexes in the set. This can be slow on
477    /// larger sets.
478    pub async fn to_parents(&self) -> Result<Option<impl Parents>> {
479        default_impl::set_to_parents(self).await
480    }
481
482    /// Obtain the attached dag if available.
483    pub fn dag(&self) -> Option<Arc<dyn DagAlgorithm + Send + Sync>> {
484        self.hints().dag()
485    }
486
487    /// Obtain the attached IdMap if available.
488    pub fn id_map(&self) -> Option<Arc<dyn IdConvert + Send + Sync>> {
489        self.hints().id_map()
490    }
491
492    /// Convert the current set into a flat static set so it can be used in some
493    /// fast paths. This is useful for some common sets like `obsolete()` that
494    /// might be represented by a complex expression.
495    ///
496    /// By flattening, the iteration order might be lost.
497    pub async fn flatten(&self) -> Result<Set> {
498        match (self.id_map(), self.dag()) {
499            (Some(id_map), Some(dag)) => {
500                // Convert to IdStaticSet
501                self.flatten_id(id_map, dag).await
502            }
503            _ => {
504                // Convert to StaticSet
505                self.flatten_names().await
506            }
507        }
508    }
509
510    /// Convert this set to a static id set.
511    ///
512    /// By flattening, the iteration order might be lost.
513    pub async fn flatten_id(
514        &self,
515        id_map: Arc<dyn IdConvert + Send + Sync>,
516        dag: Arc<dyn DagAlgorithm + Send + Sync>,
517    ) -> Result<Set> {
518        if self.as_any().is::<IdStaticSet>() {
519            return Ok(self.clone());
520        }
521        let mut ids = Vec::with_capacity(self.count()?.try_into()?);
522        for vertex in self.iter()? {
523            let id = id_map.vertex_id(vertex?).await?;
524            ids.push(id);
525        }
526        ids.sort_unstable_by_key(|i| u64::MAX - i.0);
527        let spans = IdSet::from_sorted_spans(ids);
528        let flat_set = Set::from_id_set_idmap_dag(spans, id_map, dag);
529        flat_set.hints().inherit_flags_min_max_id(self.hints());
530        Ok(flat_set)
531    }
532
533    /// Convert this set to a static name set.
534    pub async fn flatten_names(&self) -> Result<Set> {
535        if self.as_any().is::<StaticSet>() {
536            return Ok(self.clone());
537        }
538        let names = self.iter()?.collect::<Result<Vec<_>>>()?;
539        let flat_set = Self::from_static_names(names);
540        flat_set.hints().inherit_flags_min_max_id(self.hints());
541        Ok(flat_set)
542    }
543
544    /// Take the first `n` items.
545    pub fn take(&self, n: u64) -> Set {
546        if let Some(set) = self.specialized_take(n) {
547            tracing::debug!("take(x={:.6?}, {}) (specialized path)", self, n);
548            set
549        } else {
550            tracing::debug!("take(x={:.6?}, {}) (universal path)", self, n);
551            let set = slice::SliceSet::new(self.clone(), 0, Some(n));
552            Self::from_query(set)
553        }
554    }
555
556    /// Skip the first `n` items.
557    pub fn skip(&self, n: u64) -> Set {
558        if n == 0 {
559            return self.clone();
560        }
561        if let Some(set) = self.specialized_skip(n) {
562            tracing::debug!("skip(x={:.6?}, {}) (specialized path)", self, n);
563            set
564        } else {
565            tracing::debug!("skip(x={:.6?}, {}) (universal path)", self, n);
566            let set = slice::SliceSet::new(self.clone(), n, None);
567            Self::from_query(set)
568        }
569    }
570
571    /// Converts to `(IdSet, IdConvert)` pair in O(1). If the underlying set
572    /// cannot provide such information in O(1), return `None`.
573    ///
574    /// Useful if the callsite wants to have random access (ex.pathhistory)
575    /// and control how to resolve in batches.
576    pub fn to_id_set_and_id_map_in_o1(&self) -> Option<(IdSet, Arc<dyn IdConvert + Send + Sync>)> {
577        let id_set = self.specialized_flatten_id()?.into_owned();
578        Some((id_set.id_set_losing_order().clone(), id_set.map))
579    }
580}
581
582impl BitAnd for Set {
583    type Output = Self;
584
585    fn bitand(self, other: Self) -> Self {
586        self.intersection(&other)
587    }
588}
589
590impl BitOr for Set {
591    type Output = Self;
592
593    fn bitor(self, other: Self) -> Self {
594        self.union(&other)
595    }
596}
597
598impl Add for Set {
599    type Output = Self;
600
601    fn add(self, rhs: Self) -> Self::Output {
602        self.union_preserving_order(&rhs)
603    }
604}
605
606impl Sub for Set {
607    type Output = Self;
608
609    fn sub(self, other: Self) -> Self {
610        self.difference(&other)
611    }
612}
613
614impl Deref for Set {
615    type Target = dyn AsyncSetQuery;
616
617    fn deref(&self) -> &Self::Target {
618        self.0.deref()
619    }
620}
621
622impl fmt::Debug for Set {
623    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
624        self.0.fmt(f)
625    }
626}
627
628/// Read-only queries required by [`Set`]: Iteration, length and contains.
629///
630/// Types implementating this trait should rewrite methods to use fast paths
631/// when possible.
632#[async_trait::async_trait]
633pub trait AsyncSetQuery: Any + Debug + Send + Sync {
634    /// Iterate through the set in defined order.
635    async fn iter(&self) -> Result<BoxVertexStream>;
636
637    /// Iterate through the set in the reversed order.
638    async fn iter_rev(&self) -> Result<BoxVertexStream> {
639        let mut iter = self.iter().await?;
640        let mut items = Vec::new();
641        while let Some(item) = iter.next().await {
642            items.push(item);
643        }
644        Ok(Box::pin(futures::stream::iter(items.into_iter().rev())))
645    }
646
647    /// Number of names in this set. Do not override.
648    ///
649    /// This function has some built-in fast paths.
650    /// For individual set types, override count_slow, size_hint instead of count.
651    async fn count(&self) -> Result<u64> {
652        if let Some(flat) = self.specialized_flatten_id() {
653            return flat.count_slow().await;
654        }
655        self.count_slow().await
656    }
657
658    /// "Slow" count implementation. Intended to be overridden.
659    ///
660    /// This is intended to be implemented by individual set types as fallbacks
661    /// when the universal fast paths do not work.
662    async fn count_slow(&self) -> Result<u64> {
663        let mut iter = self.iter().await?;
664        let mut count = 0;
665        while let Some(item) = iter.next().await {
666            item?;
667            count += 1;
668        }
669        Ok(count)
670    }
671
672    /// Returns the bounds on the length of the set as a hint.
673    /// The first item is the lower bound.
674    /// The second item is the upper bound.
675    /// This method should not block on long operations like waiting for network.
676    async fn size_hint(&self) -> (u64, Option<u64>) {
677        (0, None)
678    }
679
680    /// The first name in the set.
681    async fn first(&self) -> Result<Option<Vertex>> {
682        self.iter().await?.next().await.transpose()
683    }
684
685    /// The last name in the set.
686    async fn last(&self) -> Result<Option<Vertex>> {
687        self.iter_rev().await?.next().await.transpose()
688    }
689
690    /// Test if this set is empty.
691    async fn is_empty(&self) -> Result<bool> {
692        self.first().await.map(|n| n.is_none())
693    }
694
695    /// Test if this set contains a given name.
696    async fn contains(&self, name: &Vertex) -> Result<bool> {
697        let mut iter = self.iter().await?;
698        while let Some(item) = iter.next().await {
699            if &item? == name {
700                return Ok(true);
701            }
702        }
703        Ok(false)
704    }
705
706    /// Test contains in less than O(N) time.
707    /// Returns None if cannot achieve in less than O(N) time.
708    async fn contains_fast(&self, name: &Vertex) -> Result<Option<bool>> {
709        let _ = name;
710        Ok(None)
711    }
712
713    /// For downcasting.
714    fn as_any(&self) -> &dyn Any;
715
716    /// Get or set optimization hints.
717    fn hints(&self) -> &Hints;
718
719    /// Get an optional IdConvert interface to check hints.
720    fn id_convert(&self) -> Option<&dyn IdConvert> {
721        None
722    }
723
724    /// Specialized "reverse" implementation.
725    /// Returns `None` to use the general purpose reverse implementation.
726    fn specialized_reverse(&self) -> Option<Set> {
727        None
728    }
729
730    /// Specialized "take" implementation.
731    /// Returns `None` to use the general purpose implementation.
732    fn specialized_take(&self, n: u64) -> Option<Set> {
733        let _ = n;
734        None
735    }
736
737    /// Specialized "take" implementation.
738    /// Returns `None` to use the general purpose implementation.
739    fn specialized_skip(&self, n: u64) -> Option<Set> {
740        let _ = n;
741        None
742    }
743
744    /// Specialized "flatten_id" implementation.
745    fn specialized_flatten_id(&self) -> Option<Cow<IdStaticSet>> {
746        None
747    }
748}
749
750/// Sync version of `AsyncSetQuery`.
751pub trait SyncSetQuery {
752    /// Iterate through the set in defined order.
753    fn iter(&self) -> Result<Box<dyn NameIter>>;
754
755    /// Iterate through the set in the reversed order.
756    fn iter_rev(&self) -> Result<Box<dyn NameIter>>;
757
758    /// Number of names in this set.
759    fn count(&self) -> Result<u64>;
760
761    /// The first name in the set.
762    fn first(&self) -> Result<Option<Vertex>>;
763
764    /// The last name in the set.
765    fn last(&self) -> Result<Option<Vertex>>;
766
767    /// Test if this set is empty.
768    fn is_empty(&self) -> Result<bool>;
769
770    /// Test if this set contains a given name.
771    fn contains(&self, name: &Vertex) -> Result<bool>;
772
773    /// For downcasting.
774    fn as_any(&self) -> &dyn Any;
775
776    /// Get or set optimization hints.
777    fn hints(&self) -> &Hints;
778
779    /// Get an optional IdConvert interface to check hints.
780    fn id_convert(&self) -> Option<&dyn IdConvert>;
781}
782
783impl<T: AsyncSetQuery> SyncSetQuery for T {
784    fn iter(&self) -> Result<Box<dyn NameIter>> {
785        non_blocking(AsyncSetQuery::iter(self))?.map(to_iter)
786    }
787
788    fn iter_rev(&self) -> Result<Box<dyn NameIter>> {
789        non_blocking(AsyncSetQuery::iter_rev(self))?.map(to_iter)
790    }
791
792    fn count(&self) -> Result<u64> {
793        non_blocking(AsyncSetQuery::count_slow(self))?
794    }
795
796    fn first(&self) -> Result<Option<Vertex>> {
797        non_blocking(AsyncSetQuery::first(self))?
798    }
799
800    fn last(&self) -> Result<Option<Vertex>> {
801        non_blocking(AsyncSetQuery::last(self))?
802    }
803
804    fn is_empty(&self) -> Result<bool> {
805        non_blocking(AsyncSetQuery::is_empty(self))?
806    }
807
808    fn contains(&self, name: &Vertex) -> Result<bool> {
809        non_blocking(AsyncSetQuery::contains(self, name))?
810    }
811
812    fn as_any(&self) -> &dyn Any {
813        AsyncSetQuery::as_any(self)
814    }
815
816    fn hints(&self) -> &Hints {
817        AsyncSetQuery::hints(self)
818    }
819
820    fn id_convert(&self) -> Option<&dyn IdConvert> {
821        AsyncSetQuery::id_convert(self)
822    }
823}
824
825impl SyncSetQuery for Set {
826    fn iter(&self) -> Result<Box<dyn NameIter>> {
827        non_blocking(AsyncSetQuery::iter(self.0.deref()))?.map(to_iter)
828    }
829
830    fn iter_rev(&self) -> Result<Box<dyn NameIter>> {
831        non_blocking(AsyncSetQuery::iter_rev(self.0.deref()))?.map(to_iter)
832    }
833
834    fn count(&self) -> Result<u64> {
835        non_blocking(AsyncSetQuery::count_slow(self.0.deref()))?
836    }
837
838    fn first(&self) -> Result<Option<Vertex>> {
839        non_blocking(AsyncSetQuery::first(self.0.deref()))?
840    }
841
842    fn last(&self) -> Result<Option<Vertex>> {
843        non_blocking(AsyncSetQuery::last(self.0.deref()))?
844    }
845
846    fn is_empty(&self) -> Result<bool> {
847        non_blocking(AsyncSetQuery::is_empty(self.0.deref()))?
848    }
849
850    fn contains(&self, name: &Vertex) -> Result<bool> {
851        non_blocking(AsyncSetQuery::contains(self.0.deref(), name))?
852    }
853
854    fn as_any(&self) -> &dyn Any {
855        AsyncSetQuery::as_any(self.0.deref())
856    }
857
858    fn hints(&self) -> &Hints {
859        AsyncSetQuery::hints(self.0.deref())
860    }
861
862    fn id_convert(&self) -> Option<&dyn IdConvert> {
863        AsyncSetQuery::id_convert(self.0.deref())
864    }
865}
866
867/// Iterator of [`Set`].
868/// Types implementing this should consider replacing `iter_rev` with a fast
869/// path if possible.
870pub trait NameIter: Iterator<Item = Result<Vertex>> + Send {}
871impl<T> NameIter for T where T: Iterator<Item = Result<Vertex>> + Send {}
872
873/// Abstract async iterator that yields `Vertex`es.
874pub trait VertexStream: Stream<Item = Result<Vertex>> + Send {}
875impl<T> VertexStream for T where T: Stream<Item = Result<Vertex>> + Send {}
876
877/// Boxed async iterator that yields `Vertex`es.
878pub type BoxVertexStream = Pin<Box<dyn VertexStream>>;
879
880/// A wrapper that converts `VertexStream` to `NameIter`.
881struct NonblockingNameIter(BoxVertexStream);
882
883impl Iterator for NonblockingNameIter {
884    type Item = Result<Vertex>;
885
886    fn next(&mut self) -> Option<Self::Item> {
887        match non_blocking(self.0.next()) {
888            Err(e) => Some(Err(e.into())),
889            Ok(v) => v,
890        }
891    }
892}
893
894fn to_iter(stream: BoxVertexStream) -> Box<dyn NameIter> {
895    Box::new(NonblockingNameIter(stream))
896}
897
898impl From<Vertex> for Set {
899    fn from(name: Vertex) -> Set {
900        Set::from_static_names(std::iter::once(name))
901    }
902}
903
904impl From<&Vertex> for Set {
905    fn from(name: &Vertex) -> Set {
906        Set::from_static_names(std::iter::once(name.clone()))
907    }
908}
909
910/// Pick `left` if `order` is "greater or equal".
911/// Pick `right` otherwise.
912fn pick<T>(order: cmp::Ordering, left: T, right: T) -> T {
913    match order {
914        cmp::Ordering::Greater | cmp::Ordering::Equal => left,
915        cmp::Ordering::Less => right,
916    }
917}
918
919#[cfg(test)]
920pub(crate) mod tests {
921    use futures::TryStreamExt;
922    use nonblocking::non_blocking_result as r;
923
924    use super::*;
925    pub(crate) use crate::tests::dbg;
926    use crate::Id;
927
928    pub(crate) fn nb<F, R>(future: F) -> R
929    where
930        F: std::future::Future<Output = R>,
931    {
932        non_blocking(future).unwrap()
933    }
934
935    // Converts async Stream to Iterator.
936    pub(crate) fn ni<F>(future: F) -> Result<Box<dyn NameIter>>
937    where
938        F: std::future::Future<Output = Result<BoxVertexStream>>,
939    {
940        nb(future).map(to_iter)
941    }
942
943    // For easier testing.
944    impl From<&str> for Set {
945        fn from(name: &str) -> Set {
946            Set::from_static_names(
947                name.split_whitespace()
948                    .map(|n| Vertex::copy_from(n.as_bytes())),
949            )
950        }
951    }
952
953    impl Set {
954        pub(crate) fn assert_eq(&self, other: Set) {
955            assert!(
956                other.count().unwrap() == self.count().unwrap()
957                    && (other.clone() & self.clone()).count().unwrap() == self.count().unwrap(),
958                "set {:?} ({:?}) != {:?} ({:?})",
959                self,
960                self.iter().unwrap().map(|i| i.unwrap()).collect::<Vec<_>>(),
961                &other,
962                other
963                    .iter()
964                    .unwrap()
965                    .map(|i| i.unwrap())
966                    .collect::<Vec<_>>(),
967            );
968        }
969    }
970
971    type SizeHint = (u64, Option<u64>);
972
973    #[derive(Default, Debug)]
974    pub(crate) struct VecQuery(Vec<Vertex>, Hints, SizeHint);
975
976    #[async_trait::async_trait]
977    impl AsyncSetQuery for VecQuery {
978        async fn iter(&self) -> Result<BoxVertexStream> {
979            let iter = self.0.clone().into_iter().map(Ok);
980            Ok(Box::pin(futures::stream::iter(iter)))
981        }
982
983        fn as_any(&self) -> &dyn Any {
984            self
985        }
986
987        fn hints(&self) -> &Hints {
988            &self.1
989        }
990
991        async fn size_hint(&self) -> SizeHint {
992            self.2
993        }
994    }
995
996    impl VecQuery {
997        /// Quickly create [`VecQuery`] that contains `len(bytes)` items.
998        pub(crate) fn from_bytes(bytes: &[u8]) -> Self {
999            let mut used = [false; 256];
1000            let v: Vec<Vertex> = bytes
1001                .iter()
1002                .filter_map(|&b| {
1003                    if used[b as usize] {
1004                        None
1005                    } else {
1006                        used[b as usize] = true;
1007                        Some(to_name(b))
1008                    }
1009                })
1010                .collect();
1011            let size_hint: SizeHint = (v.len() as u64, Some(v.len() as u64));
1012            Self(v, Hints::default(), size_hint)
1013        }
1014
1015        /// Adjust the "size_hint" to test various logic.
1016        /// - "size_min" will be reduced by the 1st bit of `adjust` (0 to 1).
1017        /// - "size_max" will be increased by the 2nd bit  of `adjust` (0 to 1).
1018        /// - If `adjust` is greater than 3, the "size_max" will be set to `None`.
1019        pub(crate) fn adjust_size_hint(mut self, adjust: u64) -> Self {
1020            assert!(adjust <= 6);
1021            self.2.0 = self.2.0.saturating_sub(adjust & 0b1);
1022            self.2.1 = self.2.1.map(|v| v + ((adjust >> 1) & 0b1));
1023            if adjust >= 4 {
1024                self.2.1 = None;
1025            }
1026            self
1027        }
1028    }
1029
1030    /// Create a [`Vertex`] from `u8` by repeating them.
1031    pub(crate) fn to_name(value: u8) -> Vertex {
1032        Vertex::from(vec![value; 2])
1033    }
1034
1035    /// Shorten a [`Vertex`] result.
1036    pub(crate) fn shorten_name(name: Vertex) -> String {
1037        name.to_hex()[..2].to_string()
1038    }
1039
1040    /// Shorten a [`NameIter`] result.
1041    pub(crate) fn shorten_iter(iter: Result<Box<dyn NameIter>>) -> Vec<String> {
1042        iter.unwrap()
1043            .map(|v| shorten_name(v.unwrap()))
1044            .collect::<Vec<_>>()
1045    }
1046
1047    #[test]
1048    fn test_empty_query() -> Result<()> {
1049        let query = VecQuery::default();
1050        check_invariants(&query)?;
1051        assert_eq!(SyncSetQuery::iter(&query)?.count(), 0);
1052        assert_eq!(SyncSetQuery::iter_rev(&query)?.count(), 0);
1053        assert_eq!(SyncSetQuery::first(&query)?, None);
1054        assert_eq!(SyncSetQuery::last(&query)?, None);
1055        assert_eq!(SyncSetQuery::count(&query)?, 0);
1056        assert!(SyncSetQuery::is_empty(&query)?);
1057        assert!(!SyncSetQuery::contains(&query, &to_name(0))?);
1058        Ok(())
1059    }
1060
1061    #[test]
1062    fn test_vec_query() -> Result<()> {
1063        let query = VecQuery::from_bytes(b"\xab\xef\xcd");
1064        check_invariants(&query)?;
1065        assert_eq!(shorten_iter(SyncSetQuery::iter(&query)), ["ab", "ef", "cd"]);
1066        assert_eq!(
1067            shorten_iter(SyncSetQuery::iter_rev(&query)),
1068            ["cd", "ef", "ab"]
1069        );
1070        assert_eq!(shorten_name(SyncSetQuery::first(&query)?.unwrap()), "ab");
1071        assert_eq!(shorten_name(SyncSetQuery::last(&query)?.unwrap()), "cd");
1072        assert!(!SyncSetQuery::is_empty(&query)?);
1073        assert!(SyncSetQuery::contains(&query, &to_name(0xef))?);
1074        assert!(!SyncSetQuery::contains(&query, &to_name(0))?);
1075        Ok(())
1076    }
1077
1078    #[test]
1079    fn test_debug() {
1080        let set = Set::from_static_names(vec![to_name(2)])
1081            .union(&Set::from_static_names(vec![to_name(1)]))
1082            .difference(
1083                &Set::from_static_names(vec![to_name(3)])
1084                    .intersection(&Set::from_static_names(vec![to_name(2), to_name(3)])),
1085            );
1086        assert_eq!(
1087            dbg(&set),
1088            "<diff <or <static [0202]> <static [0101]>> <and <static [0303]> <static [0202, 0303]>>>"
1089        );
1090        assert_eq!(
1091            format!("\n{:#?}", &set),
1092            r#"
1093<diff
1094  <or
1095    <static [
1096        0202,
1097    ]>
1098    <static [
1099        0101,
1100    ]>>
1101  <and
1102    <static [
1103        0303,
1104    ]>
1105    <static [
1106        0202,
1107        0303,
1108    ]>>>"#
1109        );
1110    }
1111
1112    #[test]
1113    fn test_flatten() {
1114        let set = Set::from_static_names(vec![to_name(2)])
1115            .union(&Set::from_static_names(vec![to_name(1)]))
1116            .difference(
1117                &Set::from_static_names(vec![to_name(3)])
1118                    .intersection(&Set::from_static_names(vec![to_name(2), to_name(3)])),
1119            );
1120        assert_eq!(dbg(r(set.flatten()).unwrap()), "<static [0202, 0101]>");
1121    }
1122
1123    #[test]
1124    fn test_union_zip() {
1125        let set1 = Set::from_static_names(vec![to_name(1), to_name(2), to_name(3), to_name(4)]);
1126        let set2 = Set::from_static_names(vec![to_name(5), to_name(6)]);
1127        let unioned = set1.union_zip(&set2);
1128        let names = unioned.iter().unwrap().collect::<Result<Vec<_>>>().unwrap();
1129        assert_eq!(dbg(names), "[0101, 0505, 0202, 0606, 0303, 0404]");
1130    }
1131
1132    #[test]
1133    fn test_ops() {
1134        let ab: Set = "a b".into();
1135        let bc: Set = "b c".into();
1136        let s = |set: Set| -> Vec<String> { shorten_iter(set.iter()) };
1137        assert_eq!(s(ab.clone() | bc.clone()), ["61", "62", "63"]);
1138        assert_eq!(s(ab.clone() & bc.clone()), ["62"]);
1139        assert_eq!(s(ab - bc), ["61"]);
1140    }
1141
1142    #[test]
1143    fn test_skip_take_slow_path() {
1144        let s: Set = "a b c d".into();
1145        let d = |set: Set| -> String { dbg(r(set.flatten_names()).unwrap()) };
1146        assert_eq!(d(s.take(2)), "<static [a, b]>");
1147        assert_eq!(d(s.skip(2)), "<static [c, d]>");
1148        assert_eq!(d(s.skip(1).take(2)), "<static [b, c]>");
1149    }
1150
1151    #[test]
1152    fn test_hints_empty_full_fast_paths() {
1153        let partial: Set = "a".into();
1154        partial.hints().add_flags(Flags::ID_ASC);
1155        let empty: Set = "".into();
1156        let full: Set = "f".into();
1157        full.hints().add_flags(Flags::FULL | Flags::ID_DESC);
1158
1159        assert_eq!(
1160            hints_ops(&partial, &empty),
1161            [
1162                "- Hints(Flags(ID_ASC))",
1163                "  Hints(Flags(EMPTY | ID_DESC | ID_ASC | TOPO_DESC | ANCESTORS))",
1164                "& Hints(Flags(EMPTY | ID_DESC | ID_ASC | TOPO_DESC | ANCESTORS))",
1165                "  Hints(Flags(EMPTY | ID_DESC | ID_ASC | TOPO_DESC | ANCESTORS))",
1166                "| Hints(Flags(ID_ASC))",
1167                "  Hints(Flags(ID_ASC))"
1168            ]
1169        );
1170        // Fast paths are not used for "|" because there is no dag associated.
1171        assert_eq!(
1172            hints_ops(&partial, &full),
1173            [
1174                "- Hints(Flags(ID_ASC))",
1175                "  Hints(Flags(ID_DESC))",
1176                "& Hints(Flags(ID_ASC))",
1177                "  Hints(Flags(ID_ASC))",
1178                "| Hints(Flags(0x0))",
1179                "  Hints(Flags(0x0))"
1180            ]
1181        );
1182        assert_eq!(
1183            hints_ops(&empty, &full),
1184            [
1185                "- Hints(Flags(EMPTY | ID_DESC | ID_ASC | TOPO_DESC | ANCESTORS))",
1186                "  Hints(Flags(FULL | ID_DESC | ANCESTORS))",
1187                "& Hints(Flags(EMPTY | ID_DESC | ID_ASC | TOPO_DESC | ANCESTORS))",
1188                "  Hints(Flags(EMPTY | ID_DESC | ID_ASC | TOPO_DESC | ANCESTORS))",
1189                "| Hints(Flags(FULL | ID_DESC | ANCESTORS))",
1190                "  Hints(Flags(FULL | ID_DESC | ANCESTORS))"
1191            ]
1192        );
1193    }
1194
1195    #[test]
1196    fn test_hints_full_subset() {
1197        let mut t = crate::tests::TestDag::new();
1198        let a = r(t.dag.all()).unwrap(); // [] FULL EMPTY
1199        t.drawdag("X", &[]);
1200        let b = r(t.dag.all()).unwrap(); // [X] FULL
1201        t.drawdag("X--Y--Z", &[]);
1202        let c = r(t.dag.all()).unwrap(); // [X Y Z] FULL
1203        let d = r(t.dag.heads(r(t.dag.all()).unwrap())).unwrap(); // [Z]
1204
1205        let a = move || a.clone();
1206        let b = move || b.clone();
1207        let c = move || c.clone();
1208        let d = move || d.clone();
1209        let f = |set: Set| {
1210            let s = dbg(&set);
1211            let v = set
1212                .iter()
1213                .unwrap()
1214                .map(|i| String::from_utf8(i.unwrap().as_ref().to_vec()).unwrap())
1215                .collect::<Vec<String>>()
1216                .join(" ");
1217            format!("{} = [{}]", s, v)
1218        };
1219
1220        assert_eq!(f(a()), "<spans []> = []");
1221        assert_eq!(f(b()), "<spans [X+N0]> = [X]");
1222        assert_eq!(f(c()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1223        assert_eq!(f(d()), "<spans [Z+N2]> = [Z]");
1224
1225        assert_eq!(f(a() - c()), "<empty> = []");
1226        assert_eq!(f(a() - d()), "<spans []> = []");
1227        assert_eq!(f(b() - c()), "<empty> = []");
1228        assert_eq!(f(b() - d()), "<spans [X+N0]> = [X]");
1229        assert_eq!(f(c() - b()), "<spans [Y:Z+N1:N2]> = [Z Y]");
1230        assert_eq!(f(c() - a()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1231        assert_eq!(f(c() - d()), "<spans [X:Y+N0:N1]> = [Y X]");
1232        assert_eq!(f(d() - a()), "<spans [Z+N2]> = [Z]");
1233        assert_eq!(f(d() - b()), "<spans [Z+N2]> = [Z]");
1234        assert_eq!(f(d() - c()), "<empty> = []");
1235
1236        assert_eq!(f(a() | c()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1237        assert_eq!(f(a() | b()), "<spans [X+N0]> = [X]");
1238        assert_eq!(f(a() | d()), "<spans [Z+N2]> = [Z]");
1239        assert_eq!(f(b() | a()), "<spans [X+N0]> = [X]");
1240        assert_eq!(f(b() | c()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1241        assert_eq!(f(b() | d()), "<spans [Z+N2, X+N0]> = [Z X]");
1242        assert_eq!(f(c() | a()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1243        assert_eq!(f(c() | b()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1244        assert_eq!(f(c() | d()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1245        assert_eq!(f(d() | a()), "<spans [Z+N2]> = [Z]");
1246        assert_eq!(f(d() | b()), "<spans [Z+N2, X+N0]> = [Z X]");
1247        assert_eq!(f(d() | c()), "<spans [X:Z+N0:N2]> = [Z Y X]");
1248
1249        assert_eq!(f(a() & c()), "<spans []> = []");
1250        assert_eq!(f(a() & d()), "<empty> = []");
1251        assert_eq!(f(b() & c()), "<spans [X+N0]> = [X]");
1252        assert_eq!(f(c() & a()), "<spans []> = []");
1253        assert_eq!(f(c() & b()), "<spans [X+N0]> = [X]");
1254        assert_eq!(f(c() & d()), "<spans [Z+N2]> = [Z]");
1255        assert_eq!(f(d() & a()), "<empty> = []");
1256        assert_eq!(f(d() & b()), "<spans []> = []");
1257        assert_eq!(f(d() & c()), "<spans [Z+N2]> = [Z]");
1258    }
1259
1260    #[test]
1261    fn test_hints_min_max_id() {
1262        let bc: Set = "b c".into();
1263        bc.hints().set_min_id(Id(20));
1264        bc.hints().add_flags(Flags::ID_DESC);
1265
1266        let ad: Set = "a d".into();
1267        ad.hints().set_max_id(Id(40));
1268        ad.hints().add_flags(Flags::ID_ASC);
1269
1270        assert_eq!(
1271            hints_ops(&bc, &ad),
1272            [
1273                "- Hints(Flags(ID_DESC), 20..)",
1274                "  Hints(Flags(ID_ASC), ..=40)",
1275                "& Hints(Flags(ID_DESC), 20..=40)",
1276                "  Hints(Flags(ID_ASC), 20..=40)",
1277                "| Hints(Flags(0x0))",
1278                "  Hints(Flags(0x0))"
1279            ]
1280        );
1281
1282        ad.hints().set_min_id(Id(10));
1283        bc.hints().set_max_id(Id(30));
1284        assert_eq!(
1285            hints_ops(&bc, &ad),
1286            [
1287                "- Hints(Flags(ID_DESC), 20..=30)",
1288                "  Hints(Flags(ID_ASC), 10..=40)",
1289                "& Hints(Flags(ID_DESC), 20..=30)",
1290                "  Hints(Flags(ID_ASC), 20..=30)",
1291                "| Hints(Flags(0x0))",
1292                "  Hints(Flags(0x0))"
1293            ]
1294        );
1295    }
1296
1297    #[test]
1298    fn test_hints_ancestors() {
1299        let a: Set = "a".into();
1300        a.hints().add_flags(Flags::ANCESTORS);
1301
1302        let b: Set = "b".into();
1303        assert_eq!(
1304            hints_ops(&a, &b),
1305            [
1306                "- Hints(Flags(0x0))",
1307                "  Hints(Flags(0x0))",
1308                "& Hints(Flags(0x0))",
1309                "  Hints(Flags(0x0))",
1310                "| Hints(Flags(0x0))",
1311                "  Hints(Flags(0x0))"
1312            ]
1313        );
1314
1315        b.hints().add_flags(Flags::ANCESTORS);
1316        assert_eq!(
1317            hints_ops(&a, &b),
1318            [
1319                "- Hints(Flags(0x0))",
1320                "  Hints(Flags(0x0))",
1321                "& Hints(Flags(ANCESTORS))",
1322                "  Hints(Flags(ANCESTORS))",
1323                "| Hints(Flags(ANCESTORS))",
1324                "  Hints(Flags(ANCESTORS))"
1325            ]
1326        );
1327    }
1328
1329    #[test]
1330    fn test_filter() {
1331        id_static::tests::with_dag(|dag| {
1332            let sets: Vec<Set> = vec!["C B A".into(), nb(dag.ancestors("C".into())).unwrap()];
1333            for abc in sets {
1334                let filter: Set = abc.filter(Box::new(|v: &Vertex| {
1335                    Box::pin(async move { Ok(v.as_ref() != b"A") })
1336                }));
1337                check_invariants(filter.0.as_ref()).unwrap();
1338                assert_eq!(abc.hints().dag_version(), filter.hints().dag_version());
1339                assert_eq!(
1340                    abc.hints().id_map_version(),
1341                    filter.hints().id_map_version()
1342                );
1343                assert!(filter.hints().flags().contains(Flags::FILTER));
1344                assert!(!filter.hints().flags().contains(Flags::ANCESTORS));
1345                assert_eq!(dbg(r(filter.flatten_names())), "Ok(<static [C, B]>)");
1346            }
1347        })
1348    }
1349
1350    #[test]
1351    fn test_reverse() {
1352        let ab: Set = "a b".into();
1353        let ba = ab.reverse();
1354        check_invariants(&*ba).unwrap();
1355        let names = ba.iter().unwrap().collect::<Result<Vec<_>>>().unwrap();
1356        assert_eq!(dbg(names), "[b, a]");
1357    }
1358
1359    // Print hints for &, |, - operations.
1360    fn hints_ops(lhs: &Set, rhs: &Set) -> Vec<String> {
1361        vec![
1362            (lhs.clone() - rhs.clone(), rhs.clone() - lhs.clone()),
1363            (lhs.clone() & rhs.clone(), rhs.clone() & lhs.clone()),
1364            (lhs.clone() | rhs.clone(), rhs.clone() | lhs.clone()),
1365        ]
1366        .into_iter()
1367        .zip("-&|".chars())
1368        .flat_map(|((set1, set2), ch)| {
1369            vec![
1370                format!("{} {:?}", ch, set1.hints()),
1371                format!("  {:?}", set2.hints()),
1372            ]
1373        })
1374        .collect()
1375    }
1376
1377    /// Check consistency of a `AsyncSetQuery`, such as `iter().nth(0)` matches
1378    /// `first()` etc.
1379    pub(crate) fn check_invariants(query: &dyn AsyncSetQuery) -> Result<()> {
1380        // Collect contains_fast result before calling other functions which might
1381        // change the internal set state.
1382        let contains_fast_vec: Vec<Option<bool>> = (0..=0xff)
1383            .map(|b| {
1384                let name = Vertex::from(vec![b; 20]);
1385                nb(query.contains_fast(&name)).unwrap_or(None)
1386            })
1387            .collect();
1388        let is_empty = nb(query.is_empty())?;
1389        let count = nb(query.count_slow())?;
1390        let (size_hint_min, size_hint_max) = nb(query.size_hint());
1391        let first = nb(query.first())?;
1392        let last = nb(query.last())?;
1393        let names: Vec<Vertex> = ni(query.iter())?.collect::<Result<Vec<_>>>()?;
1394        assert_eq!(
1395            first,
1396            names.first().cloned(),
1397            "first() should match iter().first() (set: {:?})",
1398            &query
1399        );
1400        assert_eq!(
1401            last,
1402            names.last().cloned(),
1403            "last() should match iter().last() (set: {:?})",
1404            &query
1405        );
1406        assert_eq!(
1407            count,
1408            names.len() as u64,
1409            "count() should match iter().count() (set: {:?})",
1410            &query
1411        );
1412        assert!(
1413            size_hint_min <= count,
1414            "size_hint().0 ({}) must <= count ({}) (set: {:?})",
1415            size_hint_min,
1416            count,
1417            &query
1418        );
1419        if let Some(size_hint_max) = size_hint_max {
1420            assert!(
1421                size_hint_max >= count,
1422                "size_hint().1 ({}) must >= count ({}) (set: {:?})",
1423                size_hint_max,
1424                count,
1425                &query
1426            );
1427        }
1428        assert_eq!(
1429            is_empty,
1430            count == 0,
1431            "is_empty() should match count() == 0 (set: {:?})",
1432            &query
1433        );
1434        assert!(
1435            names
1436                .iter()
1437                .all(|name| nb(query.contains(name)).ok() == Some(true)),
1438            "contains() should return true for names returned by iter() (set: {:?})",
1439            &query
1440        );
1441        assert!(
1442            names
1443                .iter()
1444                .all(|name| nb(query.contains_fast(name)).unwrap_or(None) != Some(false)),
1445            "contains_fast() should not return false for names returned by iter() (set: {:?})",
1446            &query
1447        );
1448        assert!(
1449            (0..=0xff).all(|b| {
1450                let name = Vertex::from(vec![b; 20]);
1451                nb(query.contains(&name)).ok() == Some(names.contains(&name))
1452            }),
1453            "contains() should return false for names not returned by iter() (set: {:?})",
1454            &query
1455        );
1456        assert!(
1457            (0..=0xff)
1458                .zip(contains_fast_vec.into_iter())
1459                .all(|(b, old_contains)| {
1460                    let name = Vertex::from(vec![b; 20]);
1461                    let contains = nb(query.contains_fast(&name)).unwrap_or(None);
1462                    old_contains.is_none() || contains == old_contains
1463                }),
1464            "contains_fast() should be consistent (set: {:?})",
1465            &query
1466        );
1467        assert!(
1468            (0..=0xff).all(|b| {
1469                let name = Vertex::from(vec![b; 20]);
1470                let contains = nb(query.contains_fast(&name)).unwrap_or(None);
1471                contains.is_none() || contains == Some(names.contains(&name))
1472            }),
1473            "contains_fast() should not return true for names not returned by iter() (set: {:?})",
1474            &query
1475        );
1476        if let Some(flatten_id) = query.specialized_flatten_id() {
1477            let iter = r(AsyncSetQuery::iter(&*flatten_id))?;
1478            let mut flatten_names = r(iter.try_collect::<Vec<_>>())?;
1479            flatten_names.sort_unstable();
1480            let mut sorted_names = names.clone();
1481            sorted_names.sort_unstable();
1482            assert_eq!(
1483                &sorted_names, &flatten_names,
1484                "specialized_flatten_id() should return a same set, order could be different (set: {:?})",
1485                &query
1486            );
1487        }
1488        let reversed: Vec<Vertex> = ni(query.iter_rev())?.collect::<Result<Vec<_>>>()?;
1489        if let Some(reversed_set) = query.specialized_reverse() {
1490            let iter = reversed_set.iter()?;
1491            let names = iter.collect::<Result<Vec<_>>>()?;
1492            assert_eq!(&names, &reversed);
1493        }
1494        assert_eq!(
1495            names,
1496            reversed.into_iter().rev().collect::<Vec<Vertex>>(),
1497            "iter() should match iter_rev().rev() (set: {:?})",
1498            &query
1499        );
1500        Ok(())
1501    }
1502
1503    /// Generate 2 sets in a loop to test container set (intersection, union, difference) types.
1504    /// Focus on extra "size_hint" test.
1505    pub(crate) fn check_size_hint_sets<Q: AsyncSetQuery>(build_set: impl Fn(Set, Set) -> Q) {
1506        let lhs = b"\x11\x22\x33";
1507        let rhs = b"\x33\x55\x77";
1508        for lhs_start in 0..lhs.len() {
1509            for lhs_end in lhs_start..lhs.len() {
1510                for rhs_start in 0..rhs.len() {
1511                    for rhs_end in rhs_start..rhs.len() {
1512                        for lhs_size_hint_adjust in 0..7 {
1513                            for rhs_size_hint_adjust in 0..7 {
1514                                let lhs_set = VecQuery::from_bytes(&lhs[lhs_start..lhs_end])
1515                                    .adjust_size_hint(lhs_size_hint_adjust);
1516                                let rhs_set = VecQuery::from_bytes(&rhs[rhs_start..rhs_end])
1517                                    .adjust_size_hint(rhs_size_hint_adjust);
1518                                let set =
1519                                    build_set(Set::from_query(lhs_set), Set::from_query(rhs_set));
1520                                check_invariants(&set).unwrap();
1521                            }
1522                        }
1523                    }
1524                }
1525            }
1526        }
1527    }
1528
1529    pub(crate) fn check_skip_take_reverse(set: Set) -> Result<()> {
1530        let names: Vec<Vertex> = set.iter()?.collect::<Result<Vec<_>>>()?;
1531        let len = names.len();
1532        for reverse in [false, true] {
1533            for skip in 0..=(len + 2) {
1534                for take in 0..=(len + 2) {
1535                    for skip_first in [false, true] {
1536                        let mut test_set = set.clone();
1537                        let mut expected_names = names.clone();
1538                        if reverse {
1539                            test_set = test_set.reverse();
1540                            expected_names.reverse();
1541                        }
1542                        if skip_first {
1543                            test_set = test_set.skip(skip as _).take(take as _);
1544                            expected_names =
1545                                expected_names.into_iter().skip(skip).take(take).collect();
1546                        } else {
1547                            test_set = test_set.take(take as _).skip(skip as _);
1548                            expected_names =
1549                                expected_names.into_iter().take(take).skip(skip).collect();
1550                        }
1551                        let actual_names = test_set.iter()?.collect::<Result<Vec<_>>>()?;
1552                        assert_eq!(
1553                            actual_names, expected_names,
1554                            "check_skip_take_reverse {:?} failed at reverse={reverse} skip={skip} take={take}",
1555                            &set
1556                        );
1557                    }
1558                }
1559            }
1560        }
1561        Ok(())
1562    }
1563
1564    pub(crate) fn fmt_iter(set: &Set) -> String {
1565        let iter = r(AsyncSetQuery::iter(set.deref())).unwrap();
1566        let names = r(iter.try_collect::<Vec<_>>()).unwrap();
1567        dbg(names)
1568    }
1569}