@@ -10,6 +10,18 @@ use core::iter;
1010#[ cfg( not( feature = "no_std" ) ) ]
1111use std:: iter;
1212
13+ #[ cfg( feature = "no_std" ) ]
14+ use core:: fmt:: Debug ;
15+
16+ #[ cfg( not( feature = "no_std" ) ) ]
17+ use std:: fmt:: Debug ;
18+
19+ #[ cfg( feature = "no_std" ) ]
20+ use core:: cell:: RefCell ;
21+
22+ #[ cfg( not( feature = "no_std" ) ) ]
23+ use std:: cell:: RefCell ;
24+
1325#[ cfg( feature = "no_std" ) ]
1426extern crate alloc;
1527#[ cfg( feature = "no_std" ) ]
@@ -19,27 +31,70 @@ use alloc::vec;
1931#[ cfg( feature = "no_std" ) ]
2032use alloc:: vec:: Vec ;
2133
34+ #[ cfg( feature = "dot" ) ]
35+ use super :: SEED ;
36+
2237#[ derive( Clone , Debug , PartialEq ) ]
2338/// Graph operation error
2439pub enum GraphErr {
40+ /// There is no vertex with the given id in the graph
2541 NoSuchVertex ,
42+
43+ /// There is no such edge in the graph
2644 NoSuchEdge ,
45+
46+ /// Could not add an edge to the graph
2747 CannotAddEdge ,
28- InvalidWeight
48+
49+ /// The given weight is invalid
50+ InvalidWeight ,
51+
52+ #[ cfg( feature = "dot" ) ]
53+ /// Could not render .dot file
54+ CouldNotRender ,
55+
56+ #[ cfg( feature = "dot" ) ]
57+ /// The name of the graph is invalid. Check [this](https://docs.rs/dot/0.1.1/dot/struct.Id.html#method.new)
58+ /// out for more information.
59+ InvalidGraphName ,
60+
61+ #[ cfg( feature = "dot" ) ]
62+ /// The name of the given label is invalid. Check [this](https://docs.rs/dot/0.1.1/dot/struct.Id.html#method.new)
63+ /// out for more information.
64+ InvalidLabel ,
2965}
3066
3167#[ derive( Clone , Debug ) ]
3268/// Graph data-structure
33- pub struct Graph < T > {
69+ pub struct Graph < T >
70+ where T : Clone + Debug
71+ {
72+ /// Mapping of vertex ids and vertex values
3473 vertices : HashMap < VertexId , ( T , VertexId ) > ,
74+
75+ /// Mapping between edges and weights
3576 edges : HashMap < Edge , f32 > ,
77+
78+ /// Set containing the roots of the graph
3679 roots : HashSet < VertexId > ,
80+
81+ /// Set containing the tips of the graph
3782 tips : HashSet < VertexId > ,
83+
84+ /// Mapping between vertex ids and inbound edges
3885 inbound_table : HashMap < VertexId , Vec < VertexId > > ,
86+
87+ /// Mapping between vertex ids and outbound edges
3988 outbound_table : HashMap < VertexId , Vec < VertexId > > ,
89+
90+ #[ cfg( feature = "dot" ) ]
91+ /// Mapping between vertices and labels
92+ labels : RefCell < HashMap < VertexId , String > > ,
4093}
4194
42- impl < T > Graph < T > {
95+ impl < T > Graph < T >
96+ where T : Clone + Debug
97+ {
4398 /// Creates a new graph.
4499 ///
45100 /// ## Example
@@ -59,6 +114,9 @@ impl<T> Graph<T> {
59114 tips : HashSet :: new ( ) ,
60115 inbound_table : HashMap :: new ( ) ,
61116 outbound_table : HashMap :: new ( ) ,
117+
118+ #[ cfg( feature = "dot" ) ]
119+ labels : RefCell :: new ( HashMap :: new ( ) ) ,
62120 }
63121 }
64122
@@ -84,6 +142,9 @@ impl<T> Graph<T> {
84142 tips : HashSet :: with_capacity ( capacity) ,
85143 inbound_table : HashMap :: with_capacity ( capacity) ,
86144 outbound_table : HashMap :: with_capacity ( capacity) ,
145+
146+ #[ cfg( feature = "dot" ) ]
147+ labels : RefCell :: new ( HashMap :: with_capacity ( capacity) ) ,
87148 }
88149 }
89150
@@ -145,6 +206,9 @@ impl<T> Graph<T> {
145206 self . vertices . reserve ( additional) ;
146207 self . outbound_table . reserve ( additional) ;
147208 self . inbound_table . reserve ( additional) ;
209+
210+ #[ cfg( feature = "dot" ) ]
211+ self . labels . borrow_mut ( ) . reserve ( additional) ;
148212 }
149213
150214 /// Shrinks the capacity of the graph as much as possible.
@@ -170,6 +234,9 @@ impl<T> Graph<T> {
170234 self . outbound_table . shrink_to_fit ( ) ;
171235 self . inbound_table . shrink_to_fit ( ) ;
172236
237+ #[ cfg( feature = "dot" ) ]
238+ self . labels . borrow_mut ( ) . shrink_to_fit ( ) ;
239+
173240 // Calculate additional value for edges vector
174241 // such that it is always n^2 where n is the
175242 // number of vertices that are currently placed
@@ -196,7 +263,7 @@ impl<T> Graph<T> {
196263 pub fn add_vertex ( & mut self , item : T ) -> VertexId {
197264 let id = VertexId :: random ( ) ;
198265
199- self . vertices . insert ( id. clone ( ) , ( item, id. clone ( ) ) ) ;
266+ self . vertices . insert ( id, ( item, id) ) ;
200267 self . roots . insert ( id) ;
201268 self . tips . insert ( id) ;
202269
@@ -641,7 +708,7 @@ impl<T> Graph<T> {
641708 /// assert_eq!(mapped.fetch(&id1).unwrap(), &3);
642709 /// assert_eq!(mapped.fetch(&id2).unwrap(), &4);
643710 /// ```
644- pub fn map < R > ( & self , fun : impl Fn ( & T ) -> R ) -> Graph < R > {
711+ pub fn map < R : Clone + Debug > ( & self , fun : impl Fn ( & T ) -> R ) -> Graph < R > {
645712 let mut graph: Graph < R > = Graph :: new ( ) ;
646713
647714 // Copy edge and vertex information
@@ -655,6 +722,11 @@ impl<T> Graph<T> {
655722 . map ( |( id, ( v, i) ) | ( id. clone ( ) , ( fun ( v) , i. clone ( ) ) ) )
656723 . collect ( ) ;
657724
725+ #[ cfg( feature = "dot" ) ]
726+ {
727+ graph. labels = self . labels . clone ( ) ;
728+ }
729+
658730 graph
659731 }
660732
@@ -1127,6 +1199,7 @@ impl<T> Graph<T> {
11271199 Topo :: new ( self )
11281200 }
11291201
1202+ #[ cfg( feature = "dot" ) ]
11301203 /// Creates a file with the dot representation of the graph.
11311204 /// This method requires the `dot` feature.
11321205 ///
@@ -1152,19 +1225,85 @@ impl<T> Graph<T> {
11521225 /// graph.add_edge(&v1, &v4).unwrap();
11531226 /// graph.add_edge(&v5, &v6).unwrap();
11541227 ///
1155- /// Graph::<String>::to_dot(& graph, &mut f);
1228+ /// assert!( graph.to_dot("example1" , &mut f).is_ok() );
11561229 /// ```
1157- #[ cfg( feature = "dot" ) ]
1158- pub fn to_dot ( graph : & Graph < impl :: std:: fmt:: Display + Clone + Ord > , output : & mut impl :: std:: io:: Write ) {
1159- let vertices = graph. vertex_hm_ref ( ) ;
1160- let edges : Vec < ( _ , _ ) > = graph. edges_hm_ref ( ) . unwrap ( ) . iter ( ) . map ( |( w, _) | {
1230+ pub fn to_dot ( & self , graph_name : & str , output : & mut impl :: std:: io:: Write ) -> Result < ( ) , GraphErr > {
1231+ let edges : Vec < ( _ , _ ) > = self . edges . iter ( ) . map ( |( w, _) | {
11611232 let inbound = w. inbound ( ) ;
11621233 let outbound = w. outbound ( ) ;
11631234
1164- ( vertices . get ( inbound) . unwrap ( ) . 0 . clone ( ) , vertices . get ( outbound) . unwrap ( ) . 0 . clone ( ) )
1235+ ( self . label ( inbound) . unwrap ( ) , self . label ( outbound) . unwrap ( ) )
11651236 } ) . collect ( ) ;
11661237
1167- dot:: render ( & crate :: dot:: Edges ( edges) , output) . unwrap ( )
1238+ let edges = crate :: dot:: Edges :: new ( edges, graph_name) ?;
1239+ dot:: render ( & edges, output) . map_err ( |_| GraphErr :: CouldNotRender )
1240+ }
1241+
1242+ #[ cfg( feature = "dot" ) ]
1243+ /// Labels the vertex with the given id. Returns the old label if successful.
1244+ ///
1245+ /// ## Example
1246+ /// ```rust
1247+ /// use graphlib::{Graph, VertexId};
1248+ ///
1249+ /// let mut graph: Graph<usize> = Graph::new();
1250+ /// let random_id = VertexId::random();
1251+ ///
1252+ /// let v1 = graph.add_vertex(0);
1253+ /// let v2 = graph.add_vertex(1);
1254+ /// let v3 = graph.add_vertex(2);
1255+ ///
1256+ /// assert!(graph.label_vertex(&v1, "V1").is_ok());
1257+ /// assert!(graph.label_vertex(&v2, "V2").is_ok());
1258+ /// assert!(graph.label_vertex(&v3, "V3").is_ok());
1259+ /// assert!(graph.label_vertex(&random_id, "will fail").is_err());
1260+ /// ```
1261+ pub fn label_vertex ( & mut self , vertex_id : & VertexId , label : & str ) -> Result < String , GraphErr > {
1262+ // Check label validity
1263+ let _ = dot:: Id :: new ( label. to_owned ( ) ) . map_err ( |_| GraphErr :: InvalidLabel ) ?;
1264+
1265+ if self . vertices . get ( vertex_id) . is_none ( ) {
1266+ return Err ( GraphErr :: NoSuchVertex ) ;
1267+ }
1268+
1269+ let old_label = self . label ( vertex_id) . unwrap ( ) ;
1270+ self . labels . borrow_mut ( ) . insert ( vertex_id. clone ( ) , label. to_owned ( ) ) ;
1271+
1272+ Ok ( old_label)
1273+ }
1274+
1275+ #[ cfg( feature = "dot" ) ]
1276+ /// Retrieves the label of the vertex with the given id.
1277+ ///
1278+ /// This function will return a default label if no label is set. Returns
1279+ /// `None` if there is no vertex associated with the given id in the graph.
1280+ pub fn label ( & self , vertex_id : & VertexId ) -> Option < String > {
1281+ if self . vertices . get ( vertex_id) . is_none ( ) {
1282+ return None ;
1283+ }
1284+
1285+ if let Some ( label) = self . labels . borrow ( ) . get ( vertex_id) {
1286+ return Some ( label. clone ( ) ) ;
1287+ }
1288+
1289+ let bytes = super :: gen_bytes ( ) ;
1290+
1291+ // Take only 8 bytes out of 16
1292+ let to_encode: Vec < u8 > = bytes
1293+ . iter ( )
1294+ . take ( 8 )
1295+ . cloned ( )
1296+ . collect ( ) ;
1297+
1298+ let encoded = hex:: encode ( & to_encode) ;
1299+ let label = format ! ( "N_{}" , encoded) ;
1300+ assert ! ( dot:: Id :: new( label. to_owned( ) ) . is_ok( ) ) ;
1301+
1302+ {
1303+ self . labels . borrow_mut ( ) . insert ( vertex_id. clone ( ) , label) ;
1304+ }
1305+
1306+ self . labels . borrow ( ) . get ( vertex_id) . map ( |s| s. clone ( ) )
11681307 }
11691308
11701309 fn do_add_edge ( & mut self , a : & VertexId , b : & VertexId , weight : f32 ) -> Result < ( ) , GraphErr > {
@@ -1268,16 +1407,6 @@ impl<T> Graph<T> {
12681407 None => None ,
12691408 }
12701409 }
1271-
1272- /// Returns a reference to the inner edges hash map.
1273- fn edges_hm_ref ( & self ) -> Result < ( & HashMap < Edge , f32 > ) , GraphErr > {
1274- Ok ( & self . edges )
1275- }
1276-
1277- /// Returns a reference to the inner vertices hashmap.
1278- fn vertex_hm_ref ( & self ) -> & HashMap < VertexId , ( T , VertexId ) > {
1279- & self . vertices
1280- }
12811410}
12821411
12831412#[ cfg( test) ]
0 commit comments