]> git.proxmox.com Git - cargo.git/blob - src/cargo/core/interning.rs
Refactor `Kind` to carry target name in `Target`
[cargo.git] / src / cargo / core / interning.rs
1 use serde::{Serialize, Serializer};
2 use std::borrow::Borrow;
3 use std::cmp::Ordering;
4 use std::collections::HashSet;
5 use std::ffi::OsStr;
6 use std::fmt;
7 use std::hash::{Hash, Hasher};
8 use std::ops::Deref;
9 use std::path::Path;
10 use std::ptr;
11 use std::str;
12 use std::sync::Mutex;
13
14 pub fn leak(s: String) -> &'static str {
15 Box::leak(s.into_boxed_str())
16 }
17
18 lazy_static::lazy_static! {
19 static ref STRING_CACHE: Mutex<HashSet<&'static str>> = Mutex::new(HashSet::new());
20 }
21
22 #[derive(Clone, Copy)]
23 pub struct InternedString {
24 inner: &'static str,
25 }
26
27 impl<'a> From<&'a str> for InternedString {
28 fn from(item: &'a str) -> Self {
29 InternedString::new(item)
30 }
31 }
32
33 impl<'a> From<&'a String> for InternedString {
34 fn from(item: &'a String) -> Self {
35 InternedString::new(item)
36 }
37 }
38
39 impl PartialEq for InternedString {
40 fn eq(&self, other: &InternedString) -> bool {
41 ptr::eq(self.as_str(), other.as_str())
42 }
43 }
44
45 impl Eq for InternedString {}
46
47 impl InternedString {
48 pub fn new(str: &str) -> InternedString {
49 let mut cache = STRING_CACHE.lock().unwrap();
50 let s = cache.get(str).cloned().unwrap_or_else(|| {
51 let s = leak(str.to_string());
52 cache.insert(s);
53 s
54 });
55
56 InternedString { inner: s }
57 }
58
59 pub fn as_str(&self) -> &'static str {
60 self.inner
61 }
62 }
63
64 impl Deref for InternedString {
65 type Target = str;
66
67 fn deref(&self) -> &'static str {
68 self.as_str()
69 }
70 }
71
72 impl AsRef<str> for InternedString {
73 fn as_ref(&self) -> &str {
74 self.as_str()
75 }
76 }
77
78 impl AsRef<OsStr> for InternedString {
79 fn as_ref(&self) -> &OsStr {
80 self.as_str().as_ref()
81 }
82 }
83
84 impl AsRef<Path> for InternedString {
85 fn as_ref(&self) -> &Path {
86 self.as_str().as_ref()
87 }
88 }
89
90 impl Hash for InternedString {
91 // N.B., we can't implement this as `identity(self).hash(state)`,
92 // because we use this for on-disk fingerprints and so need
93 // stability across Cargo invocations.
94 fn hash<H: Hasher>(&self, state: &mut H) {
95 self.as_str().hash(state);
96 }
97 }
98
99 impl Borrow<str> for InternedString {
100 // If we implement Hash as `identity(self).hash(state)`,
101 // then this will need to be removed.
102 fn borrow(&self) -> &str {
103 self.as_str()
104 }
105 }
106
107 impl fmt::Debug for InternedString {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 fmt::Debug::fmt(self.as_str(), f)
110 }
111 }
112
113 impl fmt::Display for InternedString {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 fmt::Display::fmt(self.as_str(), f)
116 }
117 }
118
119 impl Ord for InternedString {
120 fn cmp(&self, other: &InternedString) -> Ordering {
121 self.as_str().cmp(other.as_str())
122 }
123 }
124
125 impl PartialOrd for InternedString {
126 fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
127 Some(self.cmp(other))
128 }
129 }
130
131 impl Serialize for InternedString {
132 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
133 where
134 S: Serializer,
135 {
136 serializer.serialize_str(self.inner)
137 }
138 }
139
140 struct InternedStringVisitor;
141
142 impl<'de> serde::Deserialize<'de> for InternedString {
143 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144 where
145 D: serde::Deserializer<'de>,
146 {
147 deserializer.deserialize_str(InternedStringVisitor)
148 }
149 }
150
151 impl<'de> serde::de::Visitor<'de> for InternedStringVisitor {
152 type Value = InternedString;
153
154 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
155 formatter.write_str("an String like thing")
156 }
157
158 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
159 where
160 E: serde::de::Error,
161 {
162 Ok(InternedString::new(v))
163 }
164 }