use cxx::UniquePtr;
use std::error::Error as StdError;
use std::fmt;
use super::ffi;
pub use super::ffi::{Edge, PathPosition};
#[derive(Debug)]
pub struct Error(pub String);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl StdError for Error {}
pub struct Graph {
#[cfg(not(feature = "docs-only"))]
inner: UniquePtr<ffi::OpaqueGraph>,
#[cfg(feature = "docs-only")]
_inner: (),
}
#[cfg(not(feature = "docs-only"))]
impl Graph {
pub fn load(path: &str) -> Result<Self, Error> {
let graph_ptr = ffi::load_graph(path);
if graph_ptr.is_null() {
Err(Error(format!("Failed to load ODGI graph from '{}'", path)))
} else {
Ok(Graph { inner: graph_ptr })
}
}
pub fn node_count(&self) -> u64 {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::get_node_count(graph_t_ref)
}
pub fn get_path_names(&self) -> Vec<String> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::graph_get_path_names(graph_t_ref)
}
pub fn project(&self, path_name: &str, pos: u64) -> Option<PathPosition> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
let result_ptr = ffi::graph_project(graph_t_ref, path_name, pos);
if result_ptr.is_null() {
None
} else {
Some(result_ptr.as_ref().unwrap().clone())
}
}
pub fn get_node_sequence(&self, node_id: u64) -> String {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::graph_get_node_sequence(graph_t_ref, node_id)
}
pub fn get_node_len(&self, node_id: u64) -> u64 {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::graph_get_node_len(graph_t_ref, node_id)
}
pub fn get_successors(&self, node_id: u64) -> Vec<Edge> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::graph_get_successors(graph_t_ref, node_id)
}
pub fn get_predecessors(&self, node_id: u64) -> Vec<Edge> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::graph_get_predecessors(graph_t_ref, node_id)
}
pub fn get_paths_on_node(&self, node_id: u64) -> Vec<String> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::graph_get_paths_on_node(graph_t_ref, node_id)
}
pub fn get_path_length(&self, path_name: &str) -> Option<u64> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
if !self.get_path_names().iter().any(|p| p == path_name) {
return None;
}
let length = ffi::graph_get_path_length(graph_t_ref, path_name);
Some(length)
}
pub fn get_next_node_on_path(&self, node_id: u64, path_name: &str) -> Option<u64> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
let next_node_id = ffi::graph_get_next_node_on_path(graph_t_ref, path_name, node_id);
if next_node_id >= 0 {
Some(next_node_id as u64)
} else {
None
}
}
pub fn get_paths_on_edge(
&self,
from_node: u64,
from_orientation: bool,
to_node: u64,
to_orientation: bool,
) -> Vec<String> {
let graph_t_ref = ffi::get_graph_t(&self.inner);
ffi::graph_get_paths_on_edge(
graph_t_ref,
from_node,
from_orientation,
to_node,
to_orientation
)
}
}
#[cfg(feature = "docs-only")]
impl Graph {
pub fn load(_path: &str) -> Result<Self, Error> { Ok(Graph { _inner: () }) }
pub fn node_count(&self) -> u64 { 0 }
pub fn get_path_names(&self) -> Vec<String> { vec![] }
pub fn project(&self, _path_name: &str, _pos: u64) -> Option<PathPosition> { None }
pub fn get_node_sequence(&self, _node_id: u64) -> String { String::new() }
pub fn get_node_len(&self, _node_id: u64) -> u64 { 0 }
pub fn get_successors(&self, _node_id: u64) -> Vec<Edge> { vec![] }
pub fn get_predecessors(&self, _node_id: u64) -> Vec<Edge> { vec![] }
pub fn get_paths_on_node(&self, _node_id: u64) -> Vec<String> { vec![] }
pub fn get_path_length(&self, _path_name: &str) -> Option<u64> { None }
pub fn get_paths_on_edge(
&self,
_from_node: u64,
_from_orientation: bool,
_to_node: u64,
_to_orientation: bool,
) -> Vec<String> {
vec![]
}
}
unsafe impl Send for Graph {}
unsafe impl Sync for Graph {}