wolf-graph 0.1.0

Data structures and algorithms for working with graphs with reference or value semantics.
Documentation
use core::fmt;
use std::{str::FromStr, sync::Arc};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize};

use anyhow::Result;

use fuid::Fuid;

/// A unique identifier for a node in a graph.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeID(Arc<String>);

impl NodeID {
    /// Creates a new, random NodeID.
    pub fn new() -> NodeID {
        NodeID(Arc::new(Fuid::new().to_string()))
    }

    /// Creates a new EdgeID from the given string. FUID-compatible strings may
    /// include numerals and upper and lower case English letters.
    pub fn with_str(s: &str) -> Result<NodeID> {
        Ok(NodeID(Arc::new(s.to_string())))
    }

    /// Creates a new NodeID from the given u128.
    pub fn with_u128(i: u128) -> NodeID {
        NodeID(Arc::new(i.to_string()))
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }
}

impl Default for NodeID {
    fn default() -> Self {
        Self::new()
    }
}

impl fmt::Display for NodeID {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl fmt::Debug for NodeID {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("NodeID")
            .field(&self.to_string())
            .finish()
    }
}

impl FromStr for NodeID {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self> {
        NodeID::with_str(s)
    }
}

impl From<&str> for NodeID {
    fn from(val: &str) -> Self {
        NodeID::with_str(val).unwrap()
    }
}

impl From<String> for NodeID {
    fn from(val: String) -> Self {
        NodeID::with_str(&val).unwrap()
    }
}

impl From<NodeID> for String {
    fn from(val: NodeID) -> Self {
        val.to_string()
    }
}

impl From<&NodeID> for String {
    fn from(val: &NodeID) -> Self {
        val.to_string()
    }
}

impl From<u128> for NodeID {
    fn from(val: u128) -> Self {
        NodeID::with_u128(val)
    }
}

impl AsRef<NodeID> for NodeID {
    fn as_ref(&self) -> &NodeID {
        self
    }
}

#[cfg(feature = "serde")]
impl Serialize for NodeID {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&self.to_string())
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for NodeID {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let s = String::deserialize(deserializer)?;
        NodeID::with_str(&s).map_err(de::Error::custom)
    }
}

/// A unique identifier for an edge in a graph.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EdgeID(Arc<String>);

impl EdgeID {
    /// Creates a new, random EdgeID.
    pub fn new() -> EdgeID {
        EdgeID(Arc::new(Fuid::new().to_string()))
    }

    /// Creates a new EdgeID from the given string. FUID-compatible strings may
    /// include numerals and upper and lower case English letters.
    pub fn with_str(s: &str) -> Result<EdgeID> {
        Ok(EdgeID(Arc::new(s.to_string())))
    }

    /// Creates a new EdgeID from the given u128.
    pub fn with_u128(i: u128) -> EdgeID {
        EdgeID(Arc::new(i.to_string()))
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }
}

impl Default for EdgeID {
    fn default() -> Self {
        Self::new()
    }
}

impl fmt::Display for EdgeID {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl fmt::Debug for EdgeID {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("EdgeID")
            .field(&self.to_string())
            .finish()
    }
}

impl FromStr for EdgeID {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self> {
        EdgeID::with_str(s)
    }
}

impl From<&str> for EdgeID {
    fn from(val: &str) -> Self {
        EdgeID::with_str(val).unwrap()
    }
}

impl From<String> for EdgeID {
    fn from(val: String) -> Self {
        EdgeID::with_str(&val).unwrap()
    }
}

impl From<EdgeID> for String {
    fn from(val: EdgeID) -> Self {
        val.to_string()
    }
}

impl From<&EdgeID> for String {
    fn from(val: &EdgeID) -> Self {
        val.to_string()
    }
}

impl From<u128> for EdgeID {
    fn from(val: u128) -> Self {
        EdgeID::with_u128(val)
    }
}

impl AsRef<EdgeID> for EdgeID {
    fn as_ref(&self) -> &EdgeID {
        self
    }
}

#[cfg(feature = "serde")]
impl Serialize for EdgeID {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&self.to_string())
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for EdgeID {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let s = String::deserialize(deserializer)?;
        EdgeID::with_str(&s).map_err(de::Error::custom)
    }
}

#[cfg(test)]

mod tests {
    use super::*;

    #[test]
    fn test_node_id() -> Result<(), Box<dyn std::error::Error>> {
        let a = "6fTiplVKIi6bJFe8rTXPcu";
        let b = "5z1JeaxqBJ4Y3pEXh2B8Sj";

        let fa = NodeID::with_str(a)?;
        let fb = NodeID::with_str(b)?;

        assert_eq!(fa.to_string(), a);
        assert_eq!(fb.to_string(), b);

        assert_ne!(NodeID::new(), fa);
        assert_ne!(NodeID::new(), fb);

        let _: NodeID = "A".into();
        let _: NodeID = "A".to_string().into();
        let _: NodeID = 1.into();

        Ok(())
    }

    #[cfg(feature = "serde")]
    #[test]
    fn test_node_id_serde() -> Result<(), Box<dyn std::error::Error>> {
        use serde_json::{to_string, from_str};

        let a = NodeID::new();
        let b = to_string(&a)?;
        // println!("{}", b);
        let c: NodeID = from_str(&b)?;
        assert_eq!(a, c);

        Ok(())
    }

    #[test]
    fn test_edge_id() -> Result<(), Box<dyn std::error::Error>> {
        let a = "6fTiplVKIi6bJFe8rTXPcu";
        let b = "5z1JeaxqBJ4Y3pEXh2B8Sj";

        let fa = EdgeID::with_str(a)?;
        let fb = EdgeID::with_str(b)?;

        assert_eq!(fa.to_string(), a);
        assert_eq!(fb.to_string(), b);

        assert_ne!(EdgeID::new(), fa);
        assert_ne!(EdgeID::new(), fb);

        let _: EdgeID = "A".into();
        let _: EdgeID = "A".to_string().into();
        let _: EdgeID = 1.into();

        Ok(())
    }

    #[cfg(feature = "serde")]
    #[test]
    fn test_edge_id_serde() -> Result<(), Box<dyn std::error::Error>> {
        use serde_json::{to_string, from_str};

        let a = EdgeID::new();
        let b = to_string(&a)?;
        // println!("{}", b);
        let c: EdgeID = from_str(&b)?;
        assert_eq!(a, c);

        Ok(())
    }
}