hypergraphx 0.0.5

A hypergraph library for Rust, based on the Python library of the same name.
Documentation
use std::{
    any::{Any, TypeId, type_name},
    hash::Hash,
    mem,
    // slice::{Iter, IterMut},
};

use dyn_clone::DynClone;
/*
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Directive<T> {
    Symmetric(Vec<T>),
    Asymmetric { source: Vec<T>, target: Vec<T> },
}

impl<T> Default for Directive<T> {
    fn default() -> Self {
        Self::Symmetric(Vec::new())
    }
}

pub(crate) struct DirIter<'a, T> {
    pub(crate) sym: Option<Iter<'a, T>>,
    pub(crate) asym_source: Option<Iter<'a, T>>,
    pub(crate) asym_target: Option<Iter<'a, T>>,
}

impl<'a, T> DirIter<'a, T> {
    fn source(&self) -> &Option<Iter<'a, T>> {
        &self.asym_source
    }
    fn target(&self) -> &Option<Iter<'a, T>> {
        &self.asym_target
    }
}

pub(crate) struct DirIterMut<'a, T> {
    pub(crate) sym: Option<IterMut<'a, T>>,
    pub(crate) asym_source: Option<IterMut<'a, T>>,
    pub(crate) asym_target: Option<IterMut<'a, T>>,
}

impl<'a, T> DirIterMut<'a, T> {
    fn source(&self) -> &Option<IterMut<'a, T>> {
        &self.asym_source
    }
    fn target(&self) -> &Option<IterMut<'a, T>> {
        &self.asym_target
    }
}

impl<'a> Iterator for DirIter<'a, usize> {
    type Item = &'a usize;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(iter) = self.sym.as_mut() {
            iter.next()
        } else if let Some(iter) = self.asym_source.as_mut() {
            iter.next()
        } else if let Some(iter) = self.asym_target.as_mut() {
            iter.next()
        } else {
            None
        }
    }
}

impl<'a> Iterator for DirIterMut<'a, usize> {
    type Item = &'a mut usize;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(iter) = self.sym.as_mut() {
            iter.next()
        } else if let Some(iter) = self.asym_source.as_mut() {
            iter.next()
        } else if let Some(iter) = self.asym_target.as_mut() {
            iter.next()
        } else {
            None
        }
    }
}

impl<T> Directive<T> {
    pub fn new_symmetric(vec: Vec<T>) -> Self {
        Directive::Symmetric(vec)
    }

    pub fn new_asymmetric(source: Vec<T>, target: Vec<T>) -> Self {
        Directive::Asymmetric { source, target }
    }

    pub fn iter(&self) -> DirIter<T> {
        match self {
            Directive::Symmetric(vec) => DirIter {
                // inner: self,
                sym: Some(vec.iter()),
                asym_source: None,
                asym_target: None,
            },
            Directive::Asymmetric { source, target } => DirIter {
                // inner: self,
                sym: None,
                asym_source: Some(source.iter()),
                asym_target: Some(target.iter()),
            },
        }
    }

    pub fn iter_mut(&mut self) -> DirIterMut<T> {
        match self {
            Directive::Symmetric(vec) => DirIterMut {
                // inner: self,
                sym: Some(vec.iter_mut()),
                asym_source: None,
                asym_target: None,
            },
            Directive::Asymmetric { source, target } => DirIterMut {
                // inner: self,
                sym: None,
                asym_source: Some(source.iter_mut()),
                asym_target: Some(target.iter_mut()),
            },
        }
    }

    pub fn retain<F>(&mut self, mut f: F)
    where
        F: FnMut(&T) -> bool,
    {
        match self {
            Directive::Symmetric(vec) => vec.retain(&mut f),
            Directive::Asymmetric { source, target } => {
                source.retain(&mut f);
                target.retain(&mut f);
            }
        }
    }

    pub fn push(&mut self, item: T) {
        assert!(
            matches!(self, Directive::Symmetric(_)),
            "Cannot push to asymmetric directive"
        );
        match self {
            Directive::Symmetric(vec) => vec.push(item),
            _ => {
                unreachable!()
            }
        }
    }

    pub fn push_source(&mut self, item: T) {
        assert!(
            matches!(self, Directive::Asymmetric { .. }),
            "Cannot push source to symmetric directive"
        );
        match self {
            Directive::Symmetric(_) => unreachable!(),
            Directive::Asymmetric { source, target: _ } => source.push(item),
        }
    }
    pub fn push_target(&mut self, item: T) {
        assert!(
            matches!(self, Directive::Asymmetric { .. }),
            "Cannot push target to symmetric directive"
        );
        match self {
            Directive::Symmetric(_) => unreachable!(),
            Directive::Asymmetric { source: _, target } => target.push(item),
        }
    }
}
 */
