diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index 00fddd49908..a85c83adb47 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -7,6 +7,7 @@ use semver::ReqParseError; use serde::ser; use core::{SourceId, Summary, PackageId}; +use core::interning::InternedString; use util::{Cfg, CfgExpr, Config}; use util::errors::{CargoResult, CargoResultExt, CargoError}; @@ -20,7 +21,7 @@ pub struct Dependency { /// The data underlying a Dependency. #[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Debug)] struct Inner { - name: String, + name: InternedString, source_id: SourceId, registry_id: Option, req: VersionReq, @@ -63,7 +64,7 @@ impl ser::Serialize for Dependency { where S: ser::Serializer, { SerializedDependency { - name: self.name(), + name: &*self.name(), source: self.source_id(), req: self.version_req().to_string(), kind: self.kind(), @@ -174,7 +175,7 @@ impl Dependency { pub fn new_override(name: &str, source_id: &SourceId) -> Dependency { Dependency { inner: Rc::new(Inner { - name: name.to_string(), + name: InternedString::new(name), source_id: source_id.clone(), registry_id: None, req: VersionReq::any(), @@ -194,8 +195,8 @@ impl Dependency { &self.inner.req } - pub fn name(&self) -> &str { - &self.inner.name + pub fn name(&self) -> InternedString { + self.inner.name } pub fn source_id(&self) -> &SourceId { diff --git a/src/cargo/core/interning.rs b/src/cargo/core/interning.rs index 45dde58105c..1a0722eb135 100644 --- a/src/cargo/core/interning.rs +++ b/src/cargo/core/interning.rs @@ -6,6 +6,7 @@ use std::str; use std::mem; use std::cmp::Ordering; use std::ops::Deref; +use std::hash::{Hash, Hasher}; pub fn leek(s: String) -> &'static str { let boxed = s.into_boxed_str(); @@ -23,7 +24,7 @@ lazy_static! { RwLock::new(HashSet::new()); } -#[derive(Eq, PartialEq, Hash, Clone, Copy)] +#[derive(Eq, PartialEq, Clone, Copy)] pub struct InternedString { ptr: *const u8, len: usize, @@ -39,30 +40,43 @@ impl InternedString { cache.insert(s); InternedString { ptr: s.as_ptr(), len: s.len() } } + pub fn to_inner(&self) -> &'static str { + unsafe { + let slice = slice::from_raw_parts(self.ptr, self.len); + &str::from_utf8_unchecked(slice) + } + } } impl Deref for InternedString { type Target = str; fn deref(&self) -> &'static str { - unsafe { - let slice = slice::from_raw_parts(self.ptr, self.len); - &str::from_utf8_unchecked(slice) - } + self.to_inner() + } +} + +impl Hash for InternedString { + fn hash(&self, state: &mut H) { + self.to_inner().hash(state); } } impl fmt::Debug for InternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let str: &str = &*self; - write!(f, "InternedString {{ {} }}", str) + write!(f, "InternedString {{ {} }}", self.to_inner()) + } +} + +impl fmt::Display for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_inner()) } } impl Ord for InternedString { fn cmp(&self, other: &InternedString) -> Ordering { - let str: &str = &*self; - str.cmp(&*other) + self.to_inner().cmp(&*other) } } diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 557380d6c50..739eab5c509 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -10,6 +10,7 @@ use url::Url; use core::{Dependency, PackageId, Summary, SourceId, PackageIdSpec}; use core::{WorkspaceConfig, Epoch, Features, Feature}; +use core::interning::InternedString; use util::Config; use util::toml::TomlManifest; use util::errors::*; @@ -301,7 +302,7 @@ impl Manifest { pub fn exclude(&self) -> &[String] { &self.exclude } pub fn include(&self) -> &[String] { &self.include } pub fn metadata(&self) -> &ManifestMetadata { &self.metadata } - pub fn name(&self) -> &str { self.package_id().name() } + pub fn name(&self) -> InternedString { self.package_id().name() } pub fn package_id(&self) -> &PackageId { self.summary.package_id() } pub fn summary(&self) -> &Summary { &self.summary } pub fn targets(&self) -> &[Target] { &self.targets } diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 252b7ac836e..6fdc1f1ef27 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -11,6 +11,7 @@ use lazycell::LazyCell; use core::{Dependency, Manifest, PackageId, SourceId, Target}; use core::{Summary, SourceMap}; +use core::interning::InternedString; use ops; use util::{Config, internal, lev_distance}; use util::errors::{CargoResult, CargoResultExt}; @@ -55,7 +56,7 @@ impl ser::Serialize for Package { let description = manmeta.description.as_ref().map(String::as_ref); SerializedPackage { - name: package_id.name(), + name: &*package_id.name(), version: &package_id.version().to_string(), id: package_id, license, @@ -95,7 +96,7 @@ impl Package { /// Get the path to the manifest pub fn manifest_path(&self) -> &Path { &self.manifest_path } /// Get the name of the package - pub fn name(&self) -> &str { self.package_id().name() } + pub fn name(&self) -> InternedString { self.package_id().name() } /// Get the PackageId object for the package (fully defines a package) pub fn package_id(&self) -> &PackageId { self.manifest.package_id() } /// Get the root folder of the package diff --git a/src/cargo/core/package_id.rs b/src/cargo/core/package_id.rs index ffb4330c627..1b8133829d8 100644 --- a/src/cargo/core/package_id.rs +++ b/src/cargo/core/package_id.rs @@ -11,6 +11,7 @@ use serde::ser; use util::{CargoResult, ToSemver}; use core::source::SourceId; +use core::interning::InternedString; /// Identifier for a specific version of a package in a specific source. #[derive(Clone)] @@ -20,7 +21,7 @@ pub struct PackageId { #[derive(PartialEq, PartialOrd, Eq, Ord)] struct PackageIdInner { - name: String, + name: InternedString, version: semver::Version, source_id: SourceId, } @@ -63,7 +64,7 @@ impl<'de> de::Deserialize<'de> for PackageId { Ok(PackageId { inner: Arc::new(PackageIdInner { - name: name.to_string(), + name: InternedString::new(name), version, source_id, }), @@ -102,21 +103,21 @@ impl PackageId { let v = version.to_semver()?; Ok(PackageId { inner: Arc::new(PackageIdInner { - name: name.to_string(), + name: InternedString::new(name), version: v, source_id: sid.clone(), }), }) } - pub fn name(&self) -> &str { &self.inner.name } + pub fn name(&self) -> InternedString { self.inner.name } pub fn version(&self) -> &semver::Version { &self.inner.version } pub fn source_id(&self) -> &SourceId { &self.inner.source_id } pub fn with_precise(&self, precise: Option) -> PackageId { PackageId { inner: Arc::new(PackageIdInner { - name: self.inner.name.to_string(), + name: self.inner.name, version: self.inner.version.clone(), source_id: self.inner.source_id.with_precise(precise), }), @@ -126,7 +127,7 @@ impl PackageId { pub fn with_source_id(&self, source: &SourceId) -> PackageId { PackageId { inner: Arc::new(PackageIdInner { - name: self.inner.name.to_string(), + name: self.inner.name, version: self.inner.version.clone(), source_id: source.clone(), }), diff --git a/src/cargo/core/package_id_spec.rs b/src/cargo/core/package_id_spec.rs index be1170be4a7..065534f7069 100644 --- a/src/cargo/core/package_id_spec.rs +++ b/src/cargo/core/package_id_spec.rs @@ -115,7 +115,7 @@ impl PackageIdSpec { } pub fn matches(&self, package_id: &PackageId) -> bool { - if self.name() != package_id.name() { return false } + if self.name() != &*package_id.name() { return false } if let Some(ref v) = self.version { if v != package_id.version() { diff --git a/src/cargo/core/registry.rs b/src/cargo/core/registry.rs index 051adb84efc..56f6eed8528 100644 --- a/src/cargo/core/registry.rs +++ b/src/cargo/core/registry.rs @@ -317,7 +317,7 @@ impl<'cfg> PackageRegistry<'cfg> { -> CargoResult> { for s in self.overrides.iter() { let src = self.sources.get_mut(s).unwrap(); - let dep = Dependency::new_override(dep.name(), s); + let dep = Dependency::new_override(&*dep.name(), s); let mut results = src.query_vec(&dep)?; if !results.is_empty() { return Ok(Some(results.remove(0))) @@ -519,7 +519,7 @@ fn lock(locked: &LockedMap, patches: &HashMap>, summary: Summary) -> Summary { let pair = locked.get(summary.source_id()).and_then(|map| { - map.get(summary.name()) + map.get(&*summary.name()) }).and_then(|vec| { vec.iter().find(|&&(ref id, _)| id == summary.package_id()) }); @@ -568,7 +568,7 @@ fn lock(locked: &LockedMap, // all known locked packages to see if they match this dependency. // If anything does then we lock it to that and move on. let v = locked.get(dep.source_id()).and_then(|map| { - map.get(dep.name()) + map.get(&*dep.name()) }).and_then(|vec| { vec.iter().find(|&&(ref id, _)| dep.matches_id(id)) }); @@ -593,7 +593,7 @@ fn lock(locked: &LockedMap, assert!(remaining.next().is_none()); let patch_source = patch_id.source_id(); let patch_locked = locked.get(patch_source).and_then(|m| { - m.get(patch_id.name()) + m.get(&*patch_id.name()) }).map(|list| { list.iter().any(|&(ref id, _)| id == patch_id) }).unwrap_or(false); diff --git a/src/cargo/core/resolver/mod.rs b/src/cargo/core/resolver/mod.rs index 6edc410c04d..2a055d64e30 100644 --- a/src/cargo/core/resolver/mod.rs +++ b/src/cargo/core/resolver/mod.rs @@ -1044,7 +1044,7 @@ fn activation_error(cx: &Context, for &(p, r) in links_errors.iter() { if let ConflictReason::Links(ref link) = *r { msg.push_str("\n\nthe package `"); - msg.push_str(dep.name()); + msg.push_str(&*dep.name()); msg.push_str("` links to the native library `"); msg.push_str(link); msg.push_str("`, but it conflicts with a previous package which links to `"); @@ -1059,13 +1059,13 @@ fn activation_error(cx: &Context, for &(p, r) in features_errors.iter() { if let ConflictReason::MissingFeatures(ref features) = *r { msg.push_str("\n\nthe package `"); - msg.push_str(p.name()); + msg.push_str(&*p.name()); msg.push_str("` depends on `"); - msg.push_str(dep.name()); + msg.push_str(&*dep.name()); msg.push_str("`, with features: `"); msg.push_str(features); msg.push_str("` but `"); - msg.push_str(dep.name()); + msg.push_str(&*dep.name()); msg.push_str("` does not have these features.\n"); } // p == parent so the full path is redundant. @@ -1082,7 +1082,7 @@ fn activation_error(cx: &Context, } msg.push_str("\n\nfailed to select a version for `"); - msg.push_str(dep.name()); + msg.push_str(&*dep.name()); msg.push_str("` which could resolve this conflict"); return format_err!("{}", msg) @@ -1274,7 +1274,7 @@ fn build_requirements<'a, 'b: 'a>(s: &'a Summary, method: &'b Method) reqs.require_feature(key)?; } for dep in s.dependencies().iter().filter(|d| d.is_optional()) { - reqs.require_dependency(dep.name()); + reqs.require_dependency(dep.name().to_inner()); } } Method::Required { features: requested_features, .. } => { @@ -1304,7 +1304,7 @@ impl Context { method: &Method) -> CargoResult { let id = summary.package_id(); let prev = self.activations - .entry((InternedString::new(id.name()), id.source_id().clone())) + .entry((id.name(), id.source_id().clone())) .or_insert_with(||Rc::new(Vec::new())); if !prev.iter().any(|c| c == summary) { self.resolve_graph.push(GraphNode::Add(id.clone())); @@ -1365,13 +1365,13 @@ impl Context { } fn prev_active(&self, dep: &Dependency) -> &[Summary] { - self.activations.get(&(InternedString::new(dep.name()), dep.source_id().clone())) + self.activations.get(&(dep.name(), dep.source_id().clone())) .map(|v| &v[..]) .unwrap_or(&[]) } fn is_active(&self, id: &PackageId) -> bool { - self.activations.get(&(InternedString::new(id.name()), id.source_id().clone())) + self.activations.get(&(id.name(), id.source_id().clone())) .map(|v| v.iter().any(|s| s.package_id() == id)) .unwrap_or(false) } @@ -1397,12 +1397,12 @@ impl Context { // Next, collect all actually enabled dependencies and their features. for dep in deps { // Skip optional dependencies, but not those enabled through a feature - if dep.is_optional() && !reqs.deps.contains_key(dep.name()) { + if dep.is_optional() && !reqs.deps.contains_key(&*dep.name()) { continue } // So we want this dependency. Move the features we want from `feature_deps` // to `ret`. - let base = reqs.deps.remove(dep.name()).unwrap_or((false, vec![])); + let base = reqs.deps.remove(&*dep.name()).unwrap_or((false, vec![])); if !dep.is_optional() && base.0 { self.warnings.push( format!("Package `{}` does not have feature `{}`. It has a required dependency \ diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index 4144fde98a8..31aab456a4e 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -32,7 +32,7 @@ impl Summary { features: BTreeMap>, links: Option) -> CargoResult { for dep in dependencies.iter() { - if features.get(dep.name()).is_some() { + if features.get(&*dep.name()).is_some() { bail!("Features and dependencies cannot have the \ same name: `{}`", dep.name()) } @@ -47,7 +47,7 @@ impl Summary { let dep = parts.next().unwrap(); let is_reexport = parts.next().is_some(); if !is_reexport && features.get(dep).is_some() { continue } - match dependencies.iter().find(|d| d.name() == dep) { + match dependencies.iter().find(|d| &*d.name() == dep) { Some(d) => { if d.is_optional() || is_reexport { continue } bail!("Feature `{}` depends on `{}` which is not an \ @@ -78,7 +78,7 @@ impl Summary { } pub fn package_id(&self) -> &PackageId { &self.inner.package_id } - pub fn name(&self) -> &str { self.package_id().name() } + pub fn name(&self) -> InternedString { self.package_id().name() } pub fn version(&self) -> &Version { self.package_id().version() } pub fn source_id(&self) -> &SourceId { self.package_id().source_id() } pub fn dependencies(&self) -> &[Dependency] { &self.inner.dependencies } diff --git a/src/cargo/ops/cargo_doc.rs b/src/cargo/ops/cargo_doc.rs index d747b42d098..ed19b62405f 100644 --- a/src/cargo/ops/cargo_doc.rs +++ b/src/cargo/ops/cargo_doc.rs @@ -54,7 +54,7 @@ pub fn doc(ws: &Workspace, options: &DocOptions) -> CargoResult<()> { bail!("Passing multiple packages and `open` is not supported.\n\ Please re-run this command with `-p ` where `` \ is one of the following:\n {}", - pkgs.iter().map(|p| p.name()).collect::>().join("\n ")); + pkgs.iter().map(|p| p.name().to_inner()).collect::>().join("\n ")); } else if pkgs.len() == 1 { pkgs[0].name().replace("-", "_") } else { diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index d08c11b1662..a22974d24f9 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -136,7 +136,7 @@ pub fn update_lockfile(ws: &Workspace, opts: &UpdateOptions) resolve: &'a Resolve) -> Vec<(Vec<&'a PackageId>, Vec<&'a PackageId>)> { fn key(dep: &PackageId) -> (&str, &SourceId) { - (dep.name(), dep.source_id()) + (dep.name().to_inner(), dep.source_id()) } // Removes all package ids in `b` from `a`. Note that this is somewhat diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 40037e74e4e..6dce40768db 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -429,9 +429,9 @@ fn select_pkg<'a, T>(mut source: T, return Ok((pkg.clone(), Box::new(source))); fn multi_err(kind: &str, mut pkgs: Vec<&Package>) -> String { - pkgs.sort_by(|a, b| a.name().cmp(b.name())); + pkgs.sort_by(|a, b| a.name().cmp(&b.name())); format!("multiple packages with {} found: {}", kind, - pkgs.iter().map(|p| p.name()).collect::>() + pkgs.iter().map(|p| p.name().to_inner()).collect::>() .join(", ")) } } diff --git a/src/cargo/ops/cargo_run.rs b/src/cargo/ops/cargo_run.rs index 81ac7790844..f4c6c71ad3e 100644 --- a/src/cargo/ops/cargo_run.rs +++ b/src/cargo/ops/cargo_run.rs @@ -16,7 +16,7 @@ pub fn run(ws: &Workspace, Packages::Packages(xs) => match xs.len() { 0 => ws.current()?, 1 => ws.members() - .find(|pkg| pkg.name() == xs[0]) + .find(|pkg| &*pkg.name() == xs[0]) .ok_or_else(|| format_err!("package `{}` is not a member of the workspace", xs[0]) )?, diff --git a/src/cargo/ops/cargo_rustc/compilation.rs b/src/cargo/ops/cargo_rustc/compilation.rs index 7cb781e0f2d..e9e46cbe24a 100644 --- a/src/cargo/ops/cargo_rustc/compilation.rs +++ b/src/cargo/ops/cargo_rustc/compilation.rs @@ -170,7 +170,7 @@ impl<'cfg> Compilation<'cfg> { .env("CARGO_PKG_VERSION_PATCH", &pkg.version().patch.to_string()) .env("CARGO_PKG_VERSION_PRE", &pre_version_component(pkg.version())) .env("CARGO_PKG_VERSION", &pkg.version().to_string()) - .env("CARGO_PKG_NAME", &pkg.name()) + .env("CARGO_PKG_NAME", &*pkg.name()) .env("CARGO_PKG_DESCRIPTION", metadata.description.as_ref().unwrap_or(&String::new())) .env("CARGO_PKG_HOMEPAGE", metadata.homepage.as_ref().unwrap_or(&String::new())) .env("CARGO_PKG_AUTHORS", &pkg.authors().join(":")) diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index a23e9fe03d0..9f7766e0ef8 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -806,7 +806,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { // If the dependency is optional, then we're only activating it // if the corresponding feature was activated - if d.is_optional() && !self.resolve.features(id).contains(d.name()) { + if d.is_optional() && !self.resolve.features(id).contains(&*d.name()) { return false; } diff --git a/src/cargo/sources/registry/index.rs b/src/cargo/sources/registry/index.rs index d3135bac365..87a96471068 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -41,7 +41,7 @@ impl<'cfg> RegistryIndex<'cfg> { pkg: &PackageId, load: &mut RegistryData) -> CargoResult { - let name = pkg.name(); + let name = &*pkg.name(); let version = pkg.version(); if let Some(s) = self.hashes.get(name).and_then(|v| v.get(version)) { return Ok(s.clone()) @@ -169,7 +169,7 @@ impl<'cfg> RegistryIndex<'cfg> { f: &mut FnMut(Summary)) -> CargoResult<()> { let source_id = self.source_id.clone(); - let summaries = self.summaries(dep.name(), load)?; + let summaries = self.summaries(&*dep.name(), load)?; let summaries = summaries.iter().filter(|&&(_, yanked)| { dep.source_id().precise().is_some() || !yanked }).map(|s| s.0.clone()); @@ -180,7 +180,7 @@ impl<'cfg> RegistryIndex<'cfg> { // version requested (argument to `--precise`). let summaries = summaries.filter(|s| { match source_id.precise() { - Some(p) if p.starts_with(dep.name()) && + Some(p) if p.starts_with(&*dep.name()) && p[dep.name().len()..].starts_with('=') => { let vers = &p[dep.name().len() + 1..]; s.version().to_string() == vers diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index 18ff7589710..cb2b9fc1e63 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -435,7 +435,7 @@ impl<'cfg> Source for RegistrySource<'cfg> { // differ due to historical Cargo bugs. To paper over these we trash the // *summary* loaded from the Cargo.toml we just downloaded with the one // we loaded from the index. - let summaries = self.index.summaries(package.name(), &mut *self.ops)?; + let summaries = self.index.summaries(&*package.name(), &mut *self.ops)?; let summary = summaries.iter().map(|s| &s.0).find(|s| { s.package_id() == package }).expect("summary not found"); diff --git a/src/cargo/sources/registry/remote.rs b/src/cargo/sources/registry/remote.rs index 47f940f9274..d09b6d53118 100644 --- a/src/cargo/sources/registry/remote.rs +++ b/src/cargo/sources/registry/remote.rs @@ -217,7 +217,7 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> { write!(url, "/{}/{}/download", CRATE_TEMPLATE, VERSION_TEMPLATE).unwrap(); } let url = url - .replace(CRATE_TEMPLATE, pkg.name()) + .replace(CRATE_TEMPLATE, &*pkg.name()) .replace(VERSION_TEMPLATE, &pkg.version().to_string()) .to_url()?;