1use std::{
2 fmt::Debug,
3 hash::Hash,
4 mem::{forget, transmute},
5 ops::Deref,
6};
7
8use debug_unreachable::debug_unreachable;
9
10use crate::{
11 macros::{get_hash, impl_from_alias, partial_eq},
12 tagged_value::TaggedValue,
13 wtf8::Wtf8,
14 DYNAMIC_TAG, INLINE_TAG, LEN_MASK, LEN_OFFSET, TAG_MASK,
15};
16
17pub struct Wtf8Atom {
22 pub(crate) unsafe_data: TaggedValue,
23}
24
25impl Wtf8Atom {
26 #[inline(always)]
27 pub fn new<S>(s: S) -> Self
28 where
29 Self: From<S>,
30 {
31 Self::from(s)
32 }
33
34 #[inline(always)]
35 fn tag(&self) -> u8 {
36 self.unsafe_data.tag() & TAG_MASK
37 }
38
39 #[inline(always)]
41 fn is_dynamic(&self) -> bool {
42 self.tag() == DYNAMIC_TAG
43 }
44}
45
46impl Default for Wtf8Atom {
47 #[inline(never)]
48 fn default() -> Self {
49 Wtf8Atom::new("")
50 }
51}
52
53unsafe impl Send for Wtf8Atom {}
55
56unsafe impl Sync for Wtf8Atom {}
58
59impl Debug for Wtf8Atom {
60 #[inline]
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 Debug::fmt(&self.to_string_lossy(), f)
63 }
64}
65
66#[cfg(feature = "serde")]
67impl serde::ser::Serialize for Wtf8Atom {
68 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
69 where
70 S: serde::ser::Serializer,
71 {
72 serializer.serialize_bytes(self.as_bytes())
73 }
74}
75
76#[cfg(feature = "serde")]
77impl<'de> serde::de::Deserialize<'de> for Wtf8Atom {
78 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
79 where
80 D: serde::Deserializer<'de>,
81 {
82 String::deserialize(deserializer).map(Self::new)
83 }
84}
85
86impl PartialEq for Wtf8Atom {
87 #[inline(never)]
88 fn eq(&self, other: &Self) -> bool {
89 partial_eq!(self, other);
90
91 self.as_wtf8() == other.as_wtf8()
94 }
95}
96
97impl Eq for Wtf8Atom {}
98
99impl Hash for Wtf8Atom {
100 #[inline(always)]
101 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
102 state.write_u64(self.get_hash());
103 }
104}
105
106impl Drop for Wtf8Atom {
107 #[inline(always)]
108 fn drop(&mut self) {
109 if self.is_dynamic() {
110 unsafe { drop(crate::dynamic::restore_arc(self.unsafe_data)) }
111 }
112 }
113}
114
115impl Clone for Wtf8Atom {
116 #[inline(always)]
117 fn clone(&self) -> Self {
118 Self::from_alias(self.unsafe_data)
119 }
120}
121
122impl Deref for Wtf8Atom {
123 type Target = Wtf8;
124
125 #[inline(always)]
126 fn deref(&self) -> &Self::Target {
127 self.as_wtf8()
128 }
129}
130
131impl AsRef<Wtf8> for Wtf8Atom {
132 #[inline(always)]
133 fn as_ref(&self) -> &Wtf8 {
134 self.as_wtf8()
135 }
136}
137
138impl PartialEq<Wtf8> for Wtf8Atom {
139 #[inline]
140 fn eq(&self, other: &Wtf8) -> bool {
141 self.as_wtf8() == other
142 }
143}
144
145impl PartialEq<crate::Atom> for Wtf8Atom {
146 #[inline]
147 fn eq(&self, other: &crate::Atom) -> bool {
148 self.as_str() == Some(other.as_str())
149 }
150}
151
152impl PartialEq<&'_ Wtf8> for Wtf8Atom {
153 #[inline]
154 fn eq(&self, other: &&Wtf8) -> bool {
155 self.as_wtf8() == *other
156 }
157}
158
159impl PartialEq<Wtf8Atom> for Wtf8 {
160 #[inline]
161 fn eq(&self, other: &Wtf8Atom) -> bool {
162 self == other.as_wtf8()
163 }
164}
165
166impl Wtf8Atom {
167 pub(super) fn get_hash(&self) -> u64 {
168 get_hash!(self)
169 }
170
171 fn as_wtf8(&self) -> &Wtf8 {
172 match self.tag() {
173 DYNAMIC_TAG => unsafe {
174 let item = crate::dynamic::deref_from(self.unsafe_data);
175 Wtf8::from_bytes_unchecked(transmute::<&[u8], &'static [u8]>(&item.slice))
176 },
177 INLINE_TAG => {
178 let len = (self.unsafe_data.tag() & LEN_MASK) >> LEN_OFFSET;
179 let src = self.unsafe_data.data();
180 unsafe { Wtf8::from_bytes_unchecked(&src[..(len as usize)]) }
181 }
182 _ => unsafe { debug_unreachable!() },
183 }
184 }
185}
186
187impl_from_alias!(Wtf8Atom);
188
189#[cfg(test)]
190impl Wtf8Atom {
191 pub(crate) fn ref_count(&self) -> usize {
192 match self.tag() {
193 DYNAMIC_TAG => {
194 let ptr = unsafe { crate::dynamic::deref_from(self.unsafe_data) };
195
196 triomphe::ThinArc::strong_count(&ptr.0)
197 }
198 _ => 1,
199 }
200 }
201}