1use crate::Symbol;
2use std::borrow::Borrow;
3use std::fmt::{Debug, Formatter};
4use std::hash::{Hash, Hasher};
5
6#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
9pub struct SymbolRef<'a> {
10 text: Option<&'a str>,
11}
12
13impl<'a> Debug for SymbolRef<'a> {
14 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15 write!(f, "{}", self.text.unwrap_or("$0"))
16 }
17}
18
19impl<'a> SymbolRef<'a> {
20 pub fn text(&self) -> Option<&str> {
22 self.text
23 }
24
25 pub fn with_unknown_text() -> Self {
27 SymbolRef { text: None }
28 }
29
30 pub fn with_text(text: &str) -> SymbolRef {
32 SymbolRef { text: Some(text) }
33 }
34
35 pub fn to_owned(self) -> Symbol {
36 match self.text() {
37 None => Symbol::unknown_text(),
38 Some(text) => Symbol::owned(text),
39 }
40 }
41}
42
43impl<'a, A> PartialEq<A> for SymbolRef<'a>
44where
45 A: AsSymbolRef,
46{
47 fn eq(&self, other: &A) -> bool {
48 let other_symbol_ref = other.as_symbol_ref();
49 self == &other_symbol_ref
50 }
51}
52
53pub trait AsSymbolRef {
56 fn as_symbol_ref(&self) -> SymbolRef;
57}
58
59impl<'a, A: AsRef<str> + 'a> AsSymbolRef for A {
61 fn as_symbol_ref(&self) -> SymbolRef {
62 SymbolRef {
63 text: Some(self.as_ref()),
64 }
65 }
66}
67
68impl<'a> Hash for SymbolRef<'a> {
69 fn hash<H: Hasher>(&self, state: &mut H) {
70 match self.text {
71 None => 0.hash(state),
72 Some(text) => text.hash(state),
73 }
74 }
75}
76
77impl<'a> From<&'a str> for SymbolRef<'a> {
78 fn from(text: &'a str) -> Self {
79 Self { text: Some(text) }
80 }
81}
82
83impl<'a> From<&'a Symbol> for SymbolRef<'a> {
84 fn from(symbol: &'a Symbol) -> Self {
85 Self {
86 text: symbol.text(),
87 }
88 }
89}
90
91impl<'a> Borrow<str> for SymbolRef<'a> {
94 fn borrow(&self) -> &str {
95 self.text()
96 .expect("cannot borrow a &str from a SymbolRef with unknown text")
97 }
98}
99
100impl AsSymbolRef for Symbol {
103 fn as_symbol_ref(&self) -> SymbolRef {
104 self.text()
105 .map(SymbolRef::with_text)
106 .unwrap_or_else(SymbolRef::with_unknown_text)
107 }
108}
109
110impl AsSymbolRef for &Symbol {
111 fn as_symbol_ref(&self) -> SymbolRef {
112 self.text()
113 .map(SymbolRef::with_text)
114 .unwrap_or_else(SymbolRef::with_unknown_text)
115 }
116}
117
118impl<'borrow, 'data> AsSymbolRef for &'borrow SymbolRef<'data> {
119 fn as_symbol_ref(&self) -> SymbolRef<'data> {
120 (*self).clone()
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn symbol_ref_with_text() {
131 let symbol_ref = SymbolRef::with_text("foo");
132 assert_eq!(Some("foo"), symbol_ref.text());
133 }
134
135 #[test]
136 fn symbol_ref_with_unknown_text() {
137 let symbol_ref = SymbolRef::with_unknown_text();
138 assert_eq!(None, symbol_ref.text());
139 }
140
141 #[test]
142 fn str_as_symbol_ref() {
143 let symbol_ref: SymbolRef = "foo".as_symbol_ref();
144 assert_eq!(Some("foo"), symbol_ref.text());
145 }
146
147 #[test]
148 fn symbol_as_symbol_ref() {
149 let symbol = Symbol::owned("foo");
150 let symbol_ref: SymbolRef = symbol.as_symbol_ref();
151 assert_eq!(Some("foo"), symbol_ref.text());
152 }
153
154 #[test]
155 fn symbol_with_unknown_text_as_symbol_ref() {
156 let symbol = Symbol::unknown_text();
157 let symbol_ref: SymbolRef = symbol.as_symbol_ref();
158 assert_eq!(None, symbol_ref.text());
159 }
160}