Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 277b6b1

Browse files
committed
Added documentation for from_instruction feature
1 parent b434c0f commit 277b6b1

File tree

5 files changed

+252
-104
lines changed

5 files changed

+252
-104
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[features]
9-
default = ["from_instruction"] #TODO remove before release
9+
#default = ["from_instruction"] #TODO remove before release
1010
from_instruction = []
1111

1212
[dependencies]

src/graph/mod.rs renamed to src/graph.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ use std::{fmt::{Display, Debug}, rc::Rc, cell::RefCell, hash::Hash, collections:
22

33
use crate::{Node, Edge, Graph, AddEdgeError, ShortestPath};
44

5-
/// Graph parsing from a list of instructions
6-
#[cfg(feature = "from_instruction")]
7-
mod instruction;
8-
95
// Node implementations
106

117
impl<T: Display + Eq + Clone> Node<T> {

src/graph/instruction.rs

Lines changed: 0 additions & 98 deletions
This file was deleted.

src/instruction.rs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
//! # Recognized instructions
2+
//!
3+
//! | Instruction | Description |
4+
//! | - | - |
5+
//! | node: NODE_LABEL | Used to add a node to the graph that is labeled `NODE_LABEL`|
6+
//! | edge: SOURCE_NODE_LABEL WEIGHT TARGET_NODE_LABEL| Used to create an edge that leads from node labeled `SOURCE_NODE_LABEL` to node labeled `TARGET_NODE_LABEL` with a weight of `WEIGHT` |
7+
//! | double_edge: SOURCE_NODE_LABEL WEIGHT TARGET_NODE_LABEL| Used to create a double edge between node labeled `SOURCE_NODE_LABEL` and node labeled `TARGET_NODE_LABEL` with a weight of `WEIGHT` |
8+
//!
9+
//! # Example
10+
//! ```
11+
//! use simple_graph_algorithms::{Graph, graph::instruction::Instructions};
12+
//! # fn main() -> Result<(), String> {
13+
//!
14+
//! // Create a vector that contains instructions.
15+
//! // The idea is that these instructions are read from a file).
16+
//! let mut instruction_strings = Vec::new();
17+
//! instruction_strings.push("node: a");
18+
//! instruction_strings.push("node: b");
19+
//! instruction_strings.push("node: c");
20+
//! instruction_strings.push("node: d");
21+
//! instruction_strings.push("edge: a 3 b");
22+
//! instruction_strings.push("edge: a 4 c");
23+
//! instruction_strings.push("double_edge: b 2 d");
24+
//! instruction_strings.push("edge: c 2 a");
25+
//! instruction_strings.push("edge: c 5 d");
26+
//! instruction_strings.push("edge: b -1 a");
27+
//!
28+
//! // Create parsed instructions from the instruction strings.
29+
//! let instructions: Instructions<String> = Instructions::try_from(&instruction_strings)?;
30+
//!
31+
//! // Construct graph from instructions.
32+
//! let mut graph = Graph::from(instructions);
33+
//!
34+
//! // Do something with the graph...
35+
//! # Ok(())
36+
//! # }
37+
//! ```
38+
use std::{fmt::Display, hash::Hash};
39+
40+
use crate::Graph;
41+
42+
#[cfg(feature = "from_instruction")]
43+
enum Instruction<T: Display + Clone> {
44+
AddNode(T),
45+
AddEdge(i32, T, T),
46+
AddDoubleEdge(i32, T, T),
47+
}
48+
49+
/// A list of instructions used to construct a graph.
50+
#[cfg(feature = "from_instruction")]
51+
pub struct Instructions<T: Display + Clone> {
52+
instructions: Vec<Instruction<T>>,
53+
}
54+
55+
#[cfg(feature = "from_instruction")]
56+
impl<T: Display + Clone + From<String>> TryFrom<&Vec<&str>> for Instructions<T> {
57+
type Error = String;
58+
59+
/// Tries to parse each line of the string as an instruction and
60+
/// returns a list of instructions when the parsing was successful.
61+
///
62+
/// # Example
63+
/// ```
64+
/// use simple_graph_algorithms::{Graph, graph::instruction::Instructions};
65+
/// # fn main() -> Result<(), String> {
66+
///
67+
/// // Create a vector that contains instructions (this should normally be read from a file).
68+
/// let mut instruction_strings = Vec::new();
69+
/// instruction_strings.push("node: a");
70+
/// instruction_strings.push("node: b");
71+
/// instruction_strings.push("node: c");
72+
/// instruction_strings.push("node: d");
73+
/// instruction_strings.push("edge: a 3 b");
74+
/// instruction_strings.push("edge: a 4 c");
75+
/// instruction_strings.push("double_edge: b 2 d");
76+
/// instruction_strings.push("edge: c 2 a");
77+
/// instruction_strings.push("edge: c 5 d");
78+
/// instruction_strings.push("edge: b -1 a");
79+
///
80+
/// // Create parsed instructions from the instruction strings.
81+
/// let instructions: Instructions<String> = Instructions::try_from(&instruction_strings)?;
82+
///
83+
/// // Construct graph from instructions.
84+
/// let mut graph = Graph::from(instructions);
85+
///
86+
/// // Do something with the graph...
87+
/// # Ok(())
88+
/// # }
89+
/// ```
90+
fn try_from(value: &Vec<&str>) -> Result<Self, Self::Error> {//TODO add doc, example + test
91+
let mut instructions = Vec::new();
92+
93+
// Parse lines
94+
for line in value {
95+
try_from_vec_string(line, &mut instructions)?;
96+
}
97+
Ok(Instructions { instructions, })
98+
}
99+
}
100+
101+
#[cfg(feature = "from_instruction")]
102+
impl<T: Display + Clone + From<String>> TryFrom<&Vec<String>> for Instructions<T> {
103+
type Error = String;
104+
105+
/// Tries to parse each line of the string as an instruction and
106+
/// returns a list of instructions when the parsing was successful.
107+
///
108+
/// # Example
109+
/// ```
110+
/// use simple_graph_algorithms::{Graph, graph::instruction::Instructions};
111+
/// # fn main() -> Result<(), String> {
112+
///
113+
/// // Create a vector that contains instructions (this should normally be read from a file).
114+
/// let mut instruction_strings = Vec::new();
115+
/// instruction_strings.push(String::from("node: a"));
116+
/// instruction_strings.push(String::from("node: b"));
117+
/// instruction_strings.push(String::from("node: c"));
118+
/// instruction_strings.push(String::from("node: d"));
119+
/// instruction_strings.push(String::from("edge: a 3 b"));
120+
/// instruction_strings.push(String::from("edge: a 4 c"));
121+
/// instruction_strings.push(String::from("double_edge: b 2 d"));
122+
/// instruction_strings.push(String::from("edge: c 2 a"));
123+
/// instruction_strings.push(String::from("edge: c 5 d"));
124+
/// instruction_strings.push(String::from("edge: b -1 a"));
125+
///
126+
/// // Create parsed instructions from the instruction strings.
127+
/// let instructions: Instructions<String> = Instructions::try_from(&instruction_strings)?;
128+
///
129+
/// // Construct graph from instructions.
130+
/// let mut graph = Graph::from(instructions);
131+
///
132+
/// // Do something with the graph...
133+
/// # Ok(())
134+
/// # }
135+
/// ```
136+
fn try_from(value: &Vec<String>) -> Result<Self, Self::Error> {//TODO add doc, example + test
137+
let mut instructions = Vec::new();
138+
139+
// Parse lines
140+
for line in value {
141+
try_from_vec_string(line, &mut instructions)?;
142+
}
143+
Ok(Instructions { instructions, })
144+
}
145+
}
146+
147+
/// Tries to parse the `line` into an instruction. If successful the instruction is added to the
148+
/// `instructions` vector, if it can not be parsed an error is returned containing the offending string.
149+
fn try_from_vec_string<T: Display + Clone + From<String>>(line: &str, instructions: &mut Vec<Instruction<T>>) -> Result<(), String> {
150+
let split: Vec<&str> = line.split(' ').collect();
151+
match split[0].to_lowercase().as_str() {
152+
"node:" => {
153+
instructions.push(Instruction::AddNode(T::from(split[1].to_string())));
154+
},
155+
"edge:" => {
156+
match split[2].parse::<i32>() {
157+
Ok(weight) => {
158+
instructions.push(Instruction::AddEdge(weight, T::from(split[1].to_string()), T::from(split[3].to_string())));
159+
},
160+
Err(_) => return Err(String::from(split[2])),
161+
};
162+
},
163+
"double_edge:" => {
164+
if let Ok(weight) = split[2].parse::<i32>() {
165+
instructions.push(Instruction::AddDoubleEdge(weight, T::from(split[1].to_string()), T::from(split[3].to_string())));
166+
}
167+
},
168+
_ => (),
169+
}
170+
Ok(())
171+
}
172+
173+
#[cfg(feature = "from_instruction")]
174+
impl<T: Display + Clone + Eq + Hash> From<Instructions<T>> for Graph<T> {
175+
/// Constructs a graph from the list of instructions
176+
fn from(value: Instructions<T>) -> Self {//TODO Add doc, example + test
177+
let mut graph = Graph::new();
178+
for instruction in value.instructions {
179+
match instruction {
180+
Instruction::AddNode(id) => graph.add_node(id),
181+
Instruction::AddEdge(weight, source, target) => graph.add_edge(weight, &source, &target),
182+
Instruction::AddDoubleEdge(weight, source, target) => graph.add_double_edge(weight, &source, &target),
183+
};
184+
}
185+
graph
186+
}
187+
}
188+
189+
#[cfg(test)]
190+
mod tests {
191+
use crate::{Graph, algorithms::bellman_ford};
192+
193+
use super::Instructions;
194+
195+
196+
#[test]
197+
fn graph_from_instructions_string_test() {
198+
let mut instructions = Vec::new();
199+
instructions.push(String::from("node: a"));
200+
instructions.push(String::from("node: b"));
201+
instructions.push(String::from("node: c"));
202+
instructions.push(String::from("node: d"));
203+
instructions.push(String::from("edge: a 3 b"));
204+
instructions.push(String::from("edge: a 4 c"));
205+
instructions.push(String::from("double_edge: b 2 d"));
206+
instructions.push(String::from("edge: c 2 a"));
207+
instructions.push(String::from("edge: c 5 d"));
208+
instructions.push(String::from("edge: b -1 a"));
209+
let instructions: Result<Instructions<String>, String> = Instructions::try_from(&instructions);
210+
assert!(instructions.is_ok());
211+
let mut graph = Graph::from(instructions.unwrap());
212+
println!("{graph}");
213+
let spt = bellman_ford(&mut graph, &String::from("a"));
214+
assert!(spt.is_ok());
215+
println!("{}", spt.as_ref().unwrap().shortest_path(&String::from("d")).unwrap());
216+
assert_eq!(spt.unwrap().shortest_distance(&String::from("d")), Some(5));
217+
}
218+
219+
#[test]
220+
fn graph_from_instructions_str_test() {
221+
let mut instructions = Vec::new();
222+
instructions.push("node: a");
223+
instructions.push("node: b");
224+
instructions.push("node: c");
225+
instructions.push("node: d");
226+
instructions.push("edge: a 3 b");
227+
instructions.push("edge: a 4 c");
228+
instructions.push("double_edge: b 2 d");
229+
instructions.push("edge: c 2 a");
230+
instructions.push("edge: c 5 d");
231+
instructions.push("edge: b -1 a");
232+
let instructions: Result<Instructions<String>, String> = Instructions::try_from(&instructions);
233+
assert!(instructions.is_ok());
234+
let mut graph = Graph::from(instructions.unwrap());
235+
println!("{graph}");
236+
let spt = bellman_ford(&mut graph, &String::from("a"));
237+
assert!(spt.is_ok());
238+
println!("{}", spt.as_ref().unwrap().shortest_path(&String::from("d")).unwrap());
239+
assert_eq!(spt.unwrap().shortest_distance(&String::from("d")), Some(5));
240+
}
241+
242+
}

src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,23 @@
4141
//! Ok(())
4242
//! }
4343
//! ```
44+
//! # Features
45+
//!
46+
//! | Feature | Description |
47+
//! | - | - |
48+
//! | from_instruction | Enables functionality that allows graphs to be parsed from a list of instructions. |
4449
4550
use std::{fmt::{Display, Debug}, rc::Rc, cell::RefCell, collections::HashMap, hash::Hash};
4651
// TODO update graph print to properly print negative edge weights
4752
// TODO add available from_instruction feature to main doc page and explain briefly what it does
4853
// TODO Use Aquamarine crate to create mermaid diagrams to visualize the graphs on which the algorithms are run
4954
/// Contains implementations for the graph to work.
50-
mod graph;
55+
pub mod graph;
5156
/// Contains all algorithms that are implemented in this crate.
5257
pub mod algorithms;
58+
/// Graph parsing from a list of instructions.
59+
#[cfg(feature = "from_instruction")]
60+
pub mod instruction;
5361

5462
/// A node inside the graph
5563
#[derive(Debug, Clone, Eq)]

0 commit comments

Comments
 (0)