Skip to content

Commit d9880c3

Browse files
committed
Slightly improve InternedString
* Use `&'static str` instead of (ptr, len) pair to reduce unsafety. * try make hash calculation O(1) instead of O(n), fail miserably, document findings. * Rename `to_inner` -> `as_str()`.
1 parent 9bd7134 commit d9880c3

File tree

5 files changed

+33
-32
lines changed

5 files changed

+33
-32
lines changed

src/cargo/core/interning.rs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::collections::HashSet;
44
use std::slice;
55
use std::str;
66
use std::mem;
7+
use std::ptr;
78
use std::cmp::Ordering;
89
use std::ops::Deref;
910
use std::hash::{Hash, Hasher};
@@ -24,65 +25,68 @@ lazy_static! {
2425
RwLock::new(HashSet::new());
2526
}
2627

27-
#[derive(Eq, PartialEq, Clone, Copy)]
28+
#[derive(Clone, Copy)]
2829
pub struct InternedString {
29-
ptr: *const u8,
30-
len: usize,
30+
inner: &'static str,
3131
}
3232

33+
impl PartialEq for InternedString {
34+
fn eq(&self, other: &InternedString) -> bool {
35+
ptr::eq(self.as_str(), other.as_str())
36+
}
37+
}
38+
39+
impl Eq for InternedString {}
40+
3341
impl InternedString {
3442
pub fn new(str: &str) -> InternedString {
3543
let mut cache = STRING_CACHE.write().unwrap();
36-
if let Some(&s) = cache.get(str) {
37-
return InternedString {
38-
ptr: s.as_ptr(),
39-
len: s.len(),
40-
};
41-
}
42-
let s = leak(str.to_string());
43-
cache.insert(s);
44-
InternedString {
45-
ptr: s.as_ptr(),
46-
len: s.len(),
47-
}
44+
let s = cache.get(str).map(|&s| s).unwrap_or_else(|| {
45+
let s = leak(str.to_string());
46+
cache.insert(s);
47+
s
48+
});
49+
50+
InternedString { inner: s }
4851
}
49-
pub fn to_inner(&self) -> &'static str {
50-
unsafe {
51-
let slice = slice::from_raw_parts(self.ptr, self.len);
52-
&str::from_utf8_unchecked(slice)
53-
}
52+
53+
pub fn as_str(&self) -> &'static str {
54+
self.inner
5455
}
5556
}
5657

5758
impl Deref for InternedString {
5859
type Target = str;
5960

6061
fn deref(&self) -> &'static str {
61-
self.to_inner()
62+
self.as_str()
6263
}
6364
}
6465

6566
impl Hash for InternedString {
67+
// NB: we can't implement this as `identity(self).hash(state)`,
68+
// because we use this for on-disk fingerprints and so need
69+
// stability across Cargo invocations.
6670
fn hash<H: Hasher>(&self, state: &mut H) {
67-
self.to_inner().hash(state);
71+
self.as_str().hash(state);
6872
}
6973
}
7074

7175
impl fmt::Debug for InternedString {
7276
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73-
fmt::Debug::fmt(self.to_inner(), f)
77+
fmt::Debug::fmt(self.as_str(), f)
7478
}
7579
}
7680

7781
impl fmt::Display for InternedString {
7882
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79-
fmt::Display::fmt(self.to_inner(), f)
83+
fmt::Display::fmt(self.as_str(), f)
8084
}
8185
}
8286

8387
impl Ord for InternedString {
8488
fn cmp(&self, other: &InternedString) -> Ordering {
85-
self.to_inner().cmp(&*other)
89+
self.as_str().cmp(other.as_str())
8690
}
8791
}
8892

@@ -91,6 +95,3 @@ impl PartialOrd for InternedString {
9195
Some(self.cmp(other))
9296
}
9397
}
94-
95-
unsafe impl Send for InternedString {}
96-
unsafe impl Sync for InternedString {}

src/cargo/core/resolver/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ fn build_requirements<'a, 'b: 'a>(
280280
reqs.require_feature(key)?;
281281
}
282282
for dep in s.dependencies().iter().filter(|d| d.is_optional()) {
283-
reqs.require_dependency(dep.name().to_inner());
283+
reqs.require_dependency(dep.name().as_str());
284284
}
285285
}
286286
Method::Required {

src/cargo/ops/cargo_doc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub fn doc(ws: &Workspace, options: &DocOptions) -> CargoResult<()> {
6969
Please re-run this command with `-p <spec>` where `<spec>` \
7070
is one of the following:\n {}",
7171
pkgs.iter()
72-
.map(|p| p.name().to_inner())
72+
.map(|p| p.name().as_str())
7373
.collect::<Vec<_>>()
7474
.join("\n ")
7575
);

src/cargo/ops/cargo_generate_lockfile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ pub fn update_lockfile(ws: &Workspace, opts: &UpdateOptions) -> CargoResult<()>
142142
resolve: &'a Resolve,
143143
) -> Vec<(Vec<&'a PackageId>, Vec<&'a PackageId>)> {
144144
fn key(dep: &PackageId) -> (&str, &SourceId) {
145-
(dep.name().to_inner(), dep.source_id())
145+
(dep.name().as_str(), dep.source_id())
146146
}
147147

148148
// Removes all package ids in `b` from `a`. Note that this is somewhat

src/cargo/ops/cargo_install.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ where
506506
"multiple packages with {} found: {}",
507507
kind,
508508
pkgs.iter()
509-
.map(|p| p.name().to_inner())
509+
.map(|p| p.name().as_str())
510510
.collect::<Vec<_>>()
511511
.join(", ")
512512
)

0 commit comments

Comments
 (0)