@@ -35,6 +35,7 @@ use petgraph::graph::NodeIndex;
3535use std:: collections:: BTreeMap ;
3636use std:: collections:: BTreeSet ;
3737use std:: fmt;
38+ use swrite:: { SWrite , swriteln} ;
3839
3940/// Query information about the Dropshot/OpenAPI/Progenitor-based APIs within
4041/// the Oxide system
@@ -63,6 +64,10 @@ pub struct SystemApis {
6364 /// maps an API name to the server component(s) that expose that API
6465 api_producers : BTreeMap < ClientPackageName , ApiProducerMap > ,
6566
67+ /// index of (server, client) pairs configured as same-deployment-unit edges
68+ same_deployment_unit_edges :
69+ BTreeSet < ( ServerComponentName , ClientPackageName ) > ,
70+
6671 /// source of developer-maintained API metadata
6772 api_metadata : AllApiMetadata ,
6873 /// source of Cargo package metadata
@@ -126,6 +131,22 @@ impl SystemApis {
126131 // Load the API manifest.
127132 let api_metadata: AllApiMetadata =
128133 parse_toml_file ( & args. api_manifest_path ) ?;
134+
135+ // Build an index of configured same-deployment-unit edges. We use this
136+ // index for validation and lookups.
137+ let same_deployment_unit_edges: BTreeSet < _ > = api_metadata
138+ . same_deployment_unit_rules ( )
139+ . filter_map ( |rule| match & rule. matcher {
140+ RuleMatcher :: Server ( server) => {
141+ Some ( ( server. clone ( ) , rule. client . clone ( ) ) )
142+ }
143+ RuleMatcher :: Ancestor ( _) => {
144+ // This case is rejected at API construction time.
145+ None
146+ }
147+ } )
148+ . collect ( ) ;
149+
129150 // Load Cargo metadata and validate it against the manifest.
130151 let ( workspaces, warnings) = Workspaces :: load ( & api_metadata) ?;
131152 if !warnings. is_empty ( ) {
@@ -295,6 +316,7 @@ impl SystemApis {
295316 api_consumers,
296317 missing_expected_consumers,
297318 api_producers,
319+ same_deployment_unit_edges,
298320 api_metadata,
299321 workspaces,
300322 } )
@@ -339,15 +361,8 @@ impl SystemApis {
339361 server : & ServerComponentName ,
340362 client : & ClientPackageName ,
341363 ) -> bool {
342- self . api_metadata . same_deployment_unit_rules ( ) . any ( |rule| {
343- if rule. client != * client {
344- return false ;
345- }
346- match & rule. matcher {
347- RuleMatcher :: Server ( s) => s == server,
348- RuleMatcher :: Ancestor ( _) => false ,
349- }
350- } )
364+ self . same_deployment_unit_edges
365+ . contains ( & ( server. clone ( ) , client. clone ( ) ) )
351366 }
352367
353368 /// Given a server component, return the APIs consumed by this component
@@ -507,7 +522,7 @@ impl SystemApis {
507522 fn make_deployment_unit_graph (
508523 & self ,
509524 dependency_filter : ApiDependencyFilter ,
510- versioned_how_filter : VersionedHowFilter < ' _ > ,
525+ versioned_how_filter : VersionedHowFilter ,
511526 ) -> Result < (
512527 Graph < & DeploymentUnitName , & ClientPackageName > ,
513528 BTreeMap < & DeploymentUnitName , NodeIndex > ,
@@ -532,9 +547,8 @@ impl SystemApis {
532547 // When building a server-side-versioned-only graph,
533548 // filter to only server-versioned APIs and skip edges
534549 // that represent same-deployment-unit communication.
535- if let VersionedHowFilter :: ServerSideOnly {
536- same_unit_edges,
537- } = & versioned_how_filter
550+ if let VersionedHowFilter :: ServerSideOnly =
551+ versioned_how_filter
538552 {
539553 let api = self
540554 . api_metadata
@@ -544,7 +558,8 @@ impl SystemApis {
544558 continue ;
545559 }
546560
547- if same_unit_edges
561+ if self
562+ . same_deployment_unit_edges
548563 . contains ( & ( server_pkg. clone ( ) , client_pkg. clone ( ) ) )
549564 {
550565 continue ;
@@ -644,7 +659,7 @@ impl SystemApis {
644659 /// 3. The server and API producer are in the same deployment unit.
645660 ///
646661 /// Returns a set of (server, client) pairs.
647- fn compute_required_localhost_edges (
662+ fn compute_required_same_deployment_unit_edges (
648663 & self ,
649664 ) -> Result < BTreeSet < ( ServerComponentName , ClientPackageName ) > > {
650665 // Use the IncludeNonDag filter to include SameDeploymentUnit edges. We
@@ -655,7 +670,6 @@ impl SystemApis {
655670 let mut required = BTreeSet :: new ( ) ;
656671
657672 for ( server, server_unit) in & self . server_component_units {
658-
659673 for ( client, _) in self . component_apis_consumed ( server, filter) ? {
660674 // Only consider server-side-versioned APIs.
661675 let Some ( api) = self . api_metadata . client_pkgname_lookup ( client)
@@ -690,26 +704,11 @@ impl SystemApis {
690704
691705 /// Validates that the configured same-deployment-unit rules exactly match
692706 /// the required set of edges that must be excluded.
693- ///
694- /// Returns the validated set of edges for use by `make_deployment_unit_graph`.
695- fn validate_same_deployment_unit_rules (
696- & self ,
697- ) -> Result < BTreeSet < ( ServerComponentName , ClientPackageName ) > > {
698- let required = self . compute_required_localhost_edges ( ) ?;
699-
700- // Build the configured set from the manifest.
701- let mut configured = BTreeSet :: new ( ) ;
702- for rule in self . api_metadata . same_deployment_unit_rules ( ) {
703- let RuleMatcher :: Server ( server) = & rule. matcher else {
704- unreachable ! (
705- "same-deployment-unit rules must have server matcher \
706- (validated in api_metadata.rs)"
707- ) ;
708- } ;
709- configured. insert ( ( server. clone ( ) , rule. client . clone ( ) ) ) ;
710- }
707+ fn validate_same_deployment_unit_rules ( & self ) -> Result < ( ) > {
708+ let required = self . compute_required_same_deployment_unit_edges ( ) ?;
709+ let configured = & self . same_deployment_unit_edges ;
711710
712- let missing: BTreeSet < _ > = required. difference ( & configured) . collect ( ) ;
711+ let missing: BTreeSet < _ > = required. difference ( configured) . collect ( ) ;
713712 let extra: BTreeSet < _ > = configured. difference ( & required) . collect ( ) ;
714713
715714 if !missing. is_empty ( ) || !extra. is_empty ( ) {
@@ -718,29 +717,37 @@ impl SystemApis {
718717 ) ;
719718
720719 if !missing. is_empty ( ) {
721- msg. push_str ( "\n missing entries (these edges exist and need same-deployment-unit exclusion):\n " ) ;
720+ swriteln ! (
721+ msg,
722+ "\n missing entries (these edges exist and need \
723+ same-deployment-unit exclusion):"
724+ ) ;
722725 for ( server, client) in & missing {
723- msg . push_str ( & format ! (
724- " - server = {:?}, client = {:?} \n " ,
725- server, client
726- ) ) ;
726+ swriteln ! (
727+ msg ,
728+ " - server = {server:?} , client = {client:?}"
729+ ) ;
727730 }
728731 }
729732
730733 if !extra. is_empty ( ) {
731- msg. push_str ( "\n extra entries (these edges don't exist or don't need exclusion):\n " ) ;
734+ swriteln ! (
735+ msg,
736+ "\n extra entries (these edges don't exist or don't need \
737+ exclusion):"
738+ ) ;
732739 for ( server, client) in & extra {
733- msg . push_str ( & format ! (
734- " - server = {:?}, client = {:?} \n " ,
735- server, client
736- ) ) ;
740+ swriteln ! (
741+ msg ,
742+ " - server = {server:?} , client = {client:?}"
743+ ) ;
737744 }
738745 }
739746
740747 bail ! ( "{}" , msg) ;
741748 }
742749
743- Ok ( required )
750+ Ok ( ( ) )
744751 }
745752
746753 /// Verifies various important properties about the assignment of which APIs
@@ -799,7 +806,7 @@ impl SystemApis {
799806
800807 // Validate that all configured same-deployment-unit rules are correct
801808 // and match the required set exactly.
802- let same_unit_edges = self . validate_same_deployment_unit_rules ( ) ?;
809+ self . validate_same_deployment_unit_rules ( ) ?;
803810
804811 // Construct a graph where:
805812 //
@@ -822,9 +829,7 @@ impl SystemApis {
822829 // Do the same with a graph of deployment units.
823830 let ( graph, nodes) = self . make_deployment_unit_graph (
824831 filter,
825- VersionedHowFilter :: ServerSideOnly {
826- same_unit_edges : & same_unit_edges,
827- } ,
832+ VersionedHowFilter :: ServerSideOnly ,
828833 ) ?;
829834 let reverse_nodes: BTreeMap < _ , _ > =
830835 nodes. iter ( ) . map ( |( d_u, node) | ( node, d_u) ) . collect ( ) ;
@@ -1433,14 +1438,12 @@ impl<'a> ClientDependenciesTracker<'a> {
14331438/// Specifies whether to filter to only server-versioned APIs when building
14341439/// dependency graphs.
14351440#[ derive( Clone , Debug ) ]
1436- pub enum VersionedHowFilter < ' a > {
1441+ pub enum VersionedHowFilter {
14371442 /// Include all APIs regardless of versioning strategy.
14381443 All ,
14391444 /// Include only APIs with server-side versioning, and skip edges that
14401445 /// represent same-deployment-unit communication.
1441- ServerSideOnly {
1442- same_unit_edges : & ' a BTreeSet < ( ServerComponentName , ClientPackageName ) > ,
1443- } ,
1446+ ServerSideOnly ,
14441447}
14451448
14461449/// Specifies which API dependencies to include vs. ignore when iterating
@@ -1479,7 +1482,8 @@ pub enum ApiDependencyFilter {
14791482
14801483impl ApiDependencyFilter {
14811484 /// Return whether this filter should include a dependency on
1482- /// `client_pkgname` that goes through dependency path `dep_path`.
1485+ /// `client_pkgname` that goes either through `server` or through
1486+ /// `dep_path`.
14831487 ///
14841488 /// Note: `Evaluation::SameDeploymentUnit` edges are included by all filters
14851489 /// here. These edges represent real dependencies and should appear in
0 commit comments