• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vigna / webgraph-rs / 28829100046

06 Jul 2026 11:00PM UTC coverage: 72.759% (+3.5%) from 69.212%
28829100046

Pull #171

github

zommiommy
test: guard mmap-dependent new tests from Miri

The default and explicit LoadMmap load paths mprotect anonymous maps,
which Miri does not support; the zero-node roundtrip now runs only its
LoadMem loads under Miri. The new CLI integration tests are excluded
wholesale like the preexisting ones, as the CLI loads graphs and
Elias-Fano structures through mmap.
Pull Request #171: Fixes from a full-workspace code review: correctness, error handling, robustness

356 of 482 new or added lines in 60 files covered. (73.86%)

9 existing lines in 6 files now uncovered.

8157 of 11211 relevant lines covered (72.76%)

49198900.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.35
/webgraph/src/graphs/vec_graph.rs
1
/*
2
 * SPDX-FileCopyrightText: 2023 Inria
3
 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
4
 *
5
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6
 */
7

8
use crate::{impl_parallel_from_split, prelude::*};
9
use epserde::Epserde;
10
use lender::prelude::*;
11

12
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13
#[derive(Epserde, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
14
#[epserde(deep_copy)]
15
/// An arc with a label, stored as a pair (target, label).
16
pub struct LabeledArc<L>(usize, L);
17

18
impl<L> From<(usize, L)> for LabeledArc<L> {
19
    fn from((v, l): (usize, L)) -> Self {
15,208,916✔
20
        Self(v, l)
15,208,916✔
21
    }
22
}
23

24
impl<L> From<LabeledArc<L>> for (usize, L) {
25
    fn from(value: LabeledArc<L>) -> (usize, L) {
12,864,823✔
26
        (value.0, value.1)
12,864,823✔
27
    }
28
}
29

30
/// A mutable [`LabeledRandomAccessGraph`] implementation based on a vector of
31
/// vectors.
32
///
33
/// This implementation is faster and uses less resources than a
34
/// [`LabeledBTreeGraph`], but it is less flexible as arcs can be added only
35
/// in increasing successor order.
36
///
37
/// This struct can be serialized with [ε-serde]. By setting the feature
38
/// `serde`, this struct can be serialized using [serde], too.
39
///
40
/// [`LabeledBTreeGraph`]: crate::graphs::btree_graph::LabeledBTreeGraph
41
/// [ε-serde]: https://crates.io/crates/epserde
42
/// [serde]: https://crates.io/crates/serde
43
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44
#[derive(Epserde, Clone, Debug, PartialEq, Eq)]
45
pub struct LabeledVecGraph<L: Clone + 'static> {
46
    /// The number of arcs in the graph.
47
    num_arcs: u64,
48
    /// For each node, its list of successors.
49
    succ: Vec<Vec<LabeledArc<L>>>,
50
}
51

52
impl<L: Clone + 'static> core::default::Default for LabeledVecGraph<L> {
53
    fn default() -> Self {
1✔
54
        Self::new()
1✔
55
    }
56
}
57

58
impl<L: Clone + 'static> LabeledVecGraph<L> {
59
    /// Creates a new empty graph.
60
    pub fn new() -> Self {
3,014✔
61
        Self {
62
            num_arcs: 0,
63
            succ: vec![],
3,014✔
64
        }
65
    }
66

67
    /// Creates a new empty graph with `n` nodes.
68
    pub fn empty(n: usize) -> Self {
3,837✔
69
        Self {
70
            num_arcs: 0,
71
            succ: Vec::from_iter((0..n).map(|_| Vec::new())),
209,477✔
72
        }
73
    }
74

75
    /// Adds an isolated node to the graph and returns true if it is a new node.
76
    pub fn add_node(&mut self, node: usize) -> bool {
28,457,657✔
77
        let len = self.succ.len();
85,372,971✔
78
        self.succ.extend((len..=node).map(|_| Vec::new()));
114,551,509✔
79
        len <= node
28,457,657✔
80
    }
81

82
    /// Adds an arc to the graph.
83
    ///
84
    /// New arcs must be added in increasing successor order, or this method
85
    /// will panic.
86
    ///
87
    /// # Panics
