swh_graph/
arc_iterators.rs

1// Copyright (C) 2023-2024  The Software Heritage developers
2// See the AUTHORS file at the top-level directory of this distribution
3// License: GNU General Public License version 3, or any later version
4// See top-level LICENSE file for more information
5
6//! Structures to manipulate the Software Heritage graph
7//!
8//! In order to load only what is necessary, these structures are initially created
9//! by calling [`SwhUnidirectionalGraph::new`](crate::graph::SwhUnidirectionalGraph::new) or
10//! [`SwhBidirectionalGraph::new`](crate::graph::SwhBidirectionalGraph::new), then calling methods
11//! on them to progressively load additional data (`load_properties`, `load_all_properties`,
12//! `load_labels`)
13
14#![allow(clippy::type_complexity)]
15
16use std::borrow::Borrow;
17use std::iter::Iterator;
18
19use webgraph::prelude::*;
20
21use crate::graph::{NodeId, SwhGraphWithProperties};
22use crate::labels::{EdgeLabel, UntypedEdgeLabel};
23
24pub trait IntoFlattenedLabeledArcsIterator<Label> {
25    type Flattened: IntoIterator<Item = (NodeId, Label)>;
26
27    /// Turns this `Iterator<Item=(succ, Iterator<Item=labels>)>` into an
28    /// `Iterator<ITem=(succ, label)>`.
29    fn flatten_labels(self) -> Self::Flattened;
30}
31
32pub struct LabeledSuccessorIterator<Successors: Iterator>
33where
34    <Successors as Iterator>::Item: Pair<Left = usize, Right: IntoIterator<Item: Borrow<u64>>>,
35{
36    pub(crate) successors: Successors,
37}
38
39impl<Successors: Iterator> LabeledSuccessorIterator<Successors>
40where
41    <Successors as Iterator>::Item: Pair<Left = usize, Right: IntoIterator<Item: Borrow<u64>>>,
42{
43    pub fn new(successors: Successors) -> Self {
44        LabeledSuccessorIterator { successors }
45    }
46}
47
48impl<Successors: Iterator> Iterator for LabeledSuccessorIterator<Successors>
49where
50    <Successors as Iterator>::Item: Pair<Left = usize, Right: IntoIterator<Item: Borrow<u64>>>,
51{
52    type Item = (
53        NodeId,
54        LabeledArcIterator<
55            <<<Successors as Iterator>::Item as Pair>::Right as IntoIterator>::IntoIter,
56        >,
57    );
58
59    fn next(&mut self) -> Option<Self::Item> {
60        self.successors.next().map(|pair| {
61            let (successor, arc_labels) = pair.into_pair();
62            (
63                successor,
64                LabeledArcIterator {
65                    arc_label_ids: arc_labels.into_iter(),
66                },
67            )
68        })
69    }
70}
71
72impl<Successors: Iterator> IntoFlattenedLabeledArcsIterator<UntypedEdgeLabel>
73    for LabeledSuccessorIterator<Successors>
74where
75    <Successors as Iterator>::Item: Pair<Left = usize, Right: IntoIterator<Item: Borrow<u64>>>,
76{
77    type Flattened = FlattenedSuccessorsIterator<Self>;
78
79    fn flatten_labels(self) -> Self::Flattened {
80        FlattenedSuccessorsIterator::new(self)
81    }
82}
83
84pub struct FlattenedSuccessorsIterator<Successors: Iterator>
85where
86    <Successors as Iterator>::Item: Pair<Left = usize, Right: IntoIterator>,
87{
88    current_node_and_labels: Option<(
89        NodeId,
90        <<<Successors as Iterator>::Item as Pair>::Right as IntoIterator>::IntoIter,
91    )>,
92    iter: Successors,
93}
94
95impl<Successors: Iterator> FlattenedSuccessorsIterator<Successors>
96where
97    <Successors as Iterator>::Item: Pair<Left = usize, Right: IntoIterator>,
98{
99    pub fn new(successors: Successors) -> Self {
100        Self {
101            current_node_and_labels: None,
102            iter: successors,
103        }
104    }
105}
106
107impl<Successors: Iterator> Iterator for FlattenedSuccessorsIterator<Successors>
108where
109    <Successors as Iterator>::Item: Pair<Left = usize, Right: IntoIterator>,
110{
111    type Item = (
112        NodeId,
113        <<<Successors as Iterator>::Item as Pair>::Right as IntoIterator>::Item,
114    );
115
116    fn next(&mut self) -> Option<Self::Item> {
117        if self.current_node_and_labels.is_none() {
118            // first iterator, or exhausted current label list, move to the next one
119            self.current_node_and_labels = self
120                .iter
121                .next()
122                .map(Pair::into_pair)
123                .map(|(succ, labels)| (succ, labels.into_iter()))
124        }
125        let Some((current_node, ref mut current_labels)) = self.current_node_and_labels else {
126            // Reached the end of the iterator
127            return None;
128        };
129        match current_labels.next() {
130            Some(label) => Some((current_node, label)),
131            None => {
132                // exhausted this label list, move to the next one
133                self.current_node_and_labels = None;
134                self.next()
135            }
136        }
137    }
138}
139
140pub struct LabeledArcIterator<T: Iterator>
141where
142    <T as Iterator>::Item: Borrow<u64>,
143{
144    arc_label_ids: T,
145}
146
147impl<T: Iterator> Iterator for LabeledArcIterator<T>
148where
149    <T as Iterator>::Item: Borrow<u64>,
150{
151    type Item = UntypedEdgeLabel;
152
153    fn next(&mut self) -> Option<Self::Item> {
154        self.arc_label_ids
155            .next()
156            .map(|label| UntypedEdgeLabel::from(*label.borrow()))
157    }
158}
159
160pub struct LabelTypingSuccessorIterator<'a, G, Successors: Iterator>
161where
162    <Successors as Iterator>::Item:
163        Pair<Left = usize, Right: IntoIterator<Item = UntypedEdgeLabel>>,
164    G: SwhGraphWithProperties,
165    <G as SwhGraphWithProperties>::Maps: crate::properties::Maps,
166{
167    pub(crate) graph: &'a G,
168    pub(crate) is_transposed: bool,
169    pub(crate) successors: Successors,
170    pub(crate) src: NodeId,
171}
172
173impl<'a, G, Successors: Iterator> Iterator for LabelTypingSuccessorIterator<'a, G, Successors>
174where
175    <Successors as Iterator>::Item:
176        Pair<Left = usize, Right: IntoIterator<Item = UntypedEdgeLabel>>,
177    G: SwhGraphWithProperties,
178    <G as SwhGraphWithProperties>::Maps: crate::properties::Maps,
179{
180    type Item = (
181        NodeId,
182        LabelTypingArcIterator<
183            'a,
184            G,
185            <<<Successors as Iterator>::Item as Pair>::Right as IntoIterator>::IntoIter,
186        >,
187    );
188
189    fn next(&mut self) -> Option<Self::Item> {
190        self.successors.next().map(|pair| {
191            let mut src = self.src;
192            let (mut dst, labels) = pair.into_pair();
193            let succ = dst;
194            if self.is_transposed {
195                (src, dst) = (dst, src)
196            }
197            (
198                succ,
199                LabelTypingArcIterator {
200                    graph: self.graph,
201                    labels: labels.into_iter(),
202                    src,
203                    dst,
204                },
205            )
206        })
207    }
208}
209
210impl<G, Successors: Iterator> IntoFlattenedLabeledArcsIterator<EdgeLabel>
211    for LabelTypingSuccessorIterator<'_, G, Successors>
212where
213    <Successors as Iterator>::Item:
214        Pair<Left = usize, Right: IntoIterator<Item = UntypedEdgeLabel>>,
215    G: SwhGraphWithProperties,
216    <G as SwhGraphWithProperties>::Maps: crate::properties::Maps,
217{
218    type Flattened = FlattenedSuccessorsIterator<Self>;
219
220    fn flatten_labels(self) -> Self::Flattened {
221        FlattenedSuccessorsIterator::new(self)
222    }
223}
224
225pub struct LabelTypingArcIterator<'a, G, Labels: Iterator<Item = UntypedEdgeLabel>>
226where
227    G: SwhGraphWithProperties,
228    <G as SwhGraphWithProperties>::Maps: crate::properties::Maps,
229{
230    graph: &'a G,
231    labels: Labels,
232    src: NodeId,
233    dst: NodeId,
234}
235
236impl<G, Labels: Iterator<Item = UntypedEdgeLabel>> Iterator
237    for LabelTypingArcIterator<'_, G, Labels>
238where
239    G: SwhGraphWithProperties,
240    <G as SwhGraphWithProperties>::Maps: crate::properties::Maps,
241{
242    type Item = EdgeLabel;
243
244    fn next(&mut self) -> Option<Self::Item> {
245        let props = self.graph.properties();
246        self.labels.next().map(move |label| {
247            label
248                .for_edge_type(
249                    props.node_type(self.src),
250                    props.node_type(self.dst),
251                    self.graph.is_transposed(),
252                )
253                .unwrap_or_else(|e| {
254                    panic!(
255                        "Unexpected edge from {} ({}) to {} ({}): {}",
256                        props.swhid(self.src),
257                        self.src,
258                        props.swhid(self.dst),
259                        self.dst,
260                        e
261                    )
262                })
263        })
264    }
265}
266
267/// Wraps an iterator of labeled successors, and yields only the successors
268pub struct DelabelingIterator<Successors: Iterator>
269where
270    <Successors as Iterator>::Item: Pair<Left = usize>,
271{
272    pub(crate) successors: Successors,
273}
274impl<Successors: Iterator> Iterator for DelabelingIterator<Successors>
275where
276    <Successors as Iterator>::Item: Pair<Left = usize>,
277{
278    type Item = NodeId;
279
280    fn next(&mut self) -> Option<Self::Item> {
281        self.successors.next().map(|pair| {
282            let (successor, _arc_labels) = pair.into_pair();
283            successor
284        })
285    }
286}