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 }