88
    ///
89
    /// This method will panic:
90
    /// - if one of the given nodes is greater or equal than the number of nodes
91
    ///   in the graph;
92
    /// - if the successor is lesser than or equal to the current last successor
93
    ///   of the source node (in particular, if the arc is a duplicate of the
94
    ///   last added arc).
95
    pub fn add_arc(&mut self, u: usize, v: usize, l: L) {
15,208,900✔
96
        let max = u.max(v);
60,835,600✔
97
        if max >= self.succ.len() {
30,417,800✔
98
            panic!(
×
99
                "Node {} does not exist (the graph has {} nodes)",
×
100
                max,
×
101
                self.succ.len(),
×
102
            );
103
        }
104
        let succ = &mut self.succ[u];
30,417,800✔
105

106
        match succ.last() {
15,208,900✔
107
            None => {
108
                succ.push((v, l).into());
3,035,160✔
109
                self.num_arcs += 1;
758,790✔
110
            }
111
            Some(LabeledArc(last, _label)) => {
28,900,220✔
112
                if v <= *last {
14,450,110✔
113
                    // arcs have to be inserted in increasing successor order
114
                    panic!(
×
NEW
115
                        "Error adding arc ({u}, {v}): the successor is not strictly increasing (duplicate arcs are not allowed); the last arc inserted was ({u}, {last})"
×
116
                    );
117
                }
118
                succ.push((v, l).into());
57,800,440✔
119
                self.num_arcs += 1;
14,450,110✔
120
            }
121
        }
122
    }
123

124
    /// Adds nodes and successors from an [`IntoLender`] yielding a
125
    /// [`NodeLabelsLender`].
126
    ///
127
    /// If the lender is sorted, consider using [`add_sorted_lender`], as it
128
    /// does not need to sort the output of the lender.
129
    ///
130
    /// [`add_sorted_lender`]: Self::add_sorted_lender
131
    pub fn add_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
217✔
132
    where
133
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
134
    {
135
        let mut arcs = Vec::new();
434✔
136
        for_!( (node, succ) in iter_nodes {
23,665✔
137
            self.add_node(node);
35,172✔
138
            for (v, l) in succ {
1,080,993✔
139
                arcs.push((v, l));
1,425,692✔
140
                self.add_node(v);
712,846✔
141
            }
142
            arcs.sort_by_key(|x| x.0);
23,448✔
143
            for (v, l) in arcs.drain(..) {
1,104,441✔
144
                self.add_arc(node, v, l);
1,425,692✔
145
            }
146
        });
147
        self
217✔
148
    }
149

150
    /// Creates a new graph from an [`IntoLender`] yielding a
151
    /// [`NodeLabelsLender`].
152
    ///
153
    /// If the lender is sorted, consider using [`from_sorted_lender`], as it
154
    /// does not need to sort the output of the lender.
155
    ///
156
    /// [`from_sorted_lender`]: Self::from_sorted_lender
157
    pub fn from_lender<I: IntoLender>(iter_nodes: I) -> Self
8✔
158
    where
159
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
160
    {
161
        let mut g = Self::new();
16✔
162
        g.add_lender(iter_nodes);
24✔
163
        g
8✔
164
    }
165

166
    /// Adds nodes and successors from an [`IntoLender`] yielding a sorted
167
    /// [`NodeLabelsLender`].
168
    ///
169
    /// This method is faster than [`add_lender`] as it does not need to sort
170
    /// the output of the lender.
171
    ///
172
    /// [`add_lender`]: Self::add_lender
173
    pub fn add_sorted_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
4✔
174
    where
175
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
176
        I::Lender: SortedLender,
177
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
178
    {
179
        for_!( (node, succ) in iter_nodes {
56✔
180
            self.add_node(node);
78✔
181
            for (v, l) in succ {
119✔
182
                self.add_node(v);
124✔
183
                self.add_arc(node, v, l);
124✔
184
            }
185
        });
186
        self
4✔
187
    }
188

189
    /// Creates a new graph from a sorted [`IntoLender`] yielding a
190
    /// [`NodeLabelsLender`].
191
    ///
192
    /// This method is faster than [`from_lender`] as it does not need to
