use core::fmt;
use core::hash::{Hash, Hasher};
use crate::node::NodeIndex;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EdgeIndex {
pub(crate) index: usize,
pub(crate) generation: u32,
}
impl EdgeIndex {
#[inline]
pub(crate) fn new(index: usize, generation: u32) -> Self {
Self { index, generation }
}
#[inline]
pub fn index(&self) -> usize {
self.index
}
#[inline]
pub fn generation(&self) -> u32 {
self.generation
}
#[inline]
#[allow(dead_code)]
pub(crate) fn is_valid(&self) -> bool {
self.index != usize::MAX
}
#[inline]
#[allow(dead_code)]
pub(crate) fn invalid() -> Self {
Self {
index: usize::MAX,
generation: 0,
}
}
}
impl fmt::Debug for EdgeIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "EdgeIndex({}, {})", self.index, self.generation)
}
}
impl Hash for EdgeIndex {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
self.generation.hash(state);
}
}
pub struct EdgeRef<'a, E> {
pub index: EdgeIndex,
pub source: NodeIndex,
pub target: NodeIndex,
pub data: &'a E,
}
impl<'a, E> EdgeRef<'a, E> {
#[inline]
pub fn new(index: EdgeIndex, source: NodeIndex, target: NodeIndex, data: &'a E) -> Self {
Self {
index,
source,
target,
data,
}
}
#[inline]
pub fn index(&self) -> EdgeIndex {
self.index
}
#[inline]
pub fn source(&self) -> NodeIndex {
self.source
}
#[inline]
pub fn target(&self) -> NodeIndex {
self.target
}
#[inline]
pub fn data(&self) -> &'a E {
self.data
}
#[inline]
pub fn endpoints(&self) -> (NodeIndex, NodeIndex) {
(self.source, self.target)
}
}
impl<'a, E> Clone for EdgeRef<'a, E> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, E> Copy for EdgeRef<'a, E> {}
impl<'a, E> fmt::Debug for EdgeRef<'a, E>
where
E: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EdgeRef")
.field("index", &self.index)
.field("source", &self.source)
.field("target", &self.target)
.field("data", self.data)
.finish()
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde",
serde(bound(serialize = "E: Serialize", deserialize = "E: Deserialize<'de>"))
)]
#[repr(align(64))]
pub(crate) struct EdgeStorage<E> {
pub source: NodeIndex,
pub target: NodeIndex,
pub data: Option<E>,
pub generation: u32,
}
impl<E> Clone for EdgeStorage<E> {
fn clone(&self) -> Self {
Self {
source: self.source,
target: self.target,
data: None, generation: self.generation,
}
}
}
impl<E> EdgeStorage<E> {
#[inline]
pub(crate) fn new(source: NodeIndex, target: NodeIndex, data: E, generation: u32) -> Self {
Self {
source,
target,
data: Some(data),
generation,
}
}
#[inline]
#[allow(dead_code)]
pub(crate) fn deleted(source: NodeIndex, target: NodeIndex, generation: u32) -> Self {
Self {
source,
target,
data: None,
generation,
}
}
#[inline]
pub(crate) fn is_occupied(&self) -> bool {
self.data.is_some()
}
#[inline]
pub(crate) fn data(&self) -> Option<&E> {
self.data.as_ref()
}
#[inline]
#[allow(dead_code)]
pub(crate) fn data_mut(&mut self) -> Option<&mut E> {
self.data.as_mut()
}
#[inline]
#[allow(dead_code)]
pub(crate) fn endpoints(&self) -> (NodeIndex, NodeIndex) {
(self.source, self.target)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_edge_index_creation() {
let idx = EdgeIndex::new(42, 1);
assert_eq!(idx.index(), 42);
assert_eq!(idx.generation(), 1);
assert!(idx.is_valid());
}
#[test]
fn test_edge_index_invalid() {
let idx = EdgeIndex::invalid();
assert!(!idx.is_valid());
assert_eq!(idx.index(), usize::MAX);
}
#[test]
fn test_edge_ref() {
let source = NodeIndex::new(0, 1);
let target = NodeIndex::new(1, 1);
let edge_idx = EdgeIndex::new(0, 1);
let edge_ref = EdgeRef::new(edge_idx, source, target, &42.0);
assert_eq!(edge_ref.index(), edge_idx);
assert_eq!(edge_ref.source(), source);
assert_eq!(edge_ref.target(), target);
assert_eq!(*edge_ref.data(), 42.0);
assert_eq!(edge_ref.endpoints(), (source, target));
}
#[test]
fn test_edge_storage() {
let source = NodeIndex::new(0, 1);
let target = NodeIndex::new(1, 1);
let edge = EdgeStorage::new(source, target, 42.0, 1);
assert!(edge.is_occupied());
assert_eq!(edge.data(), Some(&42.0));
let deleted: EdgeStorage<f64> = EdgeStorage::deleted(source, target, 1);
assert!(!deleted.is_occupied());
assert_eq!(deleted.data(), None);
}
}