Skip to main content

yazi_shared/pool/
symbol.rs

1use std::{borrow::Cow, hash::{Hash, Hasher}, marker::PhantomData, mem::ManuallyDrop, ops::Deref, str};
2
3use hashbrown::hash_map::RawEntryMut;
4use serde::Deserialize;
5
6use crate::pool::{Pool, SYMBOLS, SymbolPtr, compute_hash};
7
8pub struct Symbol<T: ?Sized> {
9	ptr:      SymbolPtr,
10	_phantom: PhantomData<T>,
11}
12
13unsafe impl<T: ?Sized> Send for Symbol<T> {}
14
15unsafe impl<T: ?Sized> Sync for Symbol<T> {}
16
17impl<T: ?Sized> Clone for Symbol<T> {
18	fn clone(&self) -> Self {
19		let hash = compute_hash(&self.ptr);
20		match SYMBOLS.lock().raw_entry_mut().from_key_hashed_nocheck(hash, &self.ptr) {
21			RawEntryMut::Occupied(mut oe) => *oe.get_mut() += 1,
22			RawEntryMut::Vacant(_) => unreachable!(),
23		}
24		Self::new(self.ptr.clone())
25	}
26}
27
28impl<T: ?Sized> Drop for Symbol<T> {
29	fn drop(&mut self) {
30		let hash = compute_hash(&self.ptr);
31		match SYMBOLS.lock().raw_entry_mut().from_key_hashed_nocheck(hash, &self.ptr) {
32			RawEntryMut::Occupied(mut oe) => {
33				let count = oe.get_mut();
34				*count -= 1;
35
36				if *count == 0 {
37					oe.remove();
38					drop(unsafe { Box::from_raw(self.ptr.as_ptr()) });
39				}
40			}
41			RawEntryMut::Vacant(_) => unreachable!(),
42		}
43	}
44}
45
46impl AsRef<[u8]> for Symbol<[u8]> {
47	fn as_ref(&self) -> &[u8] { self.ptr.bytes() }
48}
49
50impl AsRef<str> for Symbol<str> {
51	fn as_ref(&self) -> &str { unsafe { str::from_utf8_unchecked(self.ptr.bytes()) } }
52}
53
54impl Deref for Symbol<[u8]> {
55	type Target = [u8];
56
57	fn deref(&self) -> &Self::Target { self.as_ref() }
58}
59
60impl Deref for Symbol<str> {
61	type Target = str;
62
63	fn deref(&self) -> &Self::Target { self.as_ref() }
64}
65
66// --- Default
67impl Default for Symbol<[u8]> {
68	fn default() -> Self { Pool::<[u8]>::intern(b"") }
69}
70
71impl Default for Symbol<str> {
72	fn default() -> Self { Pool::<str>::intern("") }
73}
74
75// --- Eq
76impl<T: ?Sized> PartialEq for Symbol<T> {
77	fn eq(&self, other: &Self) -> bool { self.ptr == other.ptr }
78}
79
80impl<T: ?Sized> Eq for Symbol<T> {}
81
82impl PartialEq<str> for Symbol<str> {
83	fn eq(&self, other: &str) -> bool { self.as_ref() == other }
84}
85
86impl PartialEq<&str> for Symbol<str> {
87	fn eq(&self, other: &&str) -> bool { self.as_ref() == *other }
88}
89
90impl PartialEq<[u8]> for Symbol<[u8]> {
91	fn eq(&self, other: &[u8]) -> bool { self.as_ref() == other }
92}
93
94// --- Hash
95impl<T: ?Sized> Hash for Symbol<T> {
96	fn hash<H: Hasher>(&self, state: &mut H) { self.ptr.as_ptr().hash(state); }
97}
98
99// --- Ord
100impl Ord for Symbol<[u8]> {
101	fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_ref().cmp(other.as_ref()) }
102}
103
104impl Ord for Symbol<str> {
105	fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_ref().cmp(other.as_ref()) }
106}
107
108// --- PartialOrd
109impl PartialOrd for Symbol<[u8]> {
110	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
111}
112
113impl PartialOrd for Symbol<str> {
114	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
115}
116
117// --- Display
118impl std::fmt::Display for Symbol<str> {
119	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120		write!(f, "{}", self.as_ref())
121	}
122}
123
124// --- Debug
125impl std::fmt::Debug for Symbol<[u8]> {
126	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127		write!(f, "Symbol<[u8]>({:?})", self.as_ref())
128	}
129}
130
131impl std::fmt::Debug for Symbol<str> {
132	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133		write!(f, "Symbol<str>({:?})", self.as_ref())
134	}
135}
136
137impl<'de> Deserialize<'de> for Symbol<str> {
138	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
139	where
140		D: serde::Deserializer<'de>,
141	{
142		Cow::<str>::deserialize(deserializer).map(Pool::<str>::intern)
143	}
144}
145
146impl<T: ?Sized> Symbol<T> {
147	#[inline]
148	pub(super) fn new(ptr: SymbolPtr) -> Self { Self { ptr, _phantom: PhantomData } }
149
150	#[inline]
151	pub(super) fn into_ptr(self) -> SymbolPtr { ManuallyDrop::new(self).ptr.clone() }
152}