193
    /// sort the output of the lender.
194
    ///
195
    /// [`from_lender`]: Self::from_lender
196
    pub fn from_sorted_lender<I: IntoLender>(iter_nodes: I) -> Self
2✔
197
    where
198
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
199
        I::Lender: SortedLender,
200
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
201
    {
202
        let mut g = Self::new();
4✔
203
        g.add_sorted_lender(iter_nodes);
6✔
204
        g
2✔
205
    }
206

207
    /// Adds nodes and successors from an [`IntoLender`] yielding a sorted
208
    /// [`NodeLabelsLender`] whose successors implement [`ExactSizeIterator`].
209
    ///
210
    /// This method has a better memory behavior than [`add_sorted_lender`]
211
    /// as it can allocate the right amount of memory for each node at once.
212
    ///
213
    /// [`add_sorted_lender`]: Self::add_sorted_lender
214
    pub fn add_exact_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
3✔
215
    where
216
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
217
        I::Lender: SortedLender,
218
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator + ExactSizeIterator,
219
    {
220
        for_!( (node, succ) in iter_nodes {
31✔
221
            self.add_node(node);
42✔
222
            let succ = succ.into_iter();
42✔
223
            let d = succ.len();
42✔
224
            self.succ[node].reserve_exact(d);
42✔
225
            self.succ[node].extend(succ.map(Into::into));
56✔
226
            self.num_arcs += d as u64;
14✔
227
            // Add the missing successor nodes; since the successors are
228
            // sorted, it suffices to add the last one.
229
            if let Some(max_succ) = self.succ[node].last().map(|arc| arc.0) {
46✔
230
                self.add_node(max_succ);
18✔
231
            }
232
        });
233
        self
3✔
234
    }
235

236
    /// Creates a new graph from a sorted [`IntoLender`] yielding a
237
    /// [`NodeLabelsLender`] whose successors implement [`ExactSizeIterator`].
238
    ///
239
    /// This method has a better memory behavior than [`from_sorted_lender`]
240
    /// as it can allocate the right amount of memory for each node at once.
241
    ///
242
    /// [`from_sorted_lender`]: Self::from_sorted_lender
243
    pub fn from_exact_lender<I: IntoLender>(iter_nodes: I) -> Self
2✔
244
    where
245
        I::Lender: for<'next> NodeLabelsLender<'next, Label = (usize, L)>,
246
        I::Lender: SortedLender,
247
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator + ExactSizeIterator,
248
    {
249
        let mut g = Self::new();
4✔
250
        g.add_exact_lender(iter_nodes);
6✔
251
        g
2✔
252
    }
253

254
    /// Adds labeled arcs from an [`IntoIterator`], adding new nodes as needed.
255
    ///
256
    /// The items must be labeled pairs of the form `((usize, usize), l)` specifying an
257
    /// arc and its label. Duplicate arcs are added once, keeping the label of
258
    /// the last occurrence, as in [`LabeledBTreeGraph`].
259
    ///
260
    /// [`LabeledBTreeGraph`]: crate::graphs::btree_graph::LabeledBTreeGraph
261
    pub fn add_arcs(&mut self, arcs: impl IntoIterator<Item = ((usize, usize), L)>) {
736✔
262
        let mut arcs = arcs.into_iter().collect::<Vec<_>>();
2,944✔
263
        arcs.sort_by_key(|x| x.0);
1,472✔
264
        // Keep the label of the last occurrence of each arc: `b` is the
265
        // element that survives deduplication, `a` the one that is removed.
266
        arcs.dedup_by(|a, b| {
7,808,242✔
267
            let dup = a.0 == b.0;
15,613,540✔
268
            if dup {
7,806,772✔
269
                core::mem::swap(a, b);
4✔
270
            }
271
            dup
7,806,770✔
272
        });
273
        for ((u, v), l) in arcs {
31,230,748✔
274
            self.add_node(u);
31,230,012✔
275
            self.add_node(v);
31,230,012✔
276
            self.add_arc(u, v, l);
31,230,012✔
277
        }
278
    }
279

280
    /// Creates a new graph from an [`IntoIterator`].
281
    ///
282
    /// The items must be labeled pairs of the form `((usize, usize), l)` specifying an
