sqry_core/graph/unified/node/
kind.rs1use std::fmt;
15
16use serde::{Deserialize, Serialize};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
29#[serde(rename_all = "snake_case")]
30pub enum NodeKind {
31 Function,
34
35 Method,
37
38 Class,
40
41 Interface,
43
44 Trait,
46
47 Module,
49
50 Variable,
53
54 Constant,
56
57 Type,
59
60 Struct,
62
63 Enum,
65
66 EnumVariant,
68
69 Macro,
71
72 Parameter,
74
75 Property,
77
78 CallSite,
84
85 Import,
87
88 Export,
90
91 StyleRule,
94
95 StyleAtRule,
97
98 StyleVariable,
100
101 Lifetime,
112
113 Component,
116
117 Service,
119
120 Resource,
122
123 Endpoint,
125
126 Test,
128
129 TypeParameter,
132
133 Annotation,
135
136 AnnotationValue,
138
139 LambdaTarget,
141
142 JavaModule,
144
145 EnumConstant,
147
148 Channel,
168
169 #[serde(other)]
175 Other,
176}
177
178impl NodeKind {
179 #[inline]
181 #[must_use]
182 pub const fn is_callable(self) -> bool {
183 matches!(self, Self::Function | Self::Method | Self::Macro)
184 }
185
186 #[inline]
188 #[must_use]
189 pub const fn is_type_definition(self) -> bool {
190 matches!(
191 self,
192 Self::Class | Self::Interface | Self::Trait | Self::Struct | Self::Enum | Self::Type
193 )
194 }
195
196 #[inline]
198 #[must_use]
199 pub const fn is_container(self) -> bool {
200 matches!(
201 self,
202 Self::Class
203 | Self::Interface
204 | Self::Trait
205 | Self::Struct
206 | Self::Module
207 | Self::Enum
208 | Self::StyleRule
209 | Self::StyleAtRule
210 | Self::JavaModule
211 )
212 }
213
214 #[inline]
216 #[must_use]
217 pub const fn is_boundary(self) -> bool {
218 matches!(self, Self::Import | Self::Export)
219 }
220
221 #[inline]
223 #[must_use]
224 pub const fn is_lifetime(self) -> bool {
225 matches!(self, Self::Lifetime)
226 }
227
228 #[must_use]
230 pub const fn as_str(self) -> &'static str {
231 match self {
232 Self::Function => "function",
233 Self::Method => "method",
234 Self::Class => "class",
235 Self::Interface => "interface",
236 Self::Trait => "trait",
237 Self::Module => "module",
238 Self::Variable => "variable",
239 Self::Constant => "constant",
240 Self::Type => "type",
241 Self::Struct => "struct",
242 Self::Enum => "enum",
243 Self::EnumVariant => "enum_variant",
244 Self::Macro => "macro",
245 Self::Parameter => "parameter",
246 Self::Property => "property",
247 Self::CallSite => "call_site",
248 Self::Import => "import",
249 Self::Export => "export",
250 Self::StyleRule => "style_rule",
251 Self::StyleAtRule => "style_at_rule",
252 Self::StyleVariable => "style_variable",
253 Self::Lifetime => "lifetime",
254 Self::Component => "component",
255 Self::Service => "service",
256 Self::Resource => "resource",
257 Self::Endpoint => "endpoint",
258 Self::Test => "test",
259 Self::TypeParameter => "type_parameter",
260 Self::Annotation => "annotation",
261 Self::AnnotationValue => "annotation_value",
262 Self::LambdaTarget => "lambda_target",
263 Self::JavaModule => "java_module",
264 Self::EnumConstant => "enum_constant",
265 Self::Channel => "channel",
266 Self::Other => "other",
267 }
268 }
269
270 #[must_use]
274 pub fn parse(s: &str) -> Option<Self> {
275 match s {
276 "function" => Some(Self::Function),
277 "method" => Some(Self::Method),
278 "class" => Some(Self::Class),
279 "interface" => Some(Self::Interface),
280 "trait" => Some(Self::Trait),
281 "module" => Some(Self::Module),
282 "variable" => Some(Self::Variable),
283 "constant" => Some(Self::Constant),
284 "type" => Some(Self::Type),
285 "struct" => Some(Self::Struct),
286 "enum" => Some(Self::Enum),
287 "enum_variant" => Some(Self::EnumVariant),
288 "macro" => Some(Self::Macro),
289 "parameter" => Some(Self::Parameter),
290 "property" => Some(Self::Property),
291 "call_site" => Some(Self::CallSite),
292 "import" => Some(Self::Import),
293 "export" => Some(Self::Export),
294 "style_rule" => Some(Self::StyleRule),
295 "style_at_rule" => Some(Self::StyleAtRule),
296 "style_variable" => Some(Self::StyleVariable),
297 "lifetime" => Some(Self::Lifetime),
298 "component" => Some(Self::Component),
299 "service" => Some(Self::Service),
300 "resource" => Some(Self::Resource),
301 "endpoint" => Some(Self::Endpoint),
302 "test" => Some(Self::Test),
303 "type_parameter" => Some(Self::TypeParameter),
304 "annotation" => Some(Self::Annotation),
305 "annotation_value" => Some(Self::AnnotationValue),
306 "lambda_target" => Some(Self::LambdaTarget),
307 "java_module" => Some(Self::JavaModule),
308 "enum_constant" => Some(Self::EnumConstant),
309 "channel" => Some(Self::Channel),
310 "other" => Some(Self::Other),
311 _ => None,
312 }
313 }
314}
315
316impl fmt::Display for NodeKind {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 f.write_str(self.as_str())
319 }
320}
321
322impl Default for NodeKind {
323 fn default() -> Self {
325 Self::Function
326 }
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 #[test]
334 fn test_node_kind_as_str() {
335 assert_eq!(NodeKind::Function.as_str(), "function");
336 assert_eq!(NodeKind::Method.as_str(), "method");
337 assert_eq!(NodeKind::Class.as_str(), "class");
338 assert_eq!(NodeKind::CallSite.as_str(), "call_site");
339 assert_eq!(NodeKind::EnumVariant.as_str(), "enum_variant");
340 }
341
342 #[test]
343 fn test_node_kind_parse() {
344 assert_eq!(NodeKind::parse("function"), Some(NodeKind::Function));
345 assert_eq!(NodeKind::parse("call_site"), Some(NodeKind::CallSite));
346 assert_eq!(NodeKind::parse("unknown"), None);
347 }
348
349 #[test]
350 fn test_node_kind_display() {
351 assert_eq!(format!("{}", NodeKind::Function), "function");
352 assert_eq!(format!("{}", NodeKind::EnumVariant), "enum_variant");
353 }
354
355 #[test]
356 fn test_is_callable() {
357 assert!(NodeKind::Function.is_callable());
358 assert!(NodeKind::Method.is_callable());
359 assert!(NodeKind::Macro.is_callable());
360 assert!(!NodeKind::Class.is_callable());
361 assert!(!NodeKind::Variable.is_callable());
362 }
363
364 #[test]
365 fn test_is_type_definition() {
366 assert!(NodeKind::Class.is_type_definition());
367 assert!(NodeKind::Interface.is_type_definition());
368 assert!(NodeKind::Trait.is_type_definition());
369 assert!(NodeKind::Struct.is_type_definition());
370 assert!(NodeKind::Enum.is_type_definition());
371 assert!(NodeKind::Type.is_type_definition());
372 assert!(!NodeKind::Function.is_type_definition());
373 assert!(!NodeKind::Variable.is_type_definition());
374 }
375
376 #[test]
377 fn test_is_container() {
378 assert!(NodeKind::Class.is_container());
379 assert!(NodeKind::Module.is_container());
380 assert!(NodeKind::Struct.is_container());
381 assert!(!NodeKind::Function.is_container());
382 assert!(!NodeKind::Variable.is_container());
383 }
384
385 #[test]
386 fn test_is_boundary() {
387 assert!(NodeKind::Import.is_boundary());
388 assert!(NodeKind::Export.is_boundary());
389 assert!(!NodeKind::Function.is_boundary());
390 }
391
392 #[test]
393 fn test_is_lifetime() {
394 assert!(NodeKind::Lifetime.is_lifetime());
395 assert!(!NodeKind::Function.is_lifetime());
396 assert!(!NodeKind::Variable.is_lifetime());
397 }
398
399 #[test]
400 fn test_lifetime_serialization() {
401 assert_eq!(NodeKind::Lifetime.as_str(), "lifetime");
402 assert_eq!(NodeKind::parse("lifetime"), Some(NodeKind::Lifetime));
403
404 let json = serde_json::to_string(&NodeKind::Lifetime).unwrap();
406 assert_eq!(json, "\"lifetime\"");
407 let deserialized: NodeKind = serde_json::from_str(&json).unwrap();
408 assert_eq!(deserialized, NodeKind::Lifetime);
409 }
410
411 #[test]
412 fn test_default() {
413 assert_eq!(NodeKind::default(), NodeKind::Function);
414 }
415
416 #[test]
417 fn test_serde_roundtrip() {
418 let kinds = [
419 NodeKind::Function,
420 NodeKind::Method,
421 NodeKind::Class,
422 NodeKind::CallSite,
423 NodeKind::EnumVariant,
424 ];
425
426 for kind in kinds {
427 let json = serde_json::to_string(&kind).unwrap();
429 let deserialized: NodeKind = serde_json::from_str(&json).unwrap();
430 assert_eq!(kind, deserialized);
431
432 let bytes = postcard::to_allocvec(&kind).unwrap();
434 let deserialized: NodeKind = postcard::from_bytes(&bytes).unwrap();
435 assert_eq!(kind, deserialized);
436 }
437 }
438
439 #[test]
440 fn test_json_format() {
441 assert_eq!(
443 serde_json::to_string(&NodeKind::Function).unwrap(),
444 "\"function\""
445 );
446 assert_eq!(
447 serde_json::to_string(&NodeKind::CallSite).unwrap(),
448 "\"call_site\""
449 );
450 assert_eq!(
451 serde_json::to_string(&NodeKind::EnumVariant).unwrap(),
452 "\"enum_variant\""
453 );
454 }
455
456 #[test]
457 fn test_hash() {
458 use std::collections::HashSet;
459
460 let mut set = HashSet::new();
461 set.insert(NodeKind::Function);
462 set.insert(NodeKind::Method);
463 set.insert(NodeKind::Class);
464
465 assert!(set.contains(&NodeKind::Function));
466 assert!(!set.contains(&NodeKind::Variable));
467 assert_eq!(set.len(), 3);
468 }
469
470 #[test]
471 #[allow(clippy::clone_on_copy)] fn test_copy_clone() {
473 let kind = NodeKind::Function;
474 let copied = kind;
475 let cloned = kind.clone();
476
477 assert_eq!(kind, copied);
478 assert_eq!(kind, cloned);
479 }
480}