use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum RelationKind {
#[default]
Callers,
Callees,
Imports,
Exports,
Returns,
}
impl RelationKind {
#[must_use]
pub const fn all() -> &'static [Self] {
&[
Self::Callers,
Self::Callees,
Self::Imports,
Self::Exports,
Self::Returns,
]
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Callers => "callers",
Self::Callees => "callees",
Self::Imports => "imports",
Self::Exports => "exports",
Self::Returns => "returns",
}
}
#[must_use]
pub fn parse(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"callers" => Some(Self::Callers),
"callees" => Some(Self::Callees),
"imports" => Some(Self::Imports),
"exports" => Some(Self::Exports),
"returns" => Some(Self::Returns),
_ => None,
}
}
#[must_use]
pub const fn is_call_relation(self) -> bool {
matches!(self, Self::Callers | Self::Callees)
}
#[must_use]
pub const fn is_boundary_relation(self) -> bool {
matches!(self, Self::Imports | Self::Exports)
}
}
impl fmt::Display for RelationKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_as_str() {
assert_eq!(RelationKind::Callers.as_str(), "callers");
assert_eq!(RelationKind::Callees.as_str(), "callees");
assert_eq!(RelationKind::Imports.as_str(), "imports");
assert_eq!(RelationKind::Exports.as_str(), "exports");
assert_eq!(RelationKind::Returns.as_str(), "returns");
}
#[test]
fn test_parse() {
assert_eq!(RelationKind::parse("callers"), Some(RelationKind::Callers));
assert_eq!(RelationKind::parse("CALLEES"), Some(RelationKind::Callees));
assert_eq!(RelationKind::parse("Imports"), Some(RelationKind::Imports));
assert_eq!(RelationKind::parse("unknown"), None);
}
#[test]
fn test_display() {
assert_eq!(format!("{}", RelationKind::Callers), "callers");
assert_eq!(format!("{}", RelationKind::Returns), "returns");
}
#[test]
fn test_serde_roundtrip() {
for kind in RelationKind::all() {
let json = serde_json::to_string(kind).unwrap();
let deserialized: RelationKind = serde_json::from_str(&json).unwrap();
assert_eq!(*kind, deserialized);
}
}
#[test]
fn test_classification() {
assert!(RelationKind::Callers.is_call_relation());
assert!(RelationKind::Callees.is_call_relation());
assert!(!RelationKind::Imports.is_call_relation());
assert!(RelationKind::Imports.is_boundary_relation());
assert!(RelationKind::Exports.is_boundary_relation());
assert!(!RelationKind::Callers.is_boundary_relation());
}
}