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