behavior_actors/operations/
features.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum FeatureStatus {
6 Enabled,
8 Disabled,
10}
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct Feature<F> {
15 pub feature: F,
17 pub status: FeatureStatus,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct FeatureSet<F> {
28 features: Vec<Feature<F>>,
29}
30
31impl<F: Eq> FeatureSet<F> {
32 #[must_use]
34 pub fn new(features: impl IntoIterator<Item = Feature<F>>) -> Self {
35 let mut normalized: Vec<Feature<F>> = Vec::new();
36 for candidate in features {
37 if let Some(existing) = normalized
38 .iter_mut()
39 .find(|existing| existing.feature == candidate.feature)
40 {
41 existing.status = candidate.status;
42 } else {
43 normalized.push(candidate);
44 }
45 }
46 Self {
47 features: normalized,
48 }
49 }
50
51 #[must_use]
53 pub fn features(&self) -> &[Feature<F>] {
54 &self.features
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn duplicate_identity_replaces_status_without_reordering() {
64 let set = FeatureSet::new([
65 Feature {
66 feature: 1,
67 status: FeatureStatus::Disabled,
68 },
69 Feature {
70 feature: 2,
71 status: FeatureStatus::Enabled,
72 },
73 Feature {
74 feature: 1,
75 status: FeatureStatus::Enabled,
76 },
77 ]);
78 assert_eq!(
79 set.features(),
80 [
81 Feature {
82 feature: 1,
83 status: FeatureStatus::Enabled
84 },
85 Feature {
86 feature: 2,
87 status: FeatureStatus::Enabled
88 }
89 ]
90 );
91 }
92}