283
    /// arc and its label.
284
    pub fn from_arcs(arcs: impl IntoIterator<Item = ((usize, usize), L)>) -> Self {
45✔
285
        let mut g = Self::new();
90✔
286
        g.add_arcs(arcs);
135✔
287
        g
45✔
288
    }
289

290
    /// Shrinks the capacity of the graph to fit its current size.
291
    pub fn shrink_to_fit(&mut self) {
1✔
292
        self.succ.shrink_to_fit();
2✔
293
        for s in self.succ.iter_mut() {
7✔
294
            s.shrink_to_fit();
3✔
295
        }
296
    }
297
}
298

299
impl<L: Clone + 'static> SequentialLabeling for LabeledVecGraph<L> {
300
    type Label = (usize, L);
301
    type Lender<'a>
302
        = LenderImpl<'a, Self>
303
    where
304
        Self: 'a;
305

306
    #[inline(always)]
307
    fn num_nodes(&self) -> usize {
3,004✔
308
        self.succ.len()
6,008✔
309
    }
310

311
    #[inline(always)]
312
    fn num_arcs_hint(&self) -> Option<u64> {
32✔
313
        Some(self.num_arcs())
32✔
314
    }
315

316
    #[inline(always)]
317
    fn iter_from(&self, from: usize) -> Self::Lender<'_> {
66✔
318
        LenderImpl {
319
            labeling: self,
320
            nodes: (from..self.num_nodes()),
132✔
321
        }
322
    }
323
}
324

325
/// Convenience implementation that makes it possible to iterate
326
/// over the graph using the [`for_`] macro
327
/// (see the [crate documentation]).
328
///
329
/// [crate documentation]: crate
330
impl<'a, L: Clone + 'static> IntoLender for &'a LabeledVecGraph<L> {
331
    type Lender = <LabeledVecGraph<L> as SequentialLabeling>::Lender<'a>;
332

333
    #[inline(always)]
334
    fn into_lender(self) -> Self::Lender {
1✔
335
        self.iter()
2✔
336
    }
337
}
338

339
impl<L: Clone + 'static> LabeledSequentialGraph<L> for LabeledVecGraph<L> {}
340

341
impl<L: Clone + 'static> RandomAccessLabeling for LabeledVecGraph<L> {
342
    type Labels<'succ> = AssumeSortedIterator<
343
        core::iter::Map<
344
            core::iter::Cloned<core::slice::Iter<'succ, LabeledArc<L>>>,
345
            fn(LabeledArc<L>) -> (usize, L),
346
        >,
347
    >;
348
    #[inline(always)]
349
    fn num_arcs(&self) -> u64 {
14,259✔
350
        self.num_arcs
14,259✔
351
    }
352

353
    #[inline(always)]
354
    fn outdegree(&self, node: usize) -> usize {
370,862✔
355
        self.succ[node].len()
741,724✔
356
    }
357

358
    #[inline(always)]
359
    fn labels(&self, node: usize) -> <Self as RandomAccessLabeling>::Labels<'_> {
1,302,366✔
360
        // SAFETY: successors are stored in a BTreeSet, which iterates in sorted order.
361
        unsafe { AssumeSortedIterator::new(self.succ[node].iter().cloned().map(Into::into)) }
6,511,830✔
362
    }
363
}
364

365
impl<L: Clone + 'static> LabeledRandomAccessGraph<L> for LabeledVecGraph<L> {}
366

367
impl<L: Clone + Sync> SplitLabeling for LabeledVecGraph<L> {
368
    type SplitLender<'a>
369
        = split::ra::Lender<'a, LabeledVecGraph<L>>
370
    where
371
        Self: 'a;
372

373
    type IntoIterator<'a>
374
        = split::ra::IntoIterator<'a, LabeledVecGraph<L>>
375
    where
376
        Self: 'a;
377

378
    fn split_iter_at(&self, cutpoints: impl IntoIterator<Item = usize>) -> Self::IntoIterator<'_> {
5✔
379
        split::ra::Iter::new(self, cutpoints)
15✔
380
    }
381
}
382

383
impl_parallel_from_split!(
384
    [L: Clone + Sync]
385
    LabeledVecGraph<L>
386
    []
387
);
388

