diff --git a/purl/src/lib.rs b/purl/src/lib.rs index 142aa3b..1bb845c 100644 --- a/purl/src/lib.rs +++ b/purl/src/lib.rs @@ -152,7 +152,7 @@ impl PurlShape for String { /// Without type-specific functionality, it's possible to create PURLs that have /// incorrect capitalization or are missing a required namespace or required /// qualifiers. -impl<'a> PurlShape for Cow<'a, str> { +impl PurlShape for Cow<'_, str> { type Error = ParseError; fn package_type(&self) -> Cow { @@ -321,6 +321,42 @@ impl GenericPurl { } } +#[cfg(feature = "package-type")] +impl Purl { + /// Create a new [`PurlBuilder`] with a combined name and namespace. + pub fn builder_with_combined_name( + package_type: PackageType, + namespaced_name: S, + ) -> PurlBuilder + where + S: AsRef, + { + // Split apart namespace and name based on ecosystem. + let namespaced_name = namespaced_name.as_ref(); + let (namespace, name) = match package_type { + PackageType::Cargo | PackageType::Gem | PackageType::NuGet | PackageType::PyPI => { + (None, namespaced_name) + }, + PackageType::Golang | PackageType::Npm => match namespaced_name.rsplit_once('/') { + Some((namespace, name)) => (Some(namespace), name), + None => (None, namespaced_name), + }, + PackageType::Maven => match namespaced_name.split_once(':') { + Some((namespace, name)) => (Some(namespace), name), + None => (None, namespaced_name), + }, + }; + + // Create the PURL builder. + let mut builder = GenericPurlBuilder::new(package_type, name); + if let Some(namespace) = namespace { + builder = builder.with_namespace(namespace); + } + + builder + } +} + /// Check whether a package type string is valid according to the rules of the /// PURL spec. #[must_use] @@ -554,4 +590,19 @@ mod tests { let purl = GenericPurl::new(Cow::Borrowed("type"), "name").unwrap(); assert_eq!(None, purl.subpath()); } + + #[cfg(feature = "package-type")] + #[test] + fn namespaced_name() { + let purl = + Purl::builder_with_combined_name(PackageType::Npm, "@angular/cli").build().unwrap(); + assert_eq!(purl.namespace(), Some("@angular")); + assert_eq!(purl.name(), "cli"); + + let purl = Purl::builder_with_combined_name(PackageType::Maven, "org.maven.plugins:pom") + .build() + .unwrap(); + assert_eq!(purl.namespace(), Some("org.maven.plugins")); + assert_eq!(purl.name(), "pom"); + } } diff --git a/purl/src/parse.rs b/purl/src/parse.rs index bf9d859..1d87e8e 100644 --- a/purl/src/parse.rs +++ b/purl/src/parse.rs @@ -322,7 +322,7 @@ mod de { struct PurlVisitor(PhantomData); - impl<'de, T> Visitor<'de> for PurlVisitor + impl Visitor<'_> for PurlVisitor where T: FromStr + PurlShape, ::Error: fmt::Display + From<::Err>, diff --git a/purl/src/qualifiers.rs b/purl/src/qualifiers.rs index 69e97bb..84472ea 100644 --- a/purl/src/qualifiers.rs +++ b/purl/src/qualifiers.rs @@ -501,9 +501,9 @@ impl<'a> Iterator for Iter<'a> { } } -impl<'a> ExactSizeIterator for Iter<'a> {} +impl ExactSizeIterator for Iter<'_> {} -impl<'a> DoubleEndedIterator for Iter<'a> { +impl DoubleEndedIterator for Iter<'_> { fn next_back(&mut self) -> Option { let (k, v) = self.0.next_back()?; Some((k, v.as_str())) @@ -534,9 +534,9 @@ impl<'a> Iterator for IterMut<'a> { } } -impl<'a> ExactSizeIterator for IterMut<'a> {} +impl ExactSizeIterator for IterMut<'_> {} -impl<'a> DoubleEndedIterator for IterMut<'a> { +impl DoubleEndedIterator for IterMut<'_> { fn next_back(&mut self) -> Option { let (k, v) = self.0.next_back()?; Some((k, v)) diff --git a/purl/src/qualifiers/well_known.rs b/purl/src/qualifiers/well_known.rs index 14a3a56..64d04b5 100644 --- a/purl/src/qualifiers/well_known.rs +++ b/purl/src/qualifiers/well_known.rs @@ -100,7 +100,7 @@ pub struct Checksum<'a> { algorithms: HashMap>, } -impl<'a> KnownQualifierKey for Checksum<'a> { +impl KnownQualifierKey for Checksum<'_> { const KEY: &'static str = "checksum"; } @@ -154,7 +154,7 @@ impl<'a> TryFrom> for SmallString { } } -impl<'a> Checksum<'a> { +impl Checksum<'_> { /// Get a reference to the hex bytes of a hash. /// /// The hash may not be valid hex bytes. @@ -258,7 +258,7 @@ impl<'a> ChecksumValue<'a> { } } -impl<'a> Deref for ChecksumValue<'a> { +impl Deref for ChecksumValue<'_> { type Target = str; fn deref(&self) -> &Self::Target {