1use std::sync::Arc;
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Keyword {
12 pub namespace: Option<Arc<str>>,
13 pub name: Arc<str>,
14}
15
16impl Keyword {
17 pub fn simple(name: impl Into<Arc<str>>) -> Self {
19 Self {
20 namespace: None,
21 name: name.into(),
22 }
23 }
24
25 pub fn qualified(ns: impl Into<Arc<str>>, name: impl Into<Arc<str>>) -> Self {
27 Self {
28 namespace: Some(ns.into()),
29 name: name.into(),
30 }
31 }
32
33 pub fn parse(s: &str) -> Self {
35 match s.find('/') {
36 Some(idx) if idx > 0 && idx < s.len() - 1 => Self::qualified(&s[..idx], &s[idx + 1..]),
37 _ => Self::simple(s),
38 }
39 }
40
41 pub fn full_name(&self) -> String {
43 match &self.namespace {
44 Some(ns) => format!("{}/{}", ns, self.name),
45 None => self.name.to_string(),
46 }
47 }
48}
49
50impl std::fmt::Display for Keyword {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 match &self.namespace {
53 Some(ns) => write!(f, ":{}/{}", ns, self.name),
54 None => write!(f, ":{}", self.name),
55 }
56 }
57}
58
59impl cljrs_gc::Trace for Keyword {
60 fn trace(&self, _: &mut cljrs_gc::MarkVisitor) {}
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn test_display() {
69 assert_eq!(Keyword::simple("foo").to_string(), ":foo");
70 assert_eq!(Keyword::qualified("ns", "name").to_string(), ":ns/name");
71 }
72
73 #[test]
74 fn test_parse() {
75 assert_eq!(Keyword::parse("foo"), Keyword::simple("foo"));
76 assert_eq!(Keyword::parse("a/b"), Keyword::qualified("a", "b"));
77 }
78
79 #[test]
80 fn test_equality() {
81 assert_eq!(Keyword::simple("a"), Keyword::simple("a"));
82 assert_ne!(Keyword::simple("a"), Keyword::simple("b"));
83 }
84}