389
/// A mutable [`RandomAccessGraph`] implementation based on a vector of
390
/// vectors.
391
///
392
/// This implementation is faster and uses less resources than a [`BTreeGraph`],
393
/// but it is less flexible as arcs can be added only in increasing successor
394
/// order.
395
///
396
/// This struct can be serialized with [ε-serde]. By setting the feature
397
/// `serde`, this struct can be serialized using [serde], too.
398
///
399
/// # Implementation Notes
400
///
401
/// This is just a newtype for a [`LabeledVecGraph`] with [`()`] labels.
402
/// All mutation methods are delegated.
403
///
404
/// [ε-serde]: https://crates.io/crates/epserde
405
/// [serde]: https://crates.io/crates/serde
406
/// [`()`]: https://doc.rust-lang.org/std/primitive.unit.html
407
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
408
#[derive(Epserde, Clone, Debug, Default, PartialEq, Eq)]
409
pub struct VecGraph(LabeledVecGraph<()>);
410

411
impl VecGraph {
412
    /// Creates a new empty graph.
413
    pub fn new() -> Self {
2,950✔
414
        LabeledVecGraph::new().into()
5,900✔
415
    }
416

417
    /// Creates a new empty graph with `n` nodes.
418
    pub fn empty(n: usize) -> Self {
3,835✔
419
        LabeledVecGraph::empty(n).into()
11,505✔
420
    }
421

422
    /// Adds an isolated node to the graph and returns true if it is a new node.
423
    pub fn add_node(&mut self, node: usize) -> bool {
1,700✔
424
        self.0.add_node(node)
5,100✔
425
    }
426

427
    /// Adds an arc to the graph.
428
    ///
429
    /// New arcs must be added in increasing successor order, or this method
430
    /// will panic.
431
    ///
432
    /// # Panics
433
    ///
434
    /// This method will panic:
435
    /// - if one of the given nodes is greater or equal than the number of nodes
436
    ///   in the graph;
437
    /// - if the successor is lesser than or equal to the current last successor
438
    ///   of the source node.
439
    pub fn add_arc(&mut self, u: usize, v: usize) {
119,180✔
440
        self.0.add_arc(u, v, ())
595,900✔
441
    }
442

443
    /// Adds nodes and successors from an [`IntoLender`] yielding a
444
    /// [`NodeLabelsLender`].
445
    ///
446
    /// If the lender is sorted, consider using [`add_sorted_lender`], as it
447
    /// does not need to sort the output of the lender.
448
    ///
449
    /// [`add_sorted_lender`]: Self::add_sorted_lender
450
    pub fn add_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
209✔
451
    where
452
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
453
    {
454
        self.0.add_lender(UnitLabelLender(iter_nodes.into_lender()));
627✔
455
        self
209✔
456
    }
457

458
    /// Creates a new graph from an [`IntoLender`] yielding a
459
    /// [`NodeLabelsLender`].
460
    ///
461
    /// If the lender is sorted, consider using [`from_sorted_lender`], as it
462
    /// does not need to sort the output of the lender.
463
    ///
464
    /// [`from_sorted_lender`]: Self::from_sorted_lender
465
    pub fn from_lender<I: IntoLender>(iter_nodes: I) -> Self
209✔
466
    where
467
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
468
    {
469
        let mut g = Self::new();
418✔
470
        g.add_lender(iter_nodes);
627✔
471
        g
209✔
472
    }
473

474
    /// Adds nodes and successors from an [`IntoLender`] yielding a sorted
475
    /// [`NodeLabelsLender`].
476
    ///
477
    /// This method is faster than [`add_lender`] as it does not need to sort
478
    /// the output of the lender.
479
    ///
480
    /// [`add_lender`]: Self::add_lender
481
    pub fn add_sorted_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
2✔
482
    where
483
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
484
        I::Lender: SortedLender,
485
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
486
    {
487
        self.0
2✔
488
            .add_sorted_lender(UnitLabelLender(iter_nodes.into_lender()));
4✔
489
        self
2✔
490
    }
491

492
    /// Creates a new graph from a sorted [`IntoLender`] yielding a
493
    /// [`NodeLabelsLender`].
494
    ///
495
    /// This method is faster than [`from_lender`] as it does not need to
496
    /// sort the output of the lender.
497
    ///
498
    /// [`from_lender`]: Self::from_lender
499
    pub fn from_sorted_lender<I: IntoLender>(iter_nodes: I) -> Self
2✔
500
    where
501
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
502
        I::Lender: SortedLender,
503
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
504
    {
505
        let mut g = Self::new();
4✔
506
        g.add_sorted_lender(iter_nodes);
6✔
507
        g
2✔
508
    }
509

510
    /// Adds nodes and successors from an [`IntoLender`] yielding a sorted
511
    /// [`NodeLabelsLender`] whose successors implement [`ExactSizeIterator`].
512
    ///
513
    /// This method has a better memory behavior than [`add_sorted_lender`]
514
    /// as it can allocate the right amount of memory for each node at once.
515
    ///
516
    /// [`add_sorted_lender`]: Self::add_sorted_lender
517
    pub fn add_exact_lender<I: IntoLender>(&mut self, iter_nodes: I) -> &mut Self
3✔
518
    where
519
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
520
        I::Lender: SortedLender,
521
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator + ExactSizeIterator,
522
    {
523
        for_!( (node, succ) in iter_nodes {
31✔
524
            self.add_node(node);
42✔
525
            let succ = succ.into_iter();
42✔
526
            let d = succ.len();
42✔
527
            self.0.succ[node].reserve_exact(d);
42✔
528
            self.0.succ[node].extend(succ.map(|x| LabeledArc(x, ())));
90✔
529
            self.0.num_arcs += d as u64;
14✔
530
            // Add the missing successor nodes; since the successors are
531
            // sorted, it suffices to add the last one.
532
            if let Some(max_succ) = self.0.succ[node].last().map(|arc| arc.0) {
48✔
533
                self.add_node(max_succ);
20✔
534
            }
535
        });
536
        self
3✔
537
    }
538

539
    /// Creates a new graph from a sorted [`IntoLender`] yielding a
540
    /// [`NodeLabelsLender`] whose successors implement [`ExactSizeIterator`].
541
    ///
542
    /// This method has a better memory behavior than [`from_sorted_lender`]
543
    /// as it can allocate the right amount of memory for each node at once.
544
    ///
545
    /// [`from_sorted_lender`]: Self::from_sorted_lender
546
    pub fn from_exact_lender<I: IntoLender>(iter_nodes: I) -> Self
2✔
547
    where
548
        I::Lender: for<'next> NodeLabelsLender<'next, Label = usize>,
549
        I::Lender: SortedLender,
550
        for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator + ExactSizeIterator,
551
    {
552
        let mut g = Self::new();
4✔
553
        g.add_exact_lender(iter_nodes);
6✔
554
        g
2✔
555
    }
556

557
    /// Adds arcs from an [`IntoIterator`], adding new nodes as needed.
558
    ///
559
    /// The items must be pairs of the form `(usize, usize)` specifying an
560
    /// arc. Duplicate arcs are added once.
561
    pub fn add_arcs(&mut self, arcs: impl IntoIterator<Item = (usize, usize)>) {
691✔
562
        self.0.add_arcs(arcs.into_iter().map(|pair| (pair, ())));
2,753,591✔
563
    }
564

565
    /// Creates a new graph from an [`IntoIterator`].
566
    ///
567
    /// The items must be pairs of the form `(usize, usize)` specifying an arc.
568
    pub fn from_arcs(arcs: impl IntoIterator<Item = (usize, usize)>) -> Self {
352✔
569
        let mut g = Self::new();
704✔
570
        g.add_arcs(arcs);
1,056✔
571
        g
352✔
572
    }
573

574
    /// Shrinks the capacity of the graph to fit its current size.
575
    pub fn shrink_to_fit(&mut self) {
×
576
        self.0.shrink_to_fit();
×
577
    }
578
}
579

