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 Wraps,
66}
67
68impl RelationKind {
69 #[must_use]
71 pub const fn all() -> &'static [Self] {
72 &[
73 Self::Callers,
74 Self::Callees,
75 Self::Imports,
76 Self::Exports,
77 Self::Returns,
78 Self::Wraps,
79 ]
80 }
81
82 #[must_use]
84 pub const fn as_str(self) -> &'static str {
85 match self {
86 Self::Callers => "callers",
87 Self::Callees => "callees",
88 Self::Imports => "imports",
89 Self::Exports => "exports",
90 Self::Returns => "returns",
91 Self::Wraps => "wraps",
92 }
93 }
94
95 #[must_use]
100 pub fn parse(s: &str) -> Option<Self> {
101 match s.to_lowercase().as_str() {
102 "callers" => Some(Self::Callers),
103 "callees" => Some(Self::Callees),
104 "imports" => Some(Self::Imports),
105 "exports" => Some(Self::Exports),
106 "returns" => Some(Self::Returns),
107 "wraps" => Some(Self::Wraps),
108 _ => None,
109 }
110 }
111
112 #[must_use]
114 pub const fn is_call_relation(self) -> bool {
115 matches!(self, Self::Callers | Self::Callees)
116 }
117
118 #[must_use]
120 pub const fn is_boundary_relation(self) -> bool {
121 matches!(self, Self::Imports | Self::Exports)
122 }
123}
124
125impl fmt::Display for RelationKind {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 f.write_str(self.as_str())
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_as_str() {
137 assert_eq!(RelationKind::Callers.as_str(), "callers");
138 assert_eq!(RelationKind::Callees.as_str(), "callees");
139 assert_eq!(RelationKind::Imports.as_str(), "imports");
140 assert_eq!(RelationKind::Exports.as_str(), "exports");
141 assert_eq!(RelationKind::Returns.as_str(), "returns");
142 }
143
144 #[test]
145 fn test_parse() {
146 assert_eq!(RelationKind::parse("callers"), Some(RelationKind::Callers));
147 assert_eq!(RelationKind::parse("CALLEES"), Some(RelationKind::Callees));
148 assert_eq!(RelationKind::parse("Imports"), Some(RelationKind::Imports));
149 assert_eq!(RelationKind::parse("unknown"), None);
150 }
151
152 #[test]
153 fn test_display() {
154 assert_eq!(format!("{}", RelationKind::Callers), "callers");
155 assert_eq!(format!("{}", RelationKind::Returns), "returns");
156 }
157
158 #[test]
159 fn test_serde_roundtrip() {
160 for kind in RelationKind::all() {
161 let json = serde_json::to_string(kind).unwrap();
162 let deserialized: RelationKind = serde_json::from_str(&json).unwrap();
163 assert_eq!(*kind, deserialized);
164 }
165 }
166
167 #[test]
168 fn test_classification() {
169 assert!(RelationKind::Callers.is_call_relation());
170 assert!(RelationKind::Callees.is_call_relation());
171 assert!(!RelationKind::Imports.is_call_relation());
172
173 assert!(RelationKind::Imports.is_boundary_relation());
174 assert!(RelationKind::Exports.is_boundary_relation());
175 assert!(!RelationKind::Callers.is_boundary_relation());
176 }
177}