litcheck_lit/config/
features.rs

1use std::{borrow::Borrow, collections::BTreeSet};
2
3use litcheck::StaticCow;
4use serde::Deserialize;
5
6use super::BooleanExpr;
7
8#[derive(Default, Clone, Deserialize)]
9#[serde(transparent)]
10pub struct FeatureSet {
11    pub features: BTreeSet<StaticCow<str>>,
12}
13impl IntoIterator for FeatureSet {
14    type Item = StaticCow<str>;
15    type IntoIter = std::collections::btree_set::IntoIter<Self::Item>;
16
17    fn into_iter(self) -> Self::IntoIter {
18        self.features.into_iter()
19    }
20}
21impl FeatureSet {
22    #[allow(unused)]
23    pub fn new<I, S>(features: I) -> Self
24    where
25        StaticCow<str>: From<S>,
26        I: IntoIterator<Item = S>,
27    {
28        let features = features.into_iter().map(StaticCow::from).collect();
29        Self { features }
30    }
31
32    #[inline]
33    pub fn is_empty(&self) -> bool {
34        self.features.is_empty()
35    }
36
37    pub fn contains<Q>(&self, feature: &Q) -> bool
38    where
39        Q: Ord + ?Sized,
40        StaticCow<str>: Borrow<Q>,
41    {
42        self.features.contains(feature)
43    }
44
45    pub fn iter(&self) -> std::collections::btree_set::Iter<'_, StaticCow<str>> {
46        self.features.iter()
47    }
48
49    pub fn insert<S>(&mut self, feature: S)
50    where
51        StaticCow<str>: From<S>,
52    {
53        self.features.insert(StaticCow::from(feature));
54    }
55
56    pub fn extend<I, S>(&mut self, features: I)
57    where
58        StaticCow<str>: From<S>,
59        I: IntoIterator<Item = S>,
60    {
61        self.features
62            .extend(features.into_iter().map(StaticCow::from));
63    }
64
65    pub fn missing_features<F: AsRef<BooleanExpr>>(&self, required: &[F]) -> Option<String> {
66        use std::fmt::Write;
67
68        let mut buf = String::new();
69        for expr in required {
70            let expr = expr.as_ref();
71            if !expr.evaluate(&self.features) {
72                if buf.is_empty() {
73                    buf.push_str("Test requires the following unavailable features: ");
74                } else {
75                    buf.push_str(", ");
76                }
77                write!(&mut buf, "{}", expr).unwrap();
78            }
79        }
80        if buf.is_empty() {
81            None
82        } else {
83            Some(buf)
84        }
85    }
86
87    pub fn unsupported_features<F: AsRef<BooleanExpr>>(&self, unsupported: &[F]) -> Option<String> {
88        use std::fmt::Write;
89
90        let mut buf = String::new();
91        for expr in unsupported {
92            let expr = expr.as_ref();
93            if expr.evaluate(&self.features) {
94                if buf.is_empty() {
95                    buf.push_str("Test does not support the following features: ");
96                } else {
97                    buf.push_str(", ");
98                }
99                write!(&mut buf, "{}", expr).unwrap();
100            }
101        }
102        if buf.is_empty() {
103            None
104        } else {
105            Some(buf)
106        }
107    }
108}