@@ -4,7 +4,7 @@ use std::{
44} ;
55
66use anyhow:: { Context , Result } ;
7- use cargo_metadata:: { Metadata , MetadataCommand , Package , PackageId } ;
7+ use cargo_metadata:: { Metadata , MetadataCommand , Package , PackageId , Source , semver :: Version } ;
88use serde:: Deserialize ;
99use sha2:: { Digest , Sha256 } ;
1010
@@ -38,13 +38,13 @@ impl VerusMetadata {
3838}
3939
4040pub struct MetadataIndex < ' a > {
41- entries : BTreeMap < & ' a PackageId , MetadataIndexEntry < ' a > > ,
41+ pub entries : BTreeMap < & ' a PackageId , MetadataIndexEntry < ' a > > ,
4242}
4343
4444pub struct MetadataIndexEntry < ' a > {
45- package : & ' a Package ,
46- verus_metadata : VerusMetadata ,
47- deps : BTreeMap < & ' a PackageId , & ' a cargo_metadata:: NodeDep > ,
45+ pub package : & ' a Package ,
46+ pub verus_metadata : VerusMetadata ,
47+ pub deps : BTreeMap < & ' a PackageId , & ' a cargo_metadata:: NodeDep > ,
4848}
4949
5050impl < ' a > MetadataIndex < ' a > {
@@ -77,6 +77,10 @@ impl<'a> MetadataIndex<'a> {
7777 Ok ( Self { entries } )
7878 }
7979
80+ pub fn iter_package_ids ( & self ) -> impl Iterator < Item = & PackageId > {
81+ self . entries . keys ( ) . map ( |package_id| * package_id)
82+ }
83+
8084 pub fn get ( & self , id : & PackageId ) -> & MetadataIndexEntry < ' a > {
8185 self . entries . get ( id) . unwrap ( )
8286 }
@@ -132,15 +136,92 @@ impl<'a> MetadataIndex<'a> {
132136 }
133137 names
134138 }
139+
140+ /// Collect sources of `vstd` that appear in the verified part of the build.
141+ pub fn collect_vstd_metadata (
142+ & self ,
143+ packages_to_verify : & Set < PackageId > ,
144+ ) -> Set < PackageMetadata > {
145+ // Packages that verification will run on.
146+ let packages_will_verify = Set :: from_iter (
147+ packages_to_verify
148+ . iter ( )
149+ . filter ( |package_id| self . get ( package_id) . verus_metadata . verify )
150+ . cloned ( ) ,
151+ ) ;
152+ // Transitive closure of packages that verification will run on.
153+ let tclosure_will_verify = self . get_transitive_closure ( packages_will_verify) ;
154+
155+ // Metadata of all `vstd` instances that appear anywhere in the transitive closure.
156+ let vstd_metadata: Set < PackageMetadata > = tclosure_will_verify
157+ . iter ( )
158+ . flat_map ( |package_id| {
159+ let entry = self . get ( package_id) ;
160+ if entry. verus_metadata . is_vstd {
161+ Some ( PackageMetadata :: from ( entry. package ) )
162+ } else {
163+ None
164+ }
165+ } )
166+ . collect ( ) ;
167+
168+ assert ! (
169+ vstd_metadata. len( ) <= 1 ,
170+ "The `vstd` versioning scheme prevents multiple instances in a resolve set." ,
171+ // This is a consequence of the current `vstd` versioning scheme.
172+ // In the current scheme, each version matches `0.0.0-*`.
173+ // By definition, *all* such versions are semver-compatible.
174+ // Cargo disallows different *compatible* versions in a resolve set.
175+ // https://doc.rust-lang.org/cargo/reference/resolver.html#semver-compatibility
176+ ) ;
177+
178+ vstd_metadata
179+ }
180+ }
181+
182+ /// Metadata about a package.
183+ #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
184+ pub struct PackageMetadata {
185+ pub version : Version ,
186+ pub source : PackageSource ,
135187}
136188
137- impl < ' a > MetadataIndexEntry < ' a > {
138- pub fn package ( & self ) -> & ' a Package {
139- self . package
189+ /// Details of a package source.
190+ #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
191+ pub enum PackageSource {
192+ Registry { url : String } ,
193+ Git { url : String , rev : Option < String > } ,
194+ Unsupported ,
195+ }
196+
197+ impl From < & Package > for PackageMetadata {
198+ fn from ( package : & Package ) -> Self {
199+ let version = package. version . clone ( ) ;
200+ let source =
201+ package. source . as_ref ( ) . map ( PackageSource :: from) . unwrap_or ( PackageSource :: Unsupported ) ;
202+ PackageMetadata { version, source }
140203 }
204+ }
141205
142- pub fn verus_metadata ( & self ) -> & VerusMetadata {
143- & self . verus_metadata
206+ /// NOTE: This code relies on Cargo internals because there's no stable API.
207+ /// The tests in `test_vstd_sources.rs` should be able to detect if these assumptions break.
208+ impl From < & Source > for PackageSource {
209+ fn from ( source : & Source ) -> Self {
210+ let repr = & source. repr ;
211+ if let Some ( registry) = repr. strip_prefix ( "registry+" ) {
212+ PackageSource :: Registry { url : registry. to_string ( ) }
213+ } else if let Some ( git_source) = repr. strip_prefix ( "git+" ) {
214+ let ( url, rev) = if let Some ( ( url, rev) ) = git_source. rsplit_once ( '#' ) {
215+ ( url, Some ( rev. to_owned ( ) ) )
216+ } else {
217+ ( git_source, None )
218+ } ;
219+ // Trim the query part of the URL.
220+ let url = url. split_once ( '?' ) . map_or ( url, |( trimmed_url, _query) | trimmed_url) ;
221+ PackageSource :: Git { url : url. to_string ( ) , rev }
222+ } else {
223+ PackageSource :: Unsupported
224+ }
144225 }
145226}
146227
0 commit comments