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
//! # Graphster
//!
//! Graphster is a versatile graph data structure library designed for rapid data manipulation,
//! analysis, and processing. It provides a rich set of features to create, manage,
//! and manipulate graphs with various types of nodes and edges, each capable of
//! holding multiple attributes.
//!
//! ## Features
//!
//! - **Nodes and Edges**: Add, remove, and manipulate nodes and edges with ease.
//! - **Attributes**: Each node and edge can have associated attributes with flexible types,
//! including integers, floats, strings, and more.
//! - **Error Handling**: Comprehensive error handling for common graph operations.
//! - **Polars Integration**: Optional support for Polars data frames to import graph data.
//!
//! ## Examples
//!
//! ### Creating a Graph
//!
//! ```rust
//! use graphster::prelude::*;
//! use std::collections::HashMap;
//!
//! let mut graph = DataGraph::new();
//!
//! // Add nodes with attributes
//! graph.add_node(0, Attributes::from([("foo", "bar")])).unwrap();
//! graph.add_node(1, HashMap::from([("bar", "foo")])).unwrap();
//!
//! // Add an edge between nodes
//! graph.add_edge(0, 1, Attributes::from([("weight", 10)])).unwrap();
//!
//! // Get node and edge counts
//! assert_eq!(graph.node_count(), 2);
//! assert_eq!(graph.edge_count(), 1);
//! ```
//!
//! ### Using Attributes
//!
//! ```rust
//! use graphster::prelude::*;
//!
//! let mut attrs = Attributes::new();
//! attrs.insert("key1", "value1");
//! attrs.insert("key2", 42);
//!
//! assert_eq!(attrs.get("key1"), Some(&AttributeValue::String("value1".to_string())));
//! assert_eq!(attrs.get("key2"), Some(&AttributeValue::Int32(42)));
//! ```
//!
//! ### Handling Errors
//!
//! ```rust
//! use graphster::prelude::*;
//!
//! let mut graph = DataGraph::new();
//! match graph.add_edge(0, 1, Attributes::new()) {
//! Ok(_) => println!("Edge added successfully"),
//! Err(e) => println!("Error adding edge: {}", e),
//! }
//! ```
//!
//! ### Using Polars DataFrames
//!
//! ```rust
//! use graphster::prelude::*;
//! use polars::prelude::*;
//!
//! let s0 = Series::new("index", &[0, 1, 2]);
//! let s1 = Series::new("values", &[Some(1), None, Some(3)]);
//! let df = DataFrame::new(vec![s0, s1]).unwrap();
//!
//! let nodes_df = NodesDataFrame::new(&df, "index");
//! let graph = DataGraph::from_nodes_dataframes(nodes_df).unwrap();
//! ```
//!
//! ### Examples of Advanced Operations
//!
//! #### Neighbors
//!
//! Retrieve all neighboring nodes that can be reached by outgoing edges from a specified node.
//!
//! ```rust
//! use graphster::prelude::*;
//!
//! let mut graph = DataGraph::new();
//! graph.add_node(0, Attributes::new()).unwrap();
//! graph.add_node(1, Attributes::new()).unwrap();
//! graph.add_edge(0, 1, Attributes::new()).unwrap();
//!
//! let neighbors: Vec<_> = graph.neighbors(0).unwrap().collect();
//! assert_eq!(neighbors, vec![&1.into()]);
//! ```
//!
//! #### Undirected Neighbors
//!
//! Retrieve all neighboring nodes regardless of the direction of the edges.
//!
//! ```rust
//! use graphster::prelude::*;
//!
//! let mut graph = DataGraph::new();
//! graph.add_node(0, Attributes::new()).unwrap();
//! graph.add_node(1, Attributes::new()).unwrap();
//! graph.add_edge(0, 1, Attributes::new()).unwrap();
//! graph.add_edge(1, 0, Attributes::new()).unwrap();
//!
//! let neighbors: Vec<_> = graph.neighbors_undirected(0).unwrap().collect();
//! assert_eq!(neighbors, vec![&1.into()]);
//! ```
//!
//! #### Edges Connecting Nodes
//!
//! Retrieve all edges connecting a specified source node to a target node.
//!
//! ```rust
//! use graphster::prelude::*;
//!
//! let mut graph = DataGraph::new();
//! graph.add_node(0, Attributes::new()).unwrap();
//! graph.add_node(1, Attributes::new()).unwrap();
//! let edge_index = graph.add_edge(0, 1, Attributes::new()).unwrap();
//!
//! let edges: Vec<_> = graph.edges_connecting(0, 1).unwrap().collect();
//! assert_eq!(edges, vec![&edge_index]);
//! ```
//!
//! #### Undirected Edges Connecting Nodes
//!
//! Retrieve all edges connecting two nodes, regardless of the direction of the edges.
//!
//! ```rust
//! use graphster::prelude::*;
//!
//! let mut graph = DataGraph::new();
//! graph.add_node(0, Attributes::new()).unwrap();
//! graph.add_node(1, Attributes::new()).unwrap();
//! let edge_index_1 = graph.add_edge(0, 1, Attributes::new()).unwrap();
//! let edge_index_2 = graph.add_edge(1, 0, Attributes::new()).unwrap();
//!
//! let edges: Vec<_> = graph.edges_connecting_undirected(0, 1).unwrap().collect();
//! assert_eq!(edges, vec![&edge_index_1, &edge_index_2]);
//! ```
//!
//! ## Optional Features
//!
//! - **Polars**: Enable support for Polars data frames by specifying the `polars` feature.