580
/// Convenience implementation that makes it possible to iterate
581
/// over the graph using the [`for_`] macro
582
/// (see the [crate documentation]).
583
///
584
/// [crate documentation]: crate
585
impl<'a> IntoLender for &'a VecGraph {
586
    type Lender = <VecGraph as SequentialLabeling>::Lender<'a>;
587

588
    #[inline(always)]
589
    fn into_lender(self) -> Self::Lender {
1✔
590
        self.iter()
2✔
591
    }
592
}
593

594
impl SequentialLabeling for VecGraph {
595
    type Label = usize;
596
    type Lender<'a>
597
        = LenderImpl<'a, Self>
598
    where
599
        Self: 'a;
600

601
    #[inline(always)]
602
    fn num_nodes(&self) -> usize {
13,679✔
603
        self.0.num_nodes()
27,358✔
604
    }
605

606
    #[inline(always)]
607
    fn num_arcs_hint(&self) -> Option<u64> {
30✔
608
        self.0.num_arcs_hint()
60✔
609
    }
610

611
    #[inline(always)]
612
    fn iter_from(&self, from: usize) -> Self::Lender<'_> {
51,856✔
613
        LenderImpl {
614
            labeling: self,
615
            nodes: (from..self.num_nodes()),
103,712✔
616
        }
617
    }
