diskann_benchmark_runner/
features.rs1use crate::utils::fmt;
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
43pub struct Features(FeaturesInner);
44
45#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
46pub(crate) enum FeaturesInner {
47 Only(&'static str),
48 Any(Vec<&'static str>),
49 All(Vec<&'static str>),
50 Custom { custom: &'static str, plural: bool },
51}
52
53impl Features {
54 pub fn new(feature: &'static str) -> Self {
56 Self(FeaturesInner::Only(feature))
57 }
58
59 pub fn any<I>(itr: I) -> Self
61 where
62 I: IntoIterator<Item = &'static str>,
63 {
64 Self(FeaturesInner::Any(itr.into_iter().collect()))
65 }
66
67 pub fn all<I>(itr: I) -> Self
69 where
70 I: IntoIterator<Item = &'static str>,
71 {
72 Self(FeaturesInner::All(itr.into_iter().collect()))
73 }
74
75 pub fn custom(custom: &'static str, plural: bool) -> Self {
78 Self(FeaturesInner::Custom { custom, plural })
79 }
80
81 #[cfg(any(test, feature = "test-app"))]
87 pub(crate) fn satisfied_by(&self, enabled: &std::collections::HashSet<String>) -> bool {
88 match &self.0 {
89 FeaturesInner::Only(feature) => enabled.contains(*feature),
90 FeaturesInner::Any(any) => any.iter().any(|f| enabled.contains(*f)),
91 FeaturesInner::All(all) => all.iter().all(|f| enabled.contains(*f)),
92 FeaturesInner::Custom { .. } => false,
93 }
94 }
95}
96
97impl From<&'static str> for Features {
98 fn from(feature: &'static str) -> Features {
99 Features::new(feature)
100 }
101}
102
103impl std::fmt::Display for Features {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 fn feature(plural: bool) -> &'static str {
106 if plural { "features" } else { "feature" }
107 }
108
109 match &self.0 {
110 FeaturesInner::Only(feature) => write!(f, "feature \"{}\"", feature),
111 FeaturesInner::Any(any) => {
112 if any.is_empty() {
113 f.write_str("feature <missing>")
114 } else {
115 write!(
116 f,
117 "{} {}",
118 feature(any.len() != 1),
119 fmt::Delimit::new(any.iter().map(fmt::Quote), ", ")
120 .with_last(", or ")
121 .with_pair(" or ")
122 )
123 }
124 }
125 FeaturesInner::All(all) => {
126 if all.is_empty() {
127 f.write_str("feature <missing>")
128 } else {
129 write!(
130 f,
131 "{} {}",
132 feature(all.len() != 1),
133 fmt::Delimit::new(all.iter().map(fmt::Quote), ", ")
134 .with_last(", and ")
135 .with_pair(" and ")
136 )
137 }
138 }
139 FeaturesInner::Custom { custom, plural } => {
140 write!(f, "{} {}", feature(*plural), custom)
141 }
142 }
143 }
144}
145
146#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn test_rendering() {
156 let list = [
157 (Features::new("a"), "feature \"a\""),
158 (Features::from("b"), "feature \"b\""),
159 (Features::any([]), "feature <missing>"),
161 (Features::any(["a"]), "feature \"a\""),
162 (Features::any(["a", "b"]), "features \"a\" or \"b\""),
163 (
164 Features::any(["a", "b", "c"]),
165 "features \"a\", \"b\", or \"c\"",
166 ),
167 (Features::all([]), "feature <missing>"),
169 (Features::all(["a"]), "feature \"a\""),
170 (Features::all(["a", "b"]), "features \"a\" and \"b\""),
171 (
172 Features::all(["a", "b", "c"]),
173 "features \"a\", \"b\", and \"c\"",
174 ),
175 (
177 Features::custom("custom/stuff", false),
178 "feature custom/stuff",
179 ),
180 (
181 Features::custom("custom/stuff", true),
182 "features custom/stuff",
183 ),
184 ];
185
186 for (feature, expected) in list.iter() {
187 assert_eq!(feature.to_string(), *expected, "Failed for {:?}", feature);
188 }
189 }
190}