feature_set/
feature_set.rs

1use std::collections::BTreeMap;
2use std::fmt;
3
4use crate::action::Action;
5use crate::feature::Feature;
6use crate::Provide;
7use crate::Require;
8
9/// A collection of features, indexed by `(feature_name, feature_version)`.
10#[derive(Debug, Clone)]
11pub struct FeatureSet {
12    features: BTreeMap<(&'static str, u64), Feature>,
13}
14
15impl FeatureSet {
16    /// Create a new `FeatureSet` from a sequence of actions that add or remove a provided feature.
17    pub fn from_provides<'a>(provides: impl IntoIterator<Item = &'a Action<Provide>>) -> Self {
18        let mut features = BTreeMap::new();
19        for a in provides {
20            match a {
21                Action::Add(p) => {
22                    let feature = p.feature();
23                    let key = (feature.name(), feature.ver());
24
25                    assert!(
26                        !features.contains_key(&key),
27                        "duplicate feature: {:?}",
28                        feature
29                    );
30
31                    features.insert(key, feature.clone());
32                }
33                Action::Delete(p) => {
34                    let feature = p.feature();
35                    let key = (feature.name(), feature.ver());
36
37                    assert!(
38                        features.contains_key(&key),
39                        "feature not found: {:?}",
40                        feature
41                    );
42
43                    features.remove(&key);
44                }
45            }
46        }
47
48        Self { features }
49    }
50
51    /// Create a new `FeatureSet` from a sequence of actions that add or remove a required feature.
52    ///
53    /// If `include_optional` is `true`, then optional features are included in the resulting
54    /// `FeatureSet`.
55    pub fn from_required<'a>(
56        required: impl IntoIterator<Item = &'a Action<Require>>,
57        include_optional: bool,
58    ) -> Self {
59        let mut features = BTreeMap::new();
60        for a in required {
61            match a {
62                Action::Add(p) => {
63                    if !include_optional && p.optional() {
64                        continue;
65                    }
66
67                    let feature = p.feature();
68                    let key = (feature.name(), feature.ver());
69
70                    assert!(
71                        !features.contains_key(&key),
72                        "duplicate feature: {:?}",
73                        feature
74                    );
75
76                    features.insert(key, feature.clone());
77                }
78                Action::Delete(p) => {
79                    let feature = p.feature();
80                    let key = (feature.name(), feature.ver());
81
82                    assert!(
83                        features.contains_key(&key),
84                        "feature not found: {:?}",
85                        feature
86                    );
87
88                    features.remove(&(feature.name(), feature.ver()));
89                }
90            }
91        }
92
93        Self { features }
94    }
95
96    pub fn contains(&self, name_ver: (&str, u64)) -> bool {
97        self.features.contains_key(&name_ver)
98    }
99}
100
101impl fmt::Display for FeatureSet {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        write!(
104            f,
105            "{}",
106            self.features
107                .keys()
108                .map(|(n, v)| { format!("{}:v{:}", n, v) })
109                .collect::<Vec<_>>()
110                .join(", ")
111        )
112    }
113}