featurecomb_schema/
lib.rs

1//! The schema for the custom
2//! [`[metadata]`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table)
3//! subtable for featurecomb.
4
5use indexmap::IndexMap;
6use serde::{Deserialize, Serialize};
7
8/// Represents the custom [`[metadata]`
9/// section](https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table) of a crate
10/// manifest.
11#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12#[serde(rename_all = "kebab-case")]
13pub struct Metadata {
14    /// Custom subtable for featurecomb.
15    pub feature_groups: Option<FeatureGroups>,
16}
17
18/// Custom
19/// [`[metadata]`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table)
20/// subtable for featurecomb.
21#[derive(Debug, Clone, Default, Serialize, Deserialize)]
22#[serde(rename_all = "kebab-case")]
23pub struct FeatureGroups {
24    /// Features.
25    pub features: Option<FeaturesTable>,
26    /// Feature groups.
27    #[serde(flatten)]
28    pub groups: IndexMap<FeatureGroupName, FeatureGroup>,
29}
30
31impl FeatureGroups {
32    /// Returns an iterator over features that are part of the given feature group.
33    pub fn features_in_group<'a>(
34        &'a self,
35        feature_group: &FeatureGroupName,
36    ) -> impl Iterator<Item = &'a FeatureName> {
37        self.groups
38            .get(feature_group)
39            .into_iter()
40            .flat_map(|g| g.features().into_iter().flat_map(|f| f.iter()))
41    }
42}
43
44/// A table similar to
45/// [`[features]`](https://doc.rust-lang.org/cargo/reference/features.html#the-features-section),
46/// with custom values.
47#[derive(Debug, Clone, Default, Serialize, Deserialize)]
48#[serde(rename_all = "kebab-case")]
49pub struct FeaturesTable {
50    #[serde(flatten)]
51    features: IndexMap<FeatureName, FeatureRelations>,
52}
53
54impl FeaturesTable {
55    /// Returns an iterator over the features names, i.e., the table's keys.
56    pub fn feature_names(&self) -> impl Iterator<Item = &FeatureName> {
57        self.features.keys()
58    }
59
60    /// Returns an iterator over the table entries.
61    pub fn iter(&self) -> impl Iterator<Item = (&FeatureName, &FeatureRelations)> {
62        self.features.iter()
63    }
64}
65
66/// Defines a feature group.
67#[derive(Debug, Clone, Serialize, Deserialize)]
68#[serde(deny_unknown_fields)]
69#[serde(rename_all = "kebab-case")]
70pub enum FeatureGroup {
71    /// Defines a feature group whose features are mutually exclusive and one must always
72    /// be enabled.
73    ExactlyOne {
74        /// Features of the group.
75        features: Vec<FeatureName>,
76    },
77    /// Defines a feature group whose features are mutually exclusive.
78    Xor {
79        /// Features of the group.
80        features: Vec<FeatureName>,
81    },
82    /// Defines a feature group with no relations between its features.
83    #[serde(untagged)]
84    Or {
85        /// Features of the group.
86        features: Vec<FeatureName>,
87    },
88}
89
90impl FeatureGroup {
91    /// Returns the features part of the feature group.
92    /// Returns `None` when the variant contains no features.
93    ///
94    /// The relation between these features depends on the feature group variant.
95    #[must_use]
96    pub fn features(&self) -> Option<&Vec<FeatureName>> {
97        match self {
98            Self::ExactlyOne { features, .. }
99            | Self::Or { features, .. }
100            | Self::Xor { features, .. } => Some(features),
101        }
102    }
103}
104
105/// A feature group name.
106#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
107pub struct FeatureGroupName(String);
108
109impl FeatureGroupName {
110    /// Returns the feature group name.
111    #[must_use]
112    pub fn name(&self) -> &str {
113        &self.0
114    }
115}
116
117impl std::fmt::Display for FeatureGroupName {
118    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119        write!(f, "{}", self.0)
120    }
121}
122
123/// A feature name.
124#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
125pub struct FeatureName(String);
126
127impl FeatureName {
128    /// Returns the feature name.
129    #[must_use]
130    pub fn name(&self) -> &str {
131        &self.0
132    }
133}
134
135impl std::fmt::Display for FeatureName {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        write!(f, "{}", self.0)
138    }
139}
140
141/// Represents the relations defined for a feature.
142#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(deny_unknown_fields)]
144#[serde(rename_all = "kebab-case")]
145pub enum FeatureRelations {
146    /// Defines the features and feature groups that a features *requires*.
147    Requires {
148        /// Features *required* by the feature.
149        // Uses an Option similarly to
150        // https://docs.rs/cargo-util-schemas/latest/cargo_util_schemas/manifest/struct.TomlDetailedDependency.html#structfield.features
151        features: Option<Vec<FeatureName>>,
152        /// Feature groups *required* by the feature.
153        groups: Option<Vec<FeatureGroupName>>,
154    },
155}