use std::borrow::Cow;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum EdgeKindError {
#[error("Custom EdgeKind label must not be empty")]
EmptyLabel,
#[error("Custom EdgeKind label must not contain ':' (got {0:?})")]
LabelContainsColon(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum EdgeKind {
CallsFunction,
CalledByFunction,
Implements,
UsesType,
Derives,
ModuleContains,
ReExports,
RaisesError,
Configures,
TestedBy,
TestUsesFixture,
CoOccursInTest,
Documents,
ReferencesConcept,
Aliases,
ErrorDescribes,
Contains,
Imports,
Exports,
Calls,
Extends,
References,
Tests,
DependsOn,
GeneratedFrom,
RuntimeObservationFor,
Reads,
Writes,
AccessesResource,
Custom(String),
}
impl EdgeKind {
pub fn custom(label: impl Into<String>) -> Result<Self, EdgeKindError> {
let s = label.into();
if s.is_empty() {
return Err(EdgeKindError::EmptyLabel);
}
if s.contains(':') {
return Err(EdgeKindError::LabelContainsColon(s));
}
Ok(EdgeKind::Custom(s))
}
pub fn score_multiplier(&self) -> f32 {
match self {
EdgeKind::Implements => 0.85,
EdgeKind::UsesType => 0.75,
EdgeKind::TestedBy => 0.80,
EdgeKind::Documents => 0.65,
EdgeKind::ReferencesConcept => 0.60,
EdgeKind::Writes => 0.90,
EdgeKind::Reads => 0.80,
EdgeKind::AccessesResource => 0.75,
EdgeKind::Custom(_) => 0.70,
_ => 0.70,
}
}
pub fn tag(&self) -> Cow<'static, str> {
match self {
EdgeKind::Custom(s) => Cow::Owned(format!("custom:{s}")),
other => Cow::Borrowed(other.static_tag()),
}
}
pub fn from_tag(tag: &str) -> Option<Self> {
if let Some(suffix) = tag.strip_prefix("custom:") {
if suffix.is_empty() || suffix.contains(':') {
return None;
}
return Some(EdgeKind::Custom(suffix.to_owned()));
}
Self::from_static_tag(tag)
}
pub fn from_static_tag(tag: &str) -> Option<Self> {
Some(match tag {
"CallsFunction" => EdgeKind::CallsFunction,
"CalledByFunction" => EdgeKind::CalledByFunction,
"Implements" => EdgeKind::Implements,
"UsesType" => EdgeKind::UsesType,
"Derives" => EdgeKind::Derives,
"ModuleContains" => EdgeKind::ModuleContains,
"ReExports" => EdgeKind::ReExports,
"RaisesError" => EdgeKind::RaisesError,
"Configures" => EdgeKind::Configures,
"TestedBy" => EdgeKind::TestedBy,
"TestUsesFixture" => EdgeKind::TestUsesFixture,
"CoOccursInTest" => EdgeKind::CoOccursInTest,
"Documents" => EdgeKind::Documents,
"ReferencesConcept" => EdgeKind::ReferencesConcept,
"Aliases" => EdgeKind::Aliases,
"ErrorDescribes" => EdgeKind::ErrorDescribes,
"Contains" => EdgeKind::Contains,
"Imports" => EdgeKind::Imports,
"Exports" => EdgeKind::Exports,
"Calls" => EdgeKind::Calls,
"Extends" => EdgeKind::Extends,
"References" => EdgeKind::References,
"Tests" => EdgeKind::Tests,
"DependsOn" => EdgeKind::DependsOn,
"GeneratedFrom" => EdgeKind::GeneratedFrom,
"RuntimeObservationFor" => EdgeKind::RuntimeObservationFor,
"Reads" => EdgeKind::Reads,
"Writes" => EdgeKind::Writes,
"AccessesResource" => EdgeKind::AccessesResource,
_ => return None,
})
}
fn static_tag(&self) -> &'static str {
match self {
EdgeKind::CallsFunction => "CallsFunction",
EdgeKind::CalledByFunction => "CalledByFunction",
EdgeKind::Implements => "Implements",
EdgeKind::UsesType => "UsesType",
EdgeKind::Derives => "Derives",
EdgeKind::ModuleContains => "ModuleContains",
EdgeKind::ReExports => "ReExports",
EdgeKind::RaisesError => "RaisesError",
EdgeKind::Configures => "Configures",
EdgeKind::TestedBy => "TestedBy",
EdgeKind::TestUsesFixture => "TestUsesFixture",
EdgeKind::CoOccursInTest => "CoOccursInTest",
EdgeKind::Documents => "Documents",
EdgeKind::ReferencesConcept => "ReferencesConcept",
EdgeKind::Aliases => "Aliases",
EdgeKind::ErrorDescribes => "ErrorDescribes",
EdgeKind::Contains => "Contains",
EdgeKind::Imports => "Imports",
EdgeKind::Exports => "Exports",
EdgeKind::Calls => "Calls",
EdgeKind::Extends => "Extends",
EdgeKind::References => "References",
EdgeKind::Tests => "Tests",
EdgeKind::DependsOn => "DependsOn",
EdgeKind::GeneratedFrom => "GeneratedFrom",
EdgeKind::RuntimeObservationFor => "RuntimeObservationFor",
EdgeKind::Reads => "Reads",
EdgeKind::Writes => "Writes",
EdgeKind::AccessesResource => "AccessesResource",
EdgeKind::Custom(_) => {
unreachable!("static_tag called on Custom — use tag() instead")
}
}
}
}
#[cfg(test)]
#[path = "edge_kind_tests.rs"]
mod tests;