arch_pkg_db/multi/
providers.rs

1use super::{MultiQueryDatabase, WithVersion};
2use crate::{
3    multi::{Entries, EntriesMut, MultiQuerier, MultiQueriers, MultiQueriersMut},
4    value::RepositoryName,
5};
6use arch_pkg_text::{
7    desc::{Query, QueryMut},
8    value::DependencyName,
9};
10use core::iter::FusedIterator;
11
12/// [Iterator] over all immutable queriers of packages which list a certain [`DependencyName`] in their
13/// [`provides`](Query::provides) array.
14///
15/// This iterator is created by calling [`MultiQueryDatabase::alternative_providers`].
16#[derive(Debug, Clone)]
17pub struct AlternativeProviders<'r, 'query, 'name, Querier> {
18    target: DependencyName<'name>,
19    current: Option<Entries<'r, 'query, Querier>>, // always filled if queriers is filled
20    queriers: MultiQueriers<'r, 'query, Querier>,
21}
22
23impl<'r, 'query, 'name, Querier> AlternativeProviders<'r, 'query, 'name, Querier> {
24    /// Create the struct in such a way to ensure invariant.
25    fn new(target: DependencyName<'name>, queriers: MultiQueriers<'r, 'query, Querier>) -> Self {
26        let mut result = AlternativeProviders {
27            target,
28            current: None,
29            queriers,
30        };
31        result.change_querier();
32        result
33    }
34
35    /// Extract an element from [`Self::queriers`] into [`Self::current`].
36    fn change_querier(&mut self) {
37        self.current = self.queriers.next().map(MultiQuerier::entries);
38    }
39}
40
41impl<'r, 'query, 'name, Querier: Query<'r>> Iterator
42    for AlternativeProviders<'r, 'query, 'name, Querier>
43{
44    type Item = (RepositoryName<'query>, &'r WithVersion<'query, Querier>);
45    fn next(&mut self) -> Option<Self::Item> {
46        loop {
47            if cfg!(debug_assertions) && self.current.is_none() && self.queriers.next().is_some() {
48                panic!("Invariant violated! `current` was emptied before `queriers`");
49            }
50
51            for (repository, querier) in self.current.as_mut()? {
52                let found = querier
53                    .provides()
54                    .into_iter()
55                    .flatten()
56                    .map(|provide| provide.components())
57                    .any(|(name, _)| name == self.target);
58                if found {
59                    return Some((repository, querier));
60                }
61            }
62
63            self.change_querier();
64        }
65    }
66}
67
68impl<'r, 'query, 'name, Querier: Query<'r>> FusedIterator
69    for AlternativeProviders<'r, 'query, 'name, Querier>
70{
71}
72
73/// [Iterator] over all mutable queriers of packages which list a certain [`DependencyName`] in their
74/// [`provides`](QueryMut::provides_mut) array.
75///
76/// This iterator is created by calling [`MultiQueryDatabase::alternative_providers_mut`].
77#[derive(Debug)]
78pub struct AlternativeProvidersMut<'r, 'query, 'name, Querier> {
79    target: DependencyName<'name>,
80    current: Option<EntriesMut<'r, 'query, Querier>>, // always filled if queriers is filled
81    queriers: MultiQueriersMut<'r, 'query, Querier>,
82}
83
84impl<'r, 'query, 'name, Querier> AlternativeProvidersMut<'r, 'query, 'name, Querier> {
85    /// Create the struct in such a way to ensure invariant.
86    fn new(target: DependencyName<'name>, queriers: MultiQueriersMut<'r, 'query, Querier>) -> Self {
87        let mut result = AlternativeProvidersMut {
88            target,
89            current: None,
90            queriers,
91        };
92        result.change_querier();
93        result
94    }
95
96    /// Extract an element from [`Self::queriers`] into [`Self::current`].
97    fn change_querier(&mut self) {
98        self.current = self.queriers.next().map(MultiQuerier::entries_mut);
99    }
100}
101
102impl<'r, 'query, 'name, Querier: QueryMut<'r>> Iterator
103    for AlternativeProvidersMut<'r, 'query, 'name, Querier>
104{
105    type Item = (RepositoryName<'query>, &'r mut WithVersion<'query, Querier>);
106    fn next(&mut self) -> Option<Self::Item> {
107        loop {
108            if cfg!(debug_assertions) && self.current.is_none() && self.queriers.next().is_some() {
109                panic!("Invariant violated! `current` was emptied before `queriers`");
110            }
111
112            for (repository, querier) in self.current.as_mut()? {
113                let found = querier
114                    .provides_mut()
115                    .into_iter()
116                    .flatten()
117                    .map(|provide| provide.components())
118                    .any(|(name, _)| name == self.target);
119                if found {
120                    return Some((repository, querier));
121                }
122            }
123
124            self.change_querier();
125        }
126    }
127}
128
129impl<'r, 'query, 'name, Querier: QueryMut<'r>> FusedIterator
130    for AlternativeProvidersMut<'r, 'query, 'name, Querier>
131{
132}
133
134impl<'query, Querier> MultiQueryDatabase<'query, Querier> {
135    /// Get an iterator over all immutable queriers of packages which list a certain [`DependencyName`] in their
136    /// [`provides`](Query::provides) array.
137    ///
138    /// This method is prefixed with "alternative" because a package doesn't usually list itself in its own `provides`,
139    /// and consequently, would usually be excluded from this iterator. Beware that if it does list itself, its own
140    /// name would be included.
141    pub fn alternative_providers<'r, 'name>(
142        &'r self,
143        target: DependencyName<'name>,
144    ) -> AlternativeProviders<'r, 'query, 'name, Querier> {
145        AlternativeProviders::new(target, self.queriers())
146    }
147
148    /// Get an iterator over all mutable queriers of packages which list a certain [`DependencyName`] in their
149    /// [`provides`](QueryMut::provides_mut) array.
150    ///
151    /// This method is prefixed with "alternative" because a package doesn't usually list itself in its own `provides`,
152    /// and consequently, would usually be excluded from this iterator. Beware that if it does list itself, its own
153    /// name would be included.
154    pub fn alternative_providers_mut<'r, 'name>(
155        &'r mut self,
156        target: DependencyName<'name>,
157    ) -> AlternativeProvidersMut<'r, 'query, 'name, Querier> {
158        AlternativeProvidersMut::new(target, self.queriers_mut())
159    }
160}