use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Metadata {
pub feature_groups: Option<FeatureGroups>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct FeatureGroups {
pub features: Option<FeaturesTable>,
#[serde(flatten)]
pub groups: IndexMap<FeatureGroupName, FeatureGroup>,
}
impl FeatureGroups {
pub fn features_in_group<'a>(
&'a self,
feature_group: &FeatureGroupName,
) -> impl Iterator<Item = &'a FeatureName> {
self.groups
.get(feature_group)
.into_iter()
.flat_map(|g| g.features().into_iter().flat_map(|f| f.iter()))
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct FeaturesTable {
#[serde(flatten)]
features: IndexMap<FeatureName, FeatureRelations>,
}
impl FeaturesTable {
pub fn feature_names(&self) -> impl Iterator<Item = &FeatureName> {
self.features.keys()
}
pub fn iter(&self) -> impl Iterator<Item = (&FeatureName, &FeatureRelations)> {
self.features.iter()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "kebab-case")]
pub enum FeatureGroup {
ExactlyOne {
features: Vec<FeatureName>,
},
Xor {
features: Vec<FeatureName>,
},
#[serde(untagged)]
Or {
features: Vec<FeatureName>,
},
}
impl FeatureGroup {
#[must_use]
pub fn features(&self) -> Option<&Vec<FeatureName>> {
match self {
Self::ExactlyOne { features, .. }
| Self::Or { features, .. }
| Self::Xor { features, .. } => Some(features),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct FeatureGroupName(String);
impl FeatureGroupName {
#[must_use]
pub fn name(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for FeatureGroupName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct FeatureName(String);
impl FeatureName {
#[must_use]
pub fn name(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for FeatureName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "kebab-case")]
pub enum FeatureRelations {
Requires {
features: Option<Vec<FeatureName>>,
groups: Option<Vec<FeatureGroupName>>,
},
}