1use crate::{
5 debug_ignore::DebugIgnore,
6 errors::FeatureGraphWarning,
7 graph::{
8 feature::{
9 build::{FeatureGraphBuildState, FeaturePetgraph},
10 Cycles, FeatureFilter, FeatureList, WeakDependencies, WeakIndex,
11 },
12 DependencyDirection, FeatureIndexInPackage, FeatureIx, PackageGraph, PackageIx,
13 PackageLink, PackageMetadata,
14 },
15 petgraph_support::{scc::Sccs, topo::TopoWithCycles},
16 platform::{PlatformStatus, PlatformStatusImpl},
17 DependencyKind, Error, PackageId,
18};
19use ahash::AHashMap;
20use once_cell::sync::OnceCell;
21use petgraph::{
22 algo::has_path_connecting,
23 prelude::*,
24 visit::{EdgeFiltered, IntoNodeReferences},
25};
26use std::{fmt, iter, iter::FromIterator};
27
28impl PackageGraph {
52 pub fn feature_graph(&self) -> FeatureGraph {
57 let inner = self.get_feature_graph();
58 FeatureGraph {
59 package_graph: self,
60 inner,
61 }
62 }
63
64 pub(super) fn get_feature_graph(&self) -> &FeatureGraphImpl {
65 self.feature_graph
66 .get_or_init(|| FeatureGraphImpl::new(self))
67 }
68}
69
70#[derive(Clone, Copy, Debug)]
74pub struct FeatureGraph<'g> {
75 pub(crate) package_graph: &'g PackageGraph,
76 pub(super) inner: &'g FeatureGraphImpl,
77}
78
79assert_covariant!(FeatureGraph);
80
81impl<'g> FeatureGraph<'g> {
82 pub fn build_warnings(&self) -> &'g [FeatureGraphWarning] {
84 &self.inner.warnings
85 }
86
87 pub fn package_graph(&self) -> &'g PackageGraph {
89 self.package_graph
90 }
91
92 pub fn feature_count(&self) -> usize {
96 self.dep_graph().node_count()
97 }
98
99 pub fn link_count(&self) -> usize {
101 self.dep_graph().edge_count()
102 }
103
104 pub fn contains(&self, feature_id: impl Into<FeatureId<'g>>) -> bool {
106 let feature_id = feature_id.into();
107 FeatureNode::from_id(self, feature_id).is_some()
108 }
109
110 pub fn metadata(
112 &self,
113 feature_id: impl Into<FeatureId<'g>>,
114 ) -> Result<FeatureMetadata<'g>, Error> {
115 let feature_id = feature_id.into();
116 let feature_node = FeatureNode::from_id(self, feature_id)
117 .ok_or_else(|| Error::unknown_feature_id(feature_id))?;
118 self.metadata_for_node(feature_node)
119 .ok_or_else(|| Error::unknown_feature_id(feature_id))
120 }
121
122 pub fn all_features_for(&self, package_id: &PackageId) -> Result<FeatureList<'g>, Error> {
126 let package = self.package_graph.metadata(package_id)?;
127 let dep_graph = self.dep_graph();
128 let features = self
129 .feature_ixs_for_package_ix(package.package_ix())
130 .map(|feature_ix| FeatureId::node_to_feature(package, &dep_graph[feature_ix]));
131 Ok(FeatureList::new(package, features))
132 }
133
134 pub fn is_default_feature<'a>(
144 &self,
145 feature_id: impl Into<FeatureId<'a>>,
146 ) -> Result<bool, Error> {
147 let feature_id = feature_id.into();
148 let default_ix = self.feature_ix(
149 self.package_graph
150 .metadata(feature_id.package_id())?
151 .default_feature_id(),
152 )?;
153 let feature_ix = self.feature_ix(feature_id)?;
154 Ok(self.feature_ix_depends_on_no_conditional(default_ix, feature_ix))
156 }
157
158 pub fn depends_on<'a>(
167 &self,
168 feature_a: impl Into<FeatureId<'a>>,
169 feature_b: impl Into<FeatureId<'a>>,
170 ) -> Result<bool, Error> {
171 let feature_a = feature_a.into();
172 let feature_b = feature_b.into();
173 let a_ix = self.feature_ix(feature_a)?;
174 let b_ix = self.feature_ix(feature_b)?;
175 Ok(self.feature_ix_depends_on(a_ix, b_ix))
176 }
177
178 pub fn directly_depends_on<'a>(
184 &self,
185 feature_a: impl Into<FeatureId<'a>>,
186 feature_b: impl Into<FeatureId<'a>>,
187 ) -> Result<bool, Error> {
188 let feature_a = feature_a.into();
189 let feature_b = feature_b.into();
190 let a_ix = self.feature_ix(feature_a)?;
191 let b_ix = self.feature_ix(feature_b)?;
192 Ok(self.dep_graph().contains_edge(a_ix, b_ix))
193 }
194
195 pub fn cycles(&self) -> Cycles<'g> {
199 Cycles::new(*self)
200 }
201
202 #[doc(hidden)]
208 pub fn verify(&self) -> Result<(), Error> {
209 let feature_set = self.resolve_all();
210 for conditional_link in feature_set.conditional_links(DependencyDirection::Forward) {
211 let (from, to) = conditional_link.endpoints();
212 let is_any = conditional_link.normal().is_present()
213 || conditional_link.build().is_present()
214 || conditional_link.dev().is_present();
215
216 if !is_any {
217 return Err(Error::FeatureGraphInternalError(format!(
218 "{} -> {}: no edge info found",
219 from.feature_id(),
220 to.feature_id()
221 )));
222 }
223 }
224
225 Ok(())
226 }
227
228 pub(super) fn sccs(&self) -> &'g Sccs<FeatureIx> {
230 self.inner.sccs.get_or_init(|| {
231 let edge_filtered =
232 EdgeFiltered::from_fn(self.dep_graph(), |edge| match edge.weight() {
233 FeatureEdge::DependenciesSection(link)
234 | FeatureEdge::NamedFeatureDepColon(link)
235 | FeatureEdge::NamedFeatureWithSlash { link, .. } => !link.dev_only(),
236 FeatureEdge::NamedFeature | FeatureEdge::FeatureToBase => true,
237 });
238 let topo = TopoWithCycles::new(&edge_filtered);
242 Sccs::new(&self.inner.graph, |scc| {
243 topo.sort_nodes(scc);
244 })
245 })
246 }
247
248 fn metadata_impl(&self, feature_id: FeatureId<'g>) -> Option<&'g FeatureMetadataImpl> {
249 let feature_node = FeatureNode::from_id(self, feature_id)?;
250 self.metadata_impl_for_node(&feature_node)
251 }
252
253 pub(in crate::graph) fn metadata_for_ix(
254 &self,
255 feature_ix: NodeIndex<FeatureIx>,
256 ) -> FeatureMetadata<'g> {
257 self.metadata_for_node(self.dep_graph()[feature_ix])
258 .expect("valid feature ix")
259 }
260
261 pub(super) fn metadata_for_node(&self, node: FeatureNode) -> Option<FeatureMetadata<'g>> {
262 let inner = self.metadata_impl_for_node(&node)?;
263 Some(FeatureMetadata {
264 graph: DebugIgnore(*self),
265 node,
266 inner,
267 })
268 }
269
270 #[inline]
271 fn metadata_impl_for_node(&self, node: &FeatureNode) -> Option<&'g FeatureMetadataImpl> {
272 self.inner.map.get(node)
273 }
274
275 pub(super) fn dep_graph(&self) -> &'g FeaturePetgraph {
276 &self.inner.graph
277 }
278
279 pub(super) fn edge_to_conditional_link(
281 &self,
282 source_ix: NodeIndex<FeatureIx>,
283 target_ix: NodeIndex<FeatureIx>,
284 edge_ix: EdgeIndex<FeatureIx>,
285 edge: Option<&'g FeatureEdge>,
286 ) -> Option<(ConditionalLink<'g>, Option<WeakIndex>)> {
287 let edge = edge.unwrap_or_else(|| &self.dep_graph()[edge_ix]);
288
289 match edge {
290 FeatureEdge::NamedFeature | FeatureEdge::FeatureToBase => None,
291 FeatureEdge::DependenciesSection(link) | FeatureEdge::NamedFeatureDepColon(link) => {
292 let link = ConditionalLink::new(*self, source_ix, target_ix, edge_ix, link);
293 let weak_index = None;
295 Some((link, weak_index))
296 }
297 FeatureEdge::NamedFeatureWithSlash { link, weak_index } => {
298 let link = ConditionalLink::new(*self, source_ix, target_ix, edge_ix, link);
299 Some((link, *weak_index))
300 }
301 }
302 }
303
304 fn feature_ix_depends_on(
305 &self,
306 a_ix: NodeIndex<FeatureIx>,
307 b_ix: NodeIndex<FeatureIx>,
308 ) -> bool {
309 has_path_connecting(self.dep_graph(), a_ix, b_ix, None)
310 }
311
312 fn feature_ix_depends_on_no_conditional(
313 &self,
314 a_ix: NodeIndex<FeatureIx>,
315 b_ix: NodeIndex<FeatureIx>,
316 ) -> bool {
317 let edge_filtered =
319 EdgeFiltered::from_fn(self.dep_graph(), |edge_ref| match edge_ref.weight() {
320 FeatureEdge::FeatureToBase | FeatureEdge::NamedFeature => true,
321 FeatureEdge::DependenciesSection(_)
322 | FeatureEdge::NamedFeatureDepColon(_)
323 | FeatureEdge::NamedFeatureWithSlash { .. } => false,
324 });
325 has_path_connecting(&edge_filtered, a_ix, b_ix, None)
326 }
327
328 pub(super) fn feature_ixs_for_package_ix(
329 &self,
330 package_ix: NodeIndex<PackageIx>,
331 ) -> impl Iterator<Item = NodeIndex<FeatureIx>> {
332 let package_ix = package_ix.index();
333 let base_ix = self.inner.base_ixs[package_ix].index();
334 let next_base_ix = self.inner.base_ixs[package_ix + 1].index();
336
337 (base_ix..next_base_ix).map(NodeIndex::new)
338 }
339
340 pub(super) fn feature_ixs_for_package_ixs(
341 &self,
342 package_ixs: impl IntoIterator<Item = NodeIndex<PackageIx>> + 'g,
343 ) -> impl Iterator<Item = NodeIndex<FeatureIx>> + 'g {
344 let this = *self;
346
347 package_ixs
348 .into_iter()
349 .flat_map(move |package_ix| this.feature_ixs_for_package_ix(package_ix))
350 }
351
352 pub(in crate::graph) fn feature_ixs_for_package_ixs_filtered<B>(
353 &self,
354 package_ixs: impl IntoIterator<Item = NodeIndex<PackageIx>>,
355 filter: impl FeatureFilter<'g>,
356 ) -> B
357 where
358 B: FromIterator<NodeIndex<FeatureIx>>,
359 {
360 let mut filter = filter;
361
362 self.feature_ixs_for_package_ixs(package_ixs)
363 .filter(|feature_ix| {
364 let feature_node = &self.dep_graph()[*feature_ix];
365 filter.accept(self, FeatureId::from_node(self.package_graph, feature_node))
366 })
367 .collect()
368 }
369
370 pub(in crate::graph) fn package_ix_for_feature_ix(
371 &self,
372 feature_ix: NodeIndex<FeatureIx>,
373 ) -> NodeIndex<PackageIx> {
374 let feature_node = &self.dep_graph()[feature_ix];
375 feature_node.package_ix()
376 }
377
378 #[allow(dead_code)]
379 pub(super) fn feature_ixs<'a, B>(
380 &self,
381 feature_ids: impl IntoIterator<Item = FeatureId<'g>>,
382 ) -> Result<B, Error>
383 where
384 B: iter::FromIterator<NodeIndex<FeatureIx>>,
385 {
386 feature_ids
387 .into_iter()
388 .map(|feature_id| self.feature_ix(feature_id))
389 .collect()
390 }
391
392 pub(super) fn feature_ix(
393 &self,
394 feature_id: FeatureId<'g>,
395 ) -> Result<NodeIndex<FeatureIx>, Error> {
396 let metadata = self
397 .metadata_impl(feature_id)
398 .ok_or_else(|| Error::unknown_feature_id(feature_id))?;
399 Ok(metadata.feature_ix)
400 }
401}
402
403#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
410pub struct FeatureId<'g> {
411 package_id: &'g PackageId,
412 label: FeatureLabel<'g>,
413}
414
415assert_covariant!(FeatureId);
416
417impl<'g> FeatureId<'g> {
418 pub fn new(package_id: &'g PackageId, label: FeatureLabel<'g>) -> Self {
420 Self { package_id, label }
421 }
422
423 pub fn named(package_id: &'g PackageId, feature_name: &'g str) -> Self {
426 Self {
427 package_id,
428 label: FeatureLabel::Named(feature_name),
429 }
430 }
431
432 pub fn optional_dependency(package_id: &'g PackageId, dep_name: &'g str) -> Self {
434 Self {
435 package_id,
436 label: FeatureLabel::OptionalDependency(dep_name),
437 }
438 }
439
440 pub fn base(package_id: &'g PackageId) -> Self {
442 Self {
443 package_id,
444 label: FeatureLabel::Base,
445 }
446 }
447
448 pub(super) fn from_node(package_graph: &'g PackageGraph, node: &FeatureNode) -> Self {
449 let package_id = &package_graph.dep_graph[node.package_ix];
450 let metadata = package_graph
451 .metadata(package_id)
452 .expect("package ID should have valid metadata");
453 let feature = Self::node_to_feature(metadata, node);
454 Self {
455 package_id,
456 label: feature,
457 }
458 }
459
460 pub(super) fn node_to_feature(
461 metadata: PackageMetadata<'g>,
462 node: &FeatureNode,
463 ) -> FeatureLabel<'g> {
464 metadata.feature_idx_to_label(node.feature_idx)
465 }
466
467 pub fn package_id(&self) -> &'g PackageId {
469 self.package_id
470 }
471
472 pub fn label(&self) -> FeatureLabel<'g> {
474 self.label
475 }
476
477 #[inline]
479 pub fn is_base(&self) -> bool {
480 self.label.kind().is_base()
481 }
482
483 #[inline]
485 pub fn is_optional_dependency(self) -> bool {
486 self.label.kind().is_optional_dependency()
487 }
488
489 #[inline]
491 pub fn is_named(self) -> bool {
492 self.label.kind().is_named()
493 }
494}
495
496impl<'g> From<(&'g PackageId, FeatureLabel<'g>)> for FeatureId<'g> {
497 fn from((package_id, label): (&'g PackageId, FeatureLabel<'g>)) -> Self {
498 FeatureId { package_id, label }
499 }
500}
501
502impl fmt::Display for FeatureId<'_> {
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533 write!(f, "{}/{}", self.package_id, self.label)
534 }
535}
536
537#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
539pub enum FeatureLabel<'g> {
540 Base,
542
543 Named(&'g str),
550
551 OptionalDependency(&'g str),
553}
554
555impl FeatureLabel<'_> {
556 #[inline]
560 pub fn kind(self) -> FeatureKind {
561 match self {
562 Self::Base => FeatureKind::Base,
563 Self::Named(_) => FeatureKind::Named,
564 Self::OptionalDependency(_) => FeatureKind::OptionalDependency,
565 }
566 }
567}
568
569impl fmt::Display for FeatureLabel<'_> {
585 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
586 match self {
587 Self::Base => write!(f, "[base]"),
588 Self::Named(feature_name) => write!(f, "{}", feature_name),
589 Self::OptionalDependency(dep_name) => write!(f, "dep:{}", dep_name),
590 }
591 }
592}
593
594#[derive(Clone, Copy)]
596pub struct FeatureMetadata<'g> {
597 graph: DebugIgnore<FeatureGraph<'g>>,
598 node: FeatureNode,
599 inner: &'g FeatureMetadataImpl,
600}
601
602assert_covariant!(FeatureMetadata);
603
604impl<'g> FeatureMetadata<'g> {
605 pub fn feature_id(&self) -> FeatureId<'g> {
607 FeatureId::from_node(self.graph.package_graph, &self.node)
608 }
609
610 pub fn package_id(&self) -> &'g PackageId {
612 &self.graph.package_graph.dep_graph[self.package_ix()]
613 }
614
615 pub fn package(&self) -> PackageMetadata<'g> {
617 self.graph
618 .package_graph
619 .metadata(self.package_id())
620 .expect("valid package ID")
621 }
622
623 pub fn label(&self) -> FeatureLabel<'g> {
625 self.feature_id().label()
626 }
627
628 #[inline]
633 pub(in crate::graph) fn package_ix(&self) -> NodeIndex<PackageIx> {
634 self.node.package_ix
635 }
636
637 #[inline]
638 pub(in crate::graph) fn feature_ix(&self) -> NodeIndex<FeatureIx> {
639 self.inner.feature_ix
640 }
641}
642
643impl fmt::Debug for FeatureMetadata<'_> {
644 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
645 f.debug_struct("FeatureMetadata")
646 .field("id", &self.feature_id())
647 .finish()
648 }
649}
650
651#[derive(Clone, Debug)]
653pub(in crate::graph) struct FeatureGraphImpl {
654 pub(super) graph: FeaturePetgraph,
655 pub(super) base_ixs: Vec<NodeIndex<FeatureIx>>,
657 pub(super) map: AHashMap<FeatureNode, FeatureMetadataImpl>,
658 pub(super) warnings: Vec<FeatureGraphWarning>,
659 pub(super) sccs: OnceCell<Sccs<FeatureIx>>,
661 pub(super) weak: WeakDependencies,
662}
663
664impl FeatureGraphImpl {
665 pub(super) fn new(package_graph: &PackageGraph) -> Self {
667 let mut build_state = FeatureGraphBuildState::new(package_graph);
668
669 let mut prev_ix = None;
671 for (package_ix, package_id) in package_graph.dep_graph.node_references() {
672 if let Some(prev_ix) = prev_ix {
673 debug_assert_eq!(package_ix.index(), prev_ix + 1, "package ixs are in order");
674 }
675 prev_ix = Some(package_ix.index());
676
677 let metadata = package_graph
678 .metadata(package_id)
679 .expect("valid package ID");
680 build_state.add_nodes(metadata);
681 }
682
683 build_state.end_nodes();
684
685 for metadata in package_graph
687 .resolve_all()
688 .packages(DependencyDirection::Reverse)
689 {
690 build_state.add_named_feature_edges(metadata);
691 }
692
693 for link in package_graph
694 .resolve_all()
695 .links(DependencyDirection::Reverse)
696 {
697 build_state.add_dependency_edges(link);
698 }
699
700 build_state.build()
701 }
702}
703
704#[derive(Copy, Clone)]
733pub struct ConditionalLink<'g> {
734 graph: DebugIgnore<FeatureGraph<'g>>,
735 from: &'g FeatureMetadataImpl,
736 to: &'g FeatureMetadataImpl,
737 edge_ix: EdgeIndex<FeatureIx>,
738 inner: &'g ConditionalLinkImpl,
739}
740
741assert_covariant!(ConditionalLink);
742
743impl<'g> ConditionalLink<'g> {
744 #[allow(dead_code)]
745 pub(super) fn new(
746 graph: FeatureGraph<'g>,
747 source_ix: NodeIndex<FeatureIx>,
748 target_ix: NodeIndex<FeatureIx>,
749 edge_ix: EdgeIndex<FeatureIx>,
750 inner: &'g ConditionalLinkImpl,
751 ) -> Self {
752 let dep_graph = graph.dep_graph();
753 Self {
754 graph: DebugIgnore(graph),
755 from: graph
756 .metadata_impl_for_node(&dep_graph[source_ix])
757 .expect("valid source ix"),
758 to: graph
759 .metadata_impl_for_node(&dep_graph[target_ix])
760 .expect("valid target ix"),
761 edge_ix,
762 inner,
763 }
764 }
765
766 pub fn from(&self) -> FeatureMetadata<'g> {
768 FeatureMetadata {
769 graph: DebugIgnore(self.graph.0),
770 node: self.graph.dep_graph()[self.from.feature_ix],
771 inner: self.from,
772 }
773 }
774
775 pub fn to(&self) -> FeatureMetadata<'g> {
777 FeatureMetadata {
778 graph: DebugIgnore(self.graph.0),
779 node: self.graph.dep_graph()[self.to.feature_ix],
780 inner: self.to,
781 }
782 }
783
784 pub fn endpoints(&self) -> (FeatureMetadata<'g>, FeatureMetadata<'g>) {
786 (self.from(), self.to())
787 }
788
789 pub fn normal(&self) -> PlatformStatus<'g> {
791 PlatformStatus::new(&self.inner.normal)
792 }
793
794 pub fn build(&self) -> PlatformStatus<'g> {
796 PlatformStatus::new(&self.inner.build)
797 }
798
799 pub fn dev(&self) -> PlatformStatus<'g> {
801 PlatformStatus::new(&self.inner.dev)
802 }
803
804 pub fn status_for_kind(&self, kind: DependencyKind) -> PlatformStatus<'g> {
807 match kind {
808 DependencyKind::Normal => self.normal(),
809 DependencyKind::Build => self.build(),
810 DependencyKind::Development => self.dev(),
811 }
812 }
813
814 pub fn dev_only(&self) -> bool {
817 self.inner.dev_only()
818 }
819
820 pub fn package_link(&self) -> PackageLink<'g> {
822 self.graph
823 .package_graph
824 .edge_ix_to_link(self.inner.package_edge_ix)
825 }
826
827 #[allow(dead_code)]
832 pub(super) fn edge_ix(&self) -> EdgeIndex<FeatureIx> {
833 self.edge_ix
834 }
835
836 #[allow(dead_code)]
837 pub(in crate::graph) fn package_edge_ix(&self) -> EdgeIndex<PackageIx> {
838 self.inner.package_edge_ix
839 }
840}
841
842impl fmt::Debug for ConditionalLink<'_> {
843 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
844 f.debug_struct("ConditionalLink")
845 .field("from", &self.from())
846 .field("to", &self.to())
847 .field("normal", &self.normal())
848 .field("build", &self.build())
849 .field("dev", &self.dev())
850 .finish()
851 }
852}
853
854#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
858pub(in crate::graph) struct FeatureNode {
859 package_ix: NodeIndex<PackageIx>,
860 feature_idx: FeatureIndexInPackage,
861}
862
863impl FeatureNode {
864 pub(in crate::graph) fn new(
866 package_ix: NodeIndex<PackageIx>,
867 feature_idx: FeatureIndexInPackage,
868 ) -> Self {
869 Self {
870 package_ix,
871 feature_idx,
872 }
873 }
874
875 pub(in crate::graph) fn base(package_ix: NodeIndex<PackageIx>) -> Self {
877 Self {
878 package_ix,
879 feature_idx: FeatureIndexInPackage::Base,
880 }
881 }
882
883 pub(in crate::graph) fn optional_dep(package_ix: NodeIndex<PackageIx>, dep_idx: usize) -> Self {
884 Self {
885 package_ix,
886 feature_idx: FeatureIndexInPackage::OptionalDependency(dep_idx),
887 }
888 }
889
890 pub(in crate::graph) fn named_feature(
891 package_ix: NodeIndex<PackageIx>,
892 named_idx: usize,
893 ) -> Self {
894 Self {
895 package_ix,
896 feature_idx: FeatureIndexInPackage::Named(named_idx),
897 }
898 }
899
900 fn from_id(feature_graph: &FeatureGraph<'_>, id: FeatureId<'_>) -> Option<Self> {
901 let metadata = feature_graph.package_graph.metadata(id.package_id()).ok()?;
902 Some(FeatureNode::new(
903 metadata.package_ix(),
904 metadata.get_feature_idx(id.label())?,
905 ))
906 }
907
908 pub(super) fn named_features(package: PackageMetadata<'_>) -> impl Iterator<Item = Self> + '_ {
909 let package_ix = package.package_ix();
910 package
911 .named_features_full()
912 .map(move |(feature_idx, _, _)| Self {
913 package_ix,
914 feature_idx,
915 })
916 }
917
918 pub(super) fn optional_deps(package: PackageMetadata<'_>) -> impl Iterator<Item = Self> + '_ {
919 let package_ix = package.package_ix();
920 package
921 .optional_deps_full()
922 .map(move |(feature_idx, _)| Self {
923 package_ix,
924 feature_idx,
925 })
926 }
927
928 pub(in crate::graph) fn package_ix(&self) -> NodeIndex<PackageIx> {
929 self.package_ix
930 }
931
932 pub(in crate::graph) fn package_id_and_feature_label<'g>(
933 &self,
934 graph: &'g PackageGraph,
935 ) -> (&'g PackageId, FeatureLabel<'g>) {
936 let package_id = &graph.dep_graph[self.package_ix];
937 let metadata = graph.metadata(package_id).unwrap();
938 let feature_label = metadata.feature_idx_to_label(self.feature_idx);
939 (package_id, feature_label)
940 }
941}
942
943#[derive(Clone, Debug)]
947#[doc(hidden)]
948pub enum FeatureEdge {
949 FeatureToBase,
951
952 DependenciesSection(ConditionalLinkImpl),
970
971 NamedFeature,
978
979 NamedFeatureDepColon(ConditionalLinkImpl),
986
987 NamedFeatureWithSlash {
996 link: ConditionalLinkImpl,
997 weak_index: Option<WeakIndex>,
998 },
999}
1000
1001#[derive(Clone, Debug)]
1003#[doc(hidden)]
1004pub struct ConditionalLinkImpl {
1005 pub(super) package_edge_ix: EdgeIndex<PackageIx>,
1006 pub(super) normal: PlatformStatusImpl,
1007 pub(super) build: PlatformStatusImpl,
1008 pub(super) dev: PlatformStatusImpl,
1009}
1010
1011impl ConditionalLinkImpl {
1012 #[inline]
1013 fn dev_only(&self) -> bool {
1014 self.normal.is_never() && self.build.is_never()
1015 }
1016}
1017
1018#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1020pub(super) struct FeatureMetadataImpl {
1021 pub(super) feature_ix: NodeIndex<FeatureIx>,
1022}
1023
1024#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1028pub enum FeatureKind {
1029 Base,
1031
1032 Named,
1039
1040 OptionalDependency,
1042}
1043
1044impl FeatureKind {
1045 #[inline]
1047 pub fn is_base(self) -> bool {
1048 matches!(self, Self::Base)
1049 }
1050
1051 #[inline]
1053 pub fn is_named(self) -> bool {
1054 matches!(self, Self::Named)
1055 }
1056
1057 #[inline]
1059 pub fn is_optional_dependency(self) -> bool {
1060 matches!(self, Self::OptionalDependency)
1061 }
1062}