use std::fmt;
use std::ops::{Deref, DerefMut};
use crate::graph::{GraphStorage, TraversalGraph};
pub struct Graph<S: GraphStorage = TraversalGraph> {
lock: parking_lot::RwLock<S>,
#[cfg(feature = "persist")]
snapshot_writer: Option<SnapshotWriter<S>>,
}
#[cfg(feature = "persist")]
pub(crate) type SnapshotWriter<S> =
fn(
&S,
&mut dyn std::io::Write,
) -> Result<crate::persist::SnapshotInfo, crate::persist::PersistError>;
pub struct GraphRead<'a, S: GraphStorage = TraversalGraph>(parking_lot::RwLockReadGuard<'a, S>);
pub struct GraphWrite<'a, S: GraphStorage = TraversalGraph>(parking_lot::RwLockWriteGuard<'a, S>);
impl<S: GraphStorage> Graph<S> {
pub fn new(storage: S) -> Self {
Graph {
lock: parking_lot::RwLock::new(storage),
#[cfg(feature = "persist")]
snapshot_writer: None,
}
}
#[cfg_attr(not(feature = "script"), allow(dead_code))]
pub(crate) fn new_like(&self, storage: S) -> Self {
Graph {
lock: parking_lot::RwLock::new(storage),
#[cfg(feature = "persist")]
snapshot_writer: self.snapshot_writer,
}
}
#[cfg(feature = "persist")]
pub(crate) fn snapshot_writer(&self) -> Option<SnapshotWriter<S>> {
self.snapshot_writer
}
pub fn read(&self) -> GraphRead<'_, S> {
GraphRead(self.lock.read())
}
pub fn write(&self) -> GraphWrite<'_, S> {
GraphWrite(self.lock.write())
}
pub fn try_write(&self) -> Option<GraphWrite<'_, S>> {
self.lock.try_write().map(GraphWrite)
}
pub fn get_mut(&mut self) -> &mut S {
self.lock.get_mut()
}
pub fn into_inner(self) -> S {
self.lock.into_inner()
}
}
#[cfg(feature = "persist")]
impl<S: crate::graph::PersistentStorage> Graph<S> {
pub fn new_persistent(storage: S) -> Self {
fn write<S: crate::graph::PersistentStorage>(
storage: &S,
writer: &mut dyn std::io::Write,
) -> Result<crate::persist::SnapshotInfo, crate::persist::PersistError> {
crate::persist::write_snapshot(storage, writer, &crate::persist::WriteOptions::new())
}
Graph {
lock: parking_lot::RwLock::new(storage),
snapshot_writer: Some(write::<S>),
}
}
}
impl<S: GraphStorage + Default> Default for Graph<S> {
fn default() -> Self {
Graph::new(S::default())
}
}
impl<S: GraphStorage> From<S> for Graph<S> {
fn from(storage: S) -> Self {
Graph::new(storage)
}
}
impl<S: GraphStorage> fmt::Debug for Graph<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Graph").finish_non_exhaustive()
}
}
impl<S: GraphStorage> Deref for GraphRead<'_, S> {
type Target = S;
#[inline]
fn deref(&self) -> &S {
&self.0
}
}
impl<S: GraphStorage> Deref for GraphWrite<'_, S> {
type Target = S;
#[inline]
fn deref(&self) -> &S {
&self.0
}
}
impl<S: GraphStorage> DerefMut for GraphWrite<'_, S> {
#[inline]
fn deref_mut(&mut self) -> &mut S {
&mut self.0
}
}
impl<S: GraphStorage> fmt::Debug for GraphRead<'_, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GraphRead").finish_non_exhaustive()
}
}
impl<S: GraphStorage> fmt::Debug for GraphWrite<'_, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GraphWrite").finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::value::PropertyMap;
#[test]
fn new_read_write_try_write_get_mut_into_inner() {
let mut graph = Graph::new(TraversalGraph::new());
assert_eq!(graph.read().vertex_count(), 0);
graph
.write()
.add_vertex(Some("a".into()), vec!["n".into()], PropertyMap::default())
.expect("a writable storage");
{
let first = graph.read();
let second = graph.read();
assert_eq!((first.vertex_count(), second.vertex_count()), (1, 1));
assert!(graph.try_write().is_none(), "readers hold the lock");
}
{
let held = graph.try_write().expect("nobody holds the lock");
assert!(graph.try_write().is_none(), "a writer holds the lock");
drop(held);
}
graph
.get_mut()
.add_vertex(Some("b".into()), vec![], PropertyMap::default())
.expect("a writable storage");
let storage = graph.into_inner();
assert_eq!(storage.vertex_count(), 2);
assert!(storage.get_vertex_by_id("b").is_some());
}
#[test]
fn default_is_empty_and_the_type_is_shareable() {
fn shareable<T: Send + Sync>() {}
shareable::<Graph>();
let graph: Graph = Graph::default();
assert_eq!(graph.read().vertex_count(), 0);
assert_eq!(format!("{graph:?}"), "Graph { .. }");
}
}