pub trait MultiplexEdgeType: DynClone + Any {
    fn type_name(&self) -> &'static str;
}

// impl<T: Clone + 'static> MultiplexEdgeType for T {
//     fn type_name(&self) -> &'static str {
//         type_name::<T>()
//     }
// }

impl<T: Any + Clone> MultiplexEdgeType for T {
    fn type_name(&self) -> &'static str {
        type_name::<T>()
    }
}

pub struct UndirectedMultiplexEdge {
    pub(crate) weight: Box<dyn MultiplexEdgeType>,
    pub(crate) weight_type: TypeId,
    pub(crate) nodes: Vec<usize>,
}

pub struct DirectedMultiplexEdge {
    pub(crate) weight: Box<dyn MultiplexEdgeType>,
    pub(crate) weight_type: TypeId,
    pub(crate) source: Vec<usize>,
    pub(crate) target: Vec<usize>,
}

impl DirectedMultiplexEdge {
    pub fn remap(&self, map: &Vec<Option<usize>>) -> Option<Self> {
        if self.source.iter().any(|&s| map[s].is_none())
            || self.target.iter().any(|&t| map[t].is_none())
        {
            return None;
        }
        let source = self.source.iter().map(|&s| map[s].unwrap()).collect();
        let target = self.target.iter().map(|&t| map[t].unwrap()).collect();
        Some(DirectedMultiplexEdge {
            weight: dyn_clone::clone_box(&*self.weight),
            weight_type: self.weight_type,
            source,
            target,
        })
    }
}

impl UndirectedMultiplexEdge {
    pub fn remap(&self, map: &Vec<Option<usize>>) -> Option<Self> {
        if self.nodes.iter().any(|&s| map[s].is_none()) {
            return None;
        }
        let nodes = self.nodes.iter().map(|&s| map[s].unwrap()).collect();
        Some(UndirectedMultiplexEdge {
            weight: dyn_clone::clone_box(&*self.weight),
            weight_type: self.weight_type,
            nodes,
        })
    }
}

impl Clone for DirectedMultiplexEdge {
    fn clone(&self) -> Self {
        Self {
            weight: dyn_clone::clone_box(&*self.weight),
            weight_type: self.weight_type,
            source: self.source.clone(),
            target: self.target.clone(),
        }
    }
}

impl PartialEq for DirectedMultiplexEdge {
    fn eq(&self, other: &Self) -> bool {
        self.weight_type == other.weight_type
            && self.source == other.source
            && self.target == other.target
            && unsafe { mem::transmute::<_, &[u8]>(&*self.weight) }
                == unsafe { mem::transmute::<_, &[u8]>(&*other.weight) }
    }
}

impl Eq for DirectedMultiplexEdge {}

impl Hash for DirectedMultiplexEdge {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.weight_type.hash(state);
        self.source.hash(state);
        self.target.hash(state);
        unsafe { mem::transmute::<_, &[u8]>(&*self.weight) }.hash(state);
    }
}

impl Clone for UndirectedMultiplexEdge {
    fn clone(&self) -> Self {
        Self {
            weight: dyn_clone::clone_box(&*self.weight),
            weight_type: self.weight_type,
            nodes: self.nodes.clone(),
        }
    }
}

impl PartialEq for UndirectedMultiplexEdge {
    fn eq(&self, other: &Self) -> bool {
        self.weight_type == other.weight_type
            && self.nodes == other.nodes
            && unsafe { mem::transmute::<_, &[u8]>(&*self.weight) }
                == unsafe { mem::transmute::<_, &[u8]>(&*other.weight) }
    }
}
impl Eq for UndirectedMultiplexEdge {}

impl Hash for UndirectedMultiplexEdge {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.weight_type.hash(state);
        self.nodes.hash(state);
        unsafe { mem::transmute::<_, &[u8]>(&*self.weight) }.hash(state);
    }
}

#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub enum MultiplexEdge<'a> {
    Directed(usize, &'a DirectedMultiplexEdge),
    Undirected(usize, &'a UndirectedMultiplexEdge),
}