Skip to content

Patch 'dot' feature and replace 'no_std' with 'std' feature #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "graphlib"
version = "0.6.3"
authors = ["Octavian Oncescu <octavonce@gmail.com>"]
edition = "2018"
edition = "2021"
repository = "https://github.com/purpleprotocol/graphlib"
keywords = ["graph", "data-structures", "mutable", "graph-algorithm", "no-std"]
categories = ["data-structures", "no-std"]
Expand All @@ -14,29 +14,33 @@ readme = "README.md"
travis-ci = { repository = "purpleprotocol/graphlib", branch = "master" }

[dependencies]
rand = { version = "0.7.3", default-features = false }
rand_core = { version = "0.5.1", default-features = false }
rand_isaac = { version = "0.2.0", default-features = false }
hex = { version = "0.4.0", default-features = false }
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
hashbrown = { version = "0.6.3", default-features = false, features = ["inline-more", "ahash"] }
dot = { version = "0.1.4", optional = true }
dot = { version = "0.1.4", default-features = false, optional = true }

[dev-dependencies]
criterion = "0.3.0"

[lib]
name = "graphlib"
path = "src/lib.rs"
crate-type = [
"lib",
]

[[bench]]
name = "benchmark"
harness = false

[features]
default = []
# std needs to be a default feature or else you get the following error:
# ink! only supports compilation as `std` or `no_std` + `wasm32-unknown`"
default = ["hashbrown/nightly", "std"]
# use `cargo bench --features sbench` only if you want benchmarks with 10 million
# iterations (may fail on some systems)
sbench = []

# nightly feature for `no_std`
# for build use `cargo +nightly build --features no_std`
no_std = ["hashbrown/nightly"]
std = []

[package.metadata.docs.rs]
features = ["dot"]
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ Graphlib is a simple and powerful Rust graph library.

This library attempts to provide a generic api for building, mutating and iterating over graphs that is similar to that of other data-structures found in Rust i.e. `Vec`, `HashMap`, `VecDeque`, etc.

## Modifications in this fork from the original
1. Fix compilation error when dot feature is enabled.
2. Replace no_std feature with a std feature (and reverse the default behavior).
3. Remove the dependency on rand. This library causes problems in constrained environments that do not have access to an RNG.

### Using Graphlib
```rust
use graphlib::Graph;
Expand Down Expand Up @@ -34,13 +39,6 @@ assert_eq!(graph.vertex_count(), 1);
assert_eq!(graph.edge_count(), 0);
```

### Using without `std`
In `Cargo.toml`:
```toml
[dependencies]
graphlib = { version = "*", features = ["no_std"] }
```

### Contributing
We welcome anyone wishing to contribute to Graphlib! Check out the [issues section][issues] of the repository before starting out.

Expand Down
4 changes: 4 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "nightly-2022-09-08"
components = [ "rustfmt" ]
targets = [ "wasm32-unknown-unknown" ]
20 changes: 4 additions & 16 deletions src/dot.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
use crate::{Graph, GraphErr, VertexId};

#[cfg(feature = "no_std")]
use core::io::Write;
#[cfg(not(feature = "std"))]
use alloc::borrow::Cow;

#[cfg(not(feature = "no_std"))]
use std::io::Write;

#[cfg(feature = "no_std")]
use core::borrow::Cow;

#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::borrow::Cow;

#[cfg(feature = "no_std")]
use core::fmt::Debug;

#[cfg(not(feature = "no_std"))]
use std::fmt::Debug;

type Nd = VertexId;
type Ed<'a> = (&'a VertexId, &'a VertexId);

Expand All @@ -43,7 +31,7 @@ impl<'a, T> dot::Labeller<'a, Nd, Ed<'a>> for DotGraph<'a, T> {
}

