sqry_core/schema/
relation.rs1use serde::{Deserialize, Serialize};
6use std::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
29#[serde(rename_all = "lowercase")]
30#[derive(Default)]
31pub enum RelationKind {
32 #[default]
36 Callers,
37
38 Callees,
42
43 Imports,
47
48 Exports,
52
53 Returns,
57}
58
59impl RelationKind {
60 #[must_use]
62 pub const fn all() -> &'static [Self] {
63 &[
64 Self::Callers,
65 Self::Callees,
66 Self::Imports,
67 Self::Exports,
68 Self::Returns,
69 ]
70 }
71
72 #[must_use]
74 pub const fn as_str(self) -> &'static str {
75 match self {
76 Self::Callers => "callers",
77 Self::Callees => "callees",
78 Self::Imports => "imports",
79 Self::Exports => "exports",
80 Self::Returns => "returns",
81 }
82 }
83
84 #[must_use]
89 pub fn parse(s: &str) -> Option<Self> {
90 match s.to_lowercase().as_str() {
91 "callers" => Some(Self::Callers),
92 "callees" => Some(Self::Callees),
93 "imports" => Some(Self::Imports),
94 "exports" => Some(Self::Exports),
95 "returns" => Some(Self::Returns),
96 _ => None,
97 }
98 }
99
100 #[must_use]
102 pub const fn is_call_relation(self) -> bool {
103 matches!(self, Self::Callers | Self::Callees)
104 }
105
106 #[must_use]
108 pub const fn is_boundary_relation(self) -> bool {
109 matches!(self, Self::Imports | Self::Exports)
110 }
111}
112
113impl fmt::Display for RelationKind {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.write_str(self.as_str())
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_as_str() {
125 assert_eq!(RelationKind::Callers.as_str(), "callers");
126 assert_eq!(RelationKind::Callees.as_str(), "callees");
127 assert_eq!(RelationKind::Imports.as_str(), "imports");
128 assert_eq!(RelationKind::Exports.as_str(), "exports");
129 assert_eq!(RelationKind::Returns.as_str(), "returns");
130 }
131
132 #[test]
133 fn test_parse() {
134 assert_eq!(RelationKind::parse("callers"), Some(RelationKind::Callers));
135 assert_eq!(RelationKind::parse("CALLEES"), Some(RelationKind::Callees));
136 assert_eq!(RelationKind::parse("Imports"), Some(RelationKind::Imports));
137 assert_eq!(RelationKind::parse("unknown"), None);
138 }
139
140 #[test]
141 fn test_display() {
142 assert_eq!(format!("{}", RelationKind::Callers), "callers");
143 assert_eq!(format!("{}", RelationKind::Returns), "returns");
144 }
145
146 #[test]
147 fn test_serde_roundtrip() {
148 for kind in RelationKind::all() {
149 let json = serde_json::to_string(kind).unwrap();
150 let deserialized: RelationKind = serde_json::from_str(&json).unwrap();
151 assert_eq!(*kind, deserialized);
152 }
153 }
154
155 #[test]
156 fn test_classification() {
157 assert!(RelationKind::Callers.is_call_relation());
158 assert!(RelationKind::Callees.is_call_relation());
159 assert!(!RelationKind::Imports.is_call_relation());
160
161 assert!(RelationKind::Imports.is_boundary_relation());
162 assert!(RelationKind::Exports.is_boundary_relation());
163 assert!(!RelationKind::Callers.is_boundary_relation());
164 }
165}