618
}
619

620
impl SequentialGraph for VecGraph {}
621

622
impl RandomAccessLabeling for VecGraph {
623
    type Labels<'succ> = AssumeSortedIterator<
624
        core::iter::Map<
625
            core::iter::Copied<core::slice::Iter<'succ, LabeledArc<()>>>,
626
            fn(LabeledArc<()>) -> usize,
627
        >,
628
    >;
629
    #[inline(always)]
630
    fn num_arcs(&self) -> u64 {
14,235✔
631
        self.0.num_arcs()
28,470✔
632
    }
633

634
    #[inline(always)]
635
    fn outdegree(&self, node: usize) -> usize {
370,856✔
636
        self.0.outdegree(node)
1,112,568✔
637
    }
638

639
    #[inline(always)]
640
    fn labels(&self, node: usize) -> <Self as RandomAccessLabeling>::Labels<'_> {
374,451✔
641
        // this is safe as we maintain each vector of successors sorted
642
        unsafe {
643
            AssumeSortedIterator::new(self.0.succ[node].iter().copied().map(|LabeledArc(x, _)| x))
1,497,804✔
644
        }
645
    }
646
}
647

648
impl RandomAccessGraph for VecGraph {}
649

650
impl From<LabeledVecGraph<()>> for VecGraph {
651
    fn from(g: LabeledVecGraph<()>) -> Self {
6,785✔
652
        VecGraph(g)
6,785✔
653
    }
654
}
655

656
impl SplitLabeling for VecGraph {
657
    type SplitLender<'a>
658
        = split::ra::Lender<'a, VecGraph>
659
    where
660
        Self: 'a;
661

662
    type IntoIterator<'a>
663
        = split::ra::IntoIterator<'a, VecGraph>
664
    where
665
        Self: 'a;
666

667
    fn split_iter_at(&self, cutpoints: impl IntoIterator<Item = usize>) -> Self::IntoIterator<'_> {
61✔
668
        split::ra::Iter::new(self, cutpoints)
183✔
669
    }
670
}
671

672
impl_parallel_from_split!(
673
    []
674
    VecGraph
675
    []
676
);
677

678
#[cfg(test)]
679
mod test {
680
    use super::*;
681
    #[test]
682
    fn test_vec_graph() {
683
        let mut arcs = vec![
684
            ((0, 1), Some(1.0)),
685
            ((0, 2), None),
686
            ((1, 2), Some(2.0)),
687
            ((2, 4), Some(f64::INFINITY)),
688
            ((3, 4), Some(f64::NEG_INFINITY)),
689
            ((1, 3), Some(f64::NAN)),
690
        ];
691
        let g = LabeledVecGraph::<_>::from_arcs(arcs.iter().copied());
692
        assert_ne!(
693
            g, g,
694
            "The label contains a NaN which is not equal to itself so the graph must be not equal to itself"
695
        );
696

697
        arcs.pop();
698
        let g = LabeledVecGraph::<_>::from_arcs(arcs);
699
        assert_eq!(g, g, "Without NaN the graph should be equal to itself");
700
    }
701
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc