/ src / recognized.rs
recognized.rs
  1  //! The definition of which features are recognized by this crate.
  2  
  3  use super::FeatureCategory;
  4  
  5  
  6  /// Descriptor of a recognized feature.
  7  ///
  8  /// (Actually private to the crate, not part of public API.  Is only `pub` for old Rust versions.)
  9  #[derive(Eq, PartialEq, Copy, Clone, Debug)]
 10  pub struct Feature
 11  {
 12      pub name:       &'static str,
 13      pub categories: &'static [FeatureCategory],
 14      pub probe:      Probe,
 15  }
 16  
 17  /// How to test whether a `rustc` version provides a feature.
 18  ///
 19  /// (Actually private to the crate, not part of public API.  Is only `pub` for old Rust versions.)
 20  #[derive(Eq, PartialEq, Copy, Clone, Debug)]
 21  pub enum Probe
 22  {
 23      Expr(&'static str),
 24      Type(&'static str),
 25      Path(&'static str),
 26      AlwaysEnabled,
 27      UnstableFeatures,
 28  }
 29  
 30  /// The definition of which features are recognized by this crate.
 31  ///
 32  /// Invariant: Must always be sorted by name.  Keep this in mind when making changes to it.  There
 33  /// is a unit-test that checks this.
 34  const DEFINITION: &'static [Feature] = &[
 35      Feature {
 36          name:       "arbitrary_self_types",
 37          categories: &["lang"],
 38          probe:      Probe::Expr(
 39              r#"{
 40                     struct Thing;
 41                     struct Wrap<T: ?Sized>(T);
 42                     impl<T: ?Sized> std::ops::Deref for Wrap<T> {
 43                         type Target = T;
 44                         fn deref(&self) -> &Self::Target { &self.0 }
 45                     }
 46                     trait WrapSelf { fn m(self: Wrap<Self>); }
 47                     impl WrapSelf for Thing { fn m(self: Wrap<Self>) {} }
 48                     Wrap(Thing).m()
 49                 }"#,
 50          ),
 51      },
 52      Feature {
 53          name:       "cfg_version",
 54          categories: &["lang"],
 55          probe:      Probe::Expr(r#"{ #[cfg(version("1.0"))] struct X; X }"#),
 56      },
 57      Feature {
 58          name:       "destructuring_assignment",
 59          categories: &["lang"],
 60          probe:      Probe::Expr("{ let (_a, _b); (_a, _b) = (1, 2); }"),
 61      },
 62      Feature {
 63          name:       "error_in_core",
 64          categories: &["lib"],
 65          probe:      Probe::Expr("{ let _: &core::error::Error; }"),
 66      },
 67      Feature {
 68          name:       "inner_deref",
 69          categories: &["lib"],
 70          probe:      Probe::Expr("Ok::<_, ()>(vec![1]).as_deref()"),
 71      },
 72      Feature {
 73          name:       "iter_zip",
 74          categories: &["lib"],
 75          probe:      Probe::Path("std::iter::zip"),
 76      },
 77      Feature { name: "never_type", categories: &["lang"], probe: Probe::Type("!") },
 78      Feature {
 79          name:       "question_mark",
 80          categories: &["lang"],
 81          probe:      Probe::Expr("|| -> Result<(), ()> { Err(())? }"),
 82      },
 83      Feature {
 84          name:       "rust1",
 85          categories: &["comp", "lang", "lib"],
 86          probe:      Probe::AlwaysEnabled,
 87      },
 88      Feature {
 89          name:       "step_trait",
 90          categories: &["lib"],
 91          probe:      Probe::Path("std::iter::Step"),
 92      },
 93      Feature {
 94          name:       "unstable_features",
 95          categories: &["comp"],
 96          probe:      Probe::UnstableFeatures,
 97      },
 98      Feature {
 99          name:       "unwrap_infallible",
100          categories: &["lib"],
101          probe:      Probe::Expr("Ok::<(), !>(()).into_ok()"),
102      },
103  ];
104  
105  /// Lookup a feature descriptor by name.  Return `None` if not recognized.
106  ///
107  /// (Actually private to the crate, not part of public API.  Is only `pub` for old Rust versions.)
108  pub fn get(feature_name: &str) -> Option<&'static Feature>
109  {
110      DEFINITION
111          .binary_search_by(|element| element.name.cmp(feature_name))
112          .ok()
113          .map(|index| &DEFINITION[index])
114  }
115  
116  
117  #[cfg(test)]
118  mod tests
119  {
120      use super::{Feature, DEFINITION};
121  
122      fn sorted() -> Vec<Feature>
123      {
124          let mut v = Vec::from(DEFINITION);
125          v.sort_by(|a, b| a.name.cmp(b.name));
126          v
127      }
128  
129      #[test]
130      fn no_duplicates()
131      {
132          let mut deduped = sorted();
133          deduped.dedup();
134          assert_eq!(DEFINITION, &*deduped);
135      }
136  
137      #[test]
138      fn is_sorted()
139      {
140          assert_eq!(DEFINITION, &*sorted());
141      }
142  }