wolf-graph 0.1.0

Data structures and algorithms for working with graphs with reference or value semantics.
Documentation
use std::borrow::Cow;

#[cfg(feature = "serde")]
use serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer}};

use crate::{EdgeID, NodeID};

#[derive(Clone, Debug, PartialEq)]
pub struct Edge<EData>
where
    EData: Clone + 'static,
{
    pub id: EdgeID,
    pub source: NodeID,
    pub target: NodeID,
    pub data: Cow<'static, EData>,
}

impl<EData> Edge<EData>
where
    EData: Clone + 'static,
{
    pub fn new(id: EdgeID, source: NodeID, target: NodeID, data: EData) -> Self {
        Edge {
            id,
            source,
            target,
            data: Cow::Owned(data),
        }
    }

    pub fn setting_data(&self, data: EData) -> Self {
        Edge {
            id: self.id.clone(),
            source: self.source.clone(),
            target: self.target.clone(),
            data: Cow::Owned(data),
        }
    }
}

#[cfg(feature = "serde")]
impl<EData> Serialize for Edge<EData>
where
    EData: Clone + Serialize + 'static,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if std::mem::size_of::<EData>() == 0 {
            (&self.id, &self.source, &self.target).serialize(serializer)
        } else {
            (&self.id, &self.source, &self.target, &self.data).serialize(serializer)
        }
    }
}

#[cfg(feature = "serde")]
impl<'de, EData> Deserialize<'de> for Edge<EData>
where
    EData: Clone + Deserialize<'de> + 'static + Default,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        if std::mem::size_of::<EData>() == 0 {
            let (id, source, target) = <(EdgeID, NodeID, NodeID)>::deserialize(deserializer)?;
            Ok(Edge::new(id, source, target, EData::default()))
        } else {
            let (id, source, target, data) = <(EdgeID, NodeID, NodeID, EData)>::deserialize(deserializer)?;
            Ok(Edge::new(id, source, target, data))
        }
    }
}

#[cfg(all(test, feature = "serde", feature = "serde_json"))]
mod tests {
    use crate::{eid, nid};

    use super::*;
    use serde_test::{assert_tokens, Token};
    use std::borrow::Cow;

    #[test]
    fn edge_with_data_round_trip() {
        let edge: Edge<i32> = Edge::<i32> {
            id: eid!("EdgeID"),
            source: nid!("Source"),
            target: nid!("Target"),
            data: Cow::Owned(42),
        };

        assert_tokens(
            &edge,
            &[
                Token::Tuple { len: 4 },
                Token::Str("EdgeID"),
                Token::Str("Source"),
                Token::Str("Target"),
                Token::I32(42),
                Token::TupleEnd,
            ],
        );

        let json = serde_json::to_string(&edge).unwrap();
        assert_eq!(json, r#"["EdgeID","Source","Target",42]"#);

        let deserialized_edge: Edge<i32> = serde_json::from_str(&json).unwrap();
        assert_eq!(deserialized_edge, edge);
    }

    #[test]
    fn edge_with_unit_data_round_trip() {
        let edge: Edge<()> = Edge {
            id: eid!("EdgeID"),
            source: nid!("Source"),
            target: nid!("Target"),
            data: Cow::Owned(()),
        };

        assert_tokens(
            &edge,
            &[
                Token::Tuple { len: 3 },
                Token::Str("EdgeID"),
                Token::Str("Source"),
                Token::Str("Target"),
                Token::TupleEnd,
            ],
        );

        let json = serde_json::to_string(&edge).unwrap();
        assert_eq!(json, r#"["EdgeID","Source","Target"]"#);

        let deserialized_edge: Edge<()> = serde_json::from_str(&json).unwrap();
        assert_eq!(deserialized_edge, edge);
    }
}