fn node_id(&'a self, n: &Nd) -> dot::Id<'a> {
let hex = format!("N{}", hex::encode(n.bytes()));
let hex = format!("N{}", n.val());
dot::Id::new(hex).unwrap()
}

Expand Down
10 changes: 6 additions & 4 deletions src/edge.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Copyright 2019 Octavian Oncescu

use crate::vertex_id::VertexId;
#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::hash::Hash;
#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::hash::Hasher;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use core::hash::{Hash, Hasher};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -40,12 +40,14 @@ impl Edge {

/// Returns true if the given vertex ids are the
/// inbound and outbound vertices of the edge.
#[allow(dead_code)]
pub(crate) fn matches(&self, a: &VertexId, b: &VertexId) -> bool {
a == &self.outbound && b == &self.inbound
}

/// Returns true if either the inbound or outbound
/// vertex is matching the given `VertexId`.
#[allow(dead_code)]
pub(crate) fn matches_any(&self, id: &VertexId) -> bool {
id == &self.inbound || id == &self.outbound
}
Expand Down
49 changes: 27 additions & 22 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,28 @@ use crate::iterators::*;
use crate::vertex_id::VertexId;
use hashbrown::{HashMap, HashSet};

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use core::iter;
#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::iter;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use core::fmt::Debug;
#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::fmt::Debug;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::vec;
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;


#[cfg(feature = "dot")]
use super::SEED;
const DEFAULT_LABEL: &str = "";

#[derive(Clone, Debug, PartialEq)]
/// Graph operation error
Expand Down Expand Up @@ -77,6 +78,8 @@ pub struct Graph<T> {
/// Mapping between vertex ids and outbound edges
outbound_table: HashMap<VertexId, Vec<VertexId>>,

next_vertex_id: u32,

#[cfg(feature = "dot")]
/// Mapping between vertices and labels
vertex_labels: HashMap<VertexId, String>,
Expand Down Expand Up @@ -106,6 +109,7 @@ impl<T> Graph<T> {
tips: HashSet::new(),
inbound_table: HashMap::new(),
outbound_table: HashMap::new(),
next_vertex_id: 1,

#[cfg(feature = "dot")]
vertex_labels: HashMap::new(),
Expand Down Expand Up @@ -136,6 +140,7 @@ impl<T> Graph<T> {
tips: HashSet::with_capacity(capacity),
inbound_table: HashMap::with_capacity(capacity),
outbound_table: HashMap::with_capacity(capacity),
next_vertex_id: 1,

#[cfg(feature = "dot")]
vertex_labels: HashMap::with_capacity(capacity),
Expand Down Expand Up @@ -261,7 +266,10 @@ impl<T> Graph<T> {
/// assert_eq!(graph.fetch(&id).unwrap(), &1);
/// ```
pub fn add_vertex(&mut self, item: T) -> VertexId {
let id = VertexId::random();
let id = VertexId::new(self.next_vertex_id);
// This library is clearly not thread-safe, so we do not bother
// using an atomic int
self.next_vertex_id += 1;

self.vertices.insert(id, (item, id));
self.roots.insert(id);
Expand All @@ -279,7 +287,7 @@ impl<T> Graph<T> {
/// let mut graph: Graph<usize> = Graph::new();
///
/// // Id of vertex that is not place in the graph
/// let id = VertexId::random();
/// let id = VertexId::new(100);
///
/// let v1 = graph.add_vertex(1);
/// let v2 = graph.add_vertex(2);
Expand Down Expand Up @@ -313,7 +321,7 @@ impl<T> Graph<T> {
/// let mut graph: Graph<usize> = Graph::new();
///
/// // Id of vertex that is not place in the graph
/// let id = VertexId::random();
/// let id = VertexId::new(100);
///
/// let v1 = graph.add_vertex(1);
/// let v2 = graph.add_vertex(2);
Expand Down Expand Up @@ -344,7 +352,7 @@ impl<T> Graph<T> {
/// let mut graph: Graph<usize> = Graph::new();
///
/// // Id of vertex that is not place in the graph
/// let id = VertexId::random();
/// let id = VertexId::new(100);
///
/// let v1 = graph.add_vertex(1);
/// let v2 = graph.add_vertex(2);
Expand Down Expand Up @@ -382,7 +390,7 @@ impl<T> Graph<T> {
/// let mut graph: Graph<usize> = Graph::new();
///
/// // Id of vertex that is not place in the graph
/// let id = VertexId::random();
/// let id = VertexId::new(100);
///
/// let v1 = graph.add_vertex(1);
/// let v2 = graph.add_vertex(2);
Expand Down Expand Up @@ -417,7 +425,7 @@ impl<T> Graph<T> {
/// let mut graph: Graph<usize> = Graph::new();
///
/// // Id of vertex that is not place in the graph
/// let id = VertexId::random();
/// let id = VertexId::new(100);
///
/// let v1 = graph.add_vertex(1);
/// let v2 = graph.add_vertex(2);
Expand Down Expand Up @@ -1368,7 +1376,7 @@ impl<T> Graph<T> {
/// use graphlib::{Graph, VertexId};
///
/// let mut graph: Graph<usize> = Graph::new();
/// let random_id = VertexId::random();
/// let random_id = VertexId::new(100);
///
/// let v1 = graph.add_vertex(0);
/// let v2 = graph.add_vertex(1);
Expand Down Expand Up @@ -1400,7 +1408,7 @@ impl<T> Graph<T> {
/// use graphlib::{Graph, VertexId};
///
/// let mut graph: Graph<usize> = Graph::new();
/// let random_id = VertexId::random();
/// let random_id = VertexId::new(100);
///
/// let v1 = graph.add_vertex(0);
/// let v2 = graph.add_vertex(1);
Expand Down Expand Up @@ -1468,7 +1476,7 @@ impl<T> Graph<T> {
/// use graphlib::{Graph, VertexId};
///
/// let mut graph: Graph<usize> = Graph::new();
/// let random_id = VertexId::random();
/// let random_id = VertexId::new(100);
/// let mut vertex_id: usize = 1;
///
/// let v1 = graph.add_vertex(0);
Expand Down Expand Up @@ -1523,7 +1531,7 @@ impl<T> Graph<T> {
/// use graphlib::{Graph, VertexId};
///
/// let mut graph: Graph<usize> = Graph::new();
/// let random_id = VertexId::random();
/// let random_id = VertexId::new(100);
/// let mut vertex_id: usize = 1;
///
/// let v1 = graph.add_vertex(0);
Expand Down Expand Up @@ -1840,9 +1848,6 @@ mod tests {
fn test_add_edge_cycle_check() {
let mut graph: Graph<usize> = Graph::new();

// Id of vertex that is not place in the graph
let id = VertexId::random();

let v1 = graph.add_vertex(1);
let v2 = graph.add_vertex(2);

Expand Down
12 changes: 6 additions & 6 deletions src/iterators/bfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ use crate::graph::Graph;
use crate::vertex_id::VertexId;

use hashbrown::HashSet;
#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::collections::VecDeque;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::collections::vec_deque::VecDeque;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use core::fmt::Debug;

#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::fmt::Debug;

#[derive(Debug)]
Expand Down
12 changes: 6 additions & 6 deletions src/iterators/dfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ use crate::graph::Graph;
use crate::iterators::VertexIter;
use crate::vertex_id::VertexId;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use core::iter::{Chain, Cloned, Peekable};
use hashbrown::HashSet;
#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::iter::{Chain, Cloned, Peekable};

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use core::fmt::Debug;

#[cfg(not(feature = "no_std"))]
#[cfg(feature = "std")]
use std::fmt::Debug;

#[derive(Debug)]
Expand Down
Loading