1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//! Traits for immutable access to a HandleGraph, including its
//! nodes/handles, edges, and the sequences of nodes.
//!
//! With the exception of [`HandleGraph`] and [`HandleGraphRef`], each of
//! these traits are centered on providing iterators to one specific
//! part of a graph. For instance, [`IntoNeighbors`] gives access to
//! the neighbors of a handle, using the associated type `Neighbors:
//! Iterator<Item = Handle>`.
//!
//! Most of the methods that define the immutable part of the
//! handlegraph behavior have default implementations in terms of
//! these iterators, though it may be desirable to provide specific
//! implementations in some cases.
//!
//! The methods on the iterator traits often take `self`, rather than
//! `&self`, because the iterators are expected to borrow (part of)
//! the graph, which means the associated types in the concrete
//! implementations will include lifetimes, and at this time the only
//! way to do that is by using a lifetime that's part of the trait's
//! implementing type.
//!
//! For this reason, you won't actually implement [`IntoHandles`] for
//! [`PackedGraph`](`crate::packedgraph::PackedGraph`), but rather for
//! `&'a PackedGraph`.
//!
//! The [`HandleGraphRef`] trait is provided to make it more convenient
//! to write generic functions using any subset of the handlegraph
//! behaviors.

use crate::handle::{Direction, Edge, Handle, NodeId};

use rayon::prelude::*;

pub mod iter;

pub use self::iter::*;

/// The base `HandleGraph` trait, with only a tiny subset of the
/// handlegraph behavior.
///
/// If you want to write code that's generic over handlegraphs, use
/// the bound [`HandleGraphRef`] instead.
pub trait HandleGraph {
    /// Return the minimum `NodeId` that exists in the graph.
    fn min_node_id(&self) -> NodeId;

    /// Return the maximum `NodeId` that exists in the graph.
    fn max_node_id(&self) -> NodeId;

    /// Return the number of nodes in the graph.
    fn node_count(&self) -> usize;

    /// Return the number of edges in the graph.
    fn edge_count(&self) -> usize;

    /// Returns the sum of the sequence lengths of all nodes in the
    /// graph.
    fn total_length(&self) -> usize;
}

/// Trait collecting all immutable trait bounds.
///
/// Trait denoting that implementors have access to all the immutable
/// parts of the HandleGraph interface, and that implementors are
/// copyable references (i.e. immutable, shared references).
///
/// Has a blanket implementation for all references that implement the
/// traits in question.
pub trait HandleGraphRef:
    IntoEdges + IntoHandles + IntoNeighbors + IntoSequences + Copy
{
}

impl<'a, T> HandleGraphRef for &'a T where
    &'a T: IntoEdges + IntoHandles + IntoNeighbors + IntoSequences + Copy
{
}

impl<'a, T> HandleGraphRef for &'a mut T where
    &'a mut T: IntoEdges + IntoHandles + IntoNeighbors + IntoSequences + Copy
{
}

/// Access all the handles in the graph as an iterator, and querying
/// the graph for number of nodes, and presence of a node by ID.
pub trait IntoHandles: Sized {
    /// The iterator through all of the graph's handles.
    type Handles: Iterator<Item = Handle>;

    /// Return an iterator on all the handles in the graph.
    fn handles(self) -> Self::Handles;

    /// Returns `true` if the node `node_id` exists in the graph. The
    /// default implementation uses `any` on the iterator from
    /// [`Self::handles`].
    #[inline]
    fn has_node<I: Into<NodeId>>(self, node_id: I) -> bool {
        let node_id = node_id.into();
        self.handles().any(|h| h.id() == node_id)
    }
}

/// Parallel access to all the handles in the graph.
pub trait IntoHandlesPar {
    /// The Rayon `ParallelIterator` through all the handles in the graph.
    type HandlesPar: ParallelIterator<Item = Handle>;

    /// Return a parallel iterator on all the handles in the graph.
    fn handles_par(self) -> Self::HandlesPar;
}

/// Access all the edges in the graph as an iterator, and related and
/// querying the graph for number of edges.
pub trait IntoEdges: Sized {
    /// The iterator through all the edges in the graph.
    type Edges: Iterator<Item = Edge>;

    /// Return an iterator that produces each of the edges in the graph.
    fn edges(self) -> Self::Edges;
}

/// Parallel access to all the edges in the graph.
pub trait IntoEdgesPar {
    /// The Rayon `ParallelIterator` through all the edges in the graph.
    type EdgesPar: ParallelIterator<Item = Edge>;

    /// Return a parallel iterator on all the edges in the graph.
    fn edges_par(self) -> Self::EdgesPar;
}

/// Access to the neighbors of handles in the graph, and querying the
/// graph for a node's degree.
///
/// Implementors should make sure that handles are flipped correctly
/// depending on direction, e.g. using NeighborIter
pub trait IntoNeighbors: Sized {
    type Neighbors: Iterator<Item = Handle>;

    /// Return an iterator of the `Handle`s adjacent to the given
    /// `handle`, in the provided `Direction`. Implementations should
    /// take the orientation of `handle` into account.
    fn neighbors(self, handle: Handle, dir: Direction) -> Self::Neighbors;

    /// Return the number of neighbors of `handle` in the given
    /// direction. The default implementation uses `count` on
    /// [`Self::neighbors`].
    #[inline]
    fn degree(self, handle: Handle, dir: Direction) -> usize {
        self.neighbors(handle, dir).count()
    }

    /// Returns `true` if the `left` handle has a connection on its
    /// right-hand side to the `right` handle. The default
    /// implementation uses `any` on [`Self::neighbors`].
    #[inline]
    fn has_edge(self, left: Handle, right: Handle) -> bool {
        self.neighbors(left, Direction::Right).any(|h| h == right)
    }
}

/// Access to the sequence of any node, and related methods such as
/// retrieving subsequences, individual bases, and node lengths.
pub trait IntoSequences: Sized {
    type Sequence: Iterator<Item = u8>;

    /// Return an iterator on the bases of the sequence of `handle`.
    /// Implementations should take the orientation of `handle` into
    /// account, and produce the reverse complement of the sequence
    /// when appropriate.
    fn sequence(self, handle: Handle) -> Self::Sequence;

    /// Returns the sequence of the provided `handle` as an owned
    /// `Vec<u8>`. This is a convenience method that calls `collect`
    /// on [`Self::sequence`], so the default implementation should be
    /// fine for all use cases.
    #[inline]
    fn sequence_vec(self, handle: Handle) -> Vec<u8> {
        self.sequence(handle).collect()
    }

    /// Returns the subsequence of the provided `handle`, with the
    /// given offset `start` and length `len`, as an owned `Vec<u8>`.
    /// This is a convenience method that uses [`Self::sequence`],
    /// `skip`, `take`, and `collect`.
    #[inline]
    fn subsequence(self, handle: Handle, start: usize, len: usize) -> Vec<u8> {
        self.sequence(handle).skip(start).take(len).collect()
    }

    /// Returns the base at position `index` of the sequence of the
    /// provided `handle`, if it exists. This is a convenience method
    /// that uses [`Self::sequence`] and `nth`.
    #[inline]
    fn base(self, handle: Handle, index: usize) -> Option<u8> {
        self.sequence(handle).nth(index)
    }

    /// Returns the sequence length of the node at `handle`. The
    /// default implementation uses `count` on [`Self::sequence`],
    /// implementors may wish to change that.
    #[inline]
    fn node_len(self, handle: Handle) -> usize {
        self.sequence(handle).count()
    }
}