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
+ }
0 commit comments