• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Data structures for representing a crate name and version, which can be
16 //! used as a map key.
17 
18 use std::{
19     borrow::Borrow,
20     cmp::Ordering,
21     hash::{Hash, Hasher},
22 };
23 
24 use semver::{BuildMetadata, Prerelease, Version};
25 
26 static MIN_VERSION: Version =
27     Version { major: 0, minor: 0, patch: 0, pre: Prerelease::EMPTY, build: BuildMetadata::EMPTY };
28 
29 /// A name and version pair trait.
30 pub trait NamedAndVersioned {
31     /// Returns the name.
name(&self) -> &str32     fn name(&self) -> &str;
33     /// Returns the version.
version(&self) -> &Version34     fn version(&self) -> &Version;
35     /// Returns a reference that can be used as a map key.
key(&self) -> NameAndVersionRef36     fn key(&self) -> NameAndVersionRef;
37 }
38 
39 /// An owned namd and version.
40 #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
41 pub struct NameAndVersion {
42     name: String,
43     version: Version,
44 }
45 
46 /// A reference to a name and version.
47 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
48 pub struct NameAndVersionRef<'a> {
49     name: &'a str,
50     version: &'a Version,
51 }
52 
53 impl NameAndVersion {
54     /// Constructor that takes ownership of args.
new(name: String, version: Version) -> Self55     pub fn new(name: String, version: Version) -> Self {
56         NameAndVersion { name, version }
57     }
58     /// Constructor that clones a reference.
from(nv: &impl NamedAndVersioned) -> Self59     pub fn from(nv: &impl NamedAndVersioned) -> Self {
60         NameAndVersion { name: nv.name().to_string(), version: nv.version().clone() }
61     }
62     /// The lowest possible version, used to find the first key in a map with this name.
min_version(name: String) -> Self63     pub fn min_version(name: String) -> Self {
64         NameAndVersion { name, version: MIN_VERSION.clone() }
65     }
66     /// Intended for testing.
try_from_str(name: &str, version: &str) -> Result<Self, semver::Error>67     pub fn try_from_str(name: &str, version: &str) -> Result<Self, semver::Error> {
68         Ok(NameAndVersion::new(name.to_string(), Version::parse(version)?))
69     }
70 }
71 
72 impl NamedAndVersioned for NameAndVersion {
name(&self) -> &str73     fn name(&self) -> &str {
74         self.name.as_str()
75     }
76 
version(&self) -> &Version77     fn version(&self) -> &Version {
78         &self.version
79     }
key(&self) -> NameAndVersionRef80     fn key(&self) -> NameAndVersionRef {
81         NameAndVersionRef::new(self.name(), self.version())
82     }
83 }
84 
85 impl<'a> NameAndVersionRef<'a> {
86     /// Construct a reference to a name and version.
new(name: &'a str, version: &'a Version) -> Self87     pub fn new(name: &'a str, version: &'a Version) -> Self {
88         NameAndVersionRef { name, version }
89     }
90 }
91 
92 impl NamedAndVersioned for NameAndVersionRef<'_> {
name(&self) -> &str93     fn name(&self) -> &str {
94         self.name
95     }
version(&self) -> &Version96     fn version(&self) -> &Version {
97         self.version
98     }
key(&self) -> NameAndVersionRef99     fn key(&self) -> NameAndVersionRef {
100         *self
101     }
102 }
103 
104 impl<'a> Borrow<dyn NamedAndVersioned + 'a> for NameAndVersion {
borrow(&self) -> &(dyn NamedAndVersioned + 'a)105     fn borrow(&self) -> &(dyn NamedAndVersioned + 'a) {
106         self
107     }
108 }
109 
110 impl PartialEq for (dyn NamedAndVersioned + '_) {
eq(&self, other: &Self) -> bool111     fn eq(&self, other: &Self) -> bool {
112         self.key().eq(&other.key())
113     }
114 }
115 
116 impl Eq for (dyn NamedAndVersioned + '_) {}
117 
118 impl PartialOrd for (dyn NamedAndVersioned + '_) {
partial_cmp(&self, other: &Self) -> Option<Ordering>119     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
120         Some(self.cmp(other))
121     }
122 }
123 
124 impl Ord for (dyn NamedAndVersioned + '_) {
cmp(&self, other: &Self) -> Ordering125     fn cmp(&self, other: &Self) -> Ordering {
126         self.key().cmp(&other.key())
127     }
128 }
129 
130 impl Hash for (dyn NamedAndVersioned + '_) {
hash<H: Hasher>(&self, state: &mut H)131     fn hash<H: Hasher>(&self, state: &mut H) {
132         self.key().hash(state)
133     }
134 }
135 
136 #[cfg(test)]
137 mod tests {
138     use super::*;
139 
140     #[test]
test_name_version_ref() -> Result<(), semver::Error>141     fn test_name_version_ref() -> Result<(), semver::Error> {
142         let version = Version::parse("2.3.4")?;
143         let nvp = NameAndVersionRef::new("foo", &version);
144         assert_eq!(nvp.name(), "foo");
145         assert_eq!(nvp.version().to_string(), "2.3.4");
146         Ok(())
147     }
148 
149     #[test]
test_name_and_version() -> Result<(), semver::Error>150     fn test_name_and_version() -> Result<(), semver::Error> {
151         let version = Version::parse("2.3.4")?;
152         let nvp = NameAndVersion::new("foo".to_string(), version);
153         assert_eq!(nvp.name(), "foo");
154         assert_eq!(nvp.version().to_string(), "2.3.4");
155         Ok(())
156     }
157 }
158