diff --git a/Cargo.toml b/Cargo.toml index 540de1a..d120413 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,13 @@ exclude = ["/.*"] std = [] default = ["std"] +[build-dependencies] +autocfg = "1" + [dependencies] serde = { version = "1.0.95", optional = true, default-features = false, features = ["alloc"] } [dev-dependencies] +rustversion = "1" serde = { version = "1", features = ["derive"] } serde_test = "1" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..b60351a --- /dev/null +++ b/build.rs @@ -0,0 +1,24 @@ +fn main() { + let cfg = match autocfg::AutoCfg::new() { + Ok(cfg) => cfg, + Err(e) => { + // If we couldn't detect the compiler version and features, just + // print a warning. This isn't a fatal error: we can still build + // Slab, we just can't enable cfgs automatically. + println!( + "cargo:warning=slab: failed to detect compiler features: {}", + e + ); + return; + } + }; + // Note that this is `no_`*, not `has_*`. This allows treating as the latest + // stable rustc is used when the build script doesn't run. This is useful + // for non-cargo build systems that don't run the build script. + if !cfg.probe_rustc_version(1, 39) { + println!("cargo:rustc-cfg=slab_no_const_vec_new"); + } + if !cfg.probe_rustc_version(1, 46) { + println!("cargo:rustc-cfg=slab_no_track_caller"); + } +} diff --git a/src/lib.rs b/src/lib.rs index f207455..577f7b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -219,14 +219,35 @@ impl Slab { /// The function does not allocate and the returned slab will have no /// capacity until `insert` is called or capacity is explicitly reserved. /// + /// This is `const fn` on Rust 1.39+. + /// /// # Examples /// /// ``` /// # use slab::*; /// let slab: Slab = Slab::new(); /// ``` - pub fn new() -> Slab { - Slab::with_capacity(0) + #[cfg(not(slab_no_const_vec_new))] + pub const fn new() -> Self { + Self { + entries: Vec::new(), + next: 0, + len: 0, + } + } + /// Construct a new, empty `Slab`. + /// + /// The function does not allocate and the returned slab will have no + /// capacity until `insert` is called or capacity is explicitly reserved. + /// + /// This is `const fn` on Rust 1.39+. + #[cfg(slab_no_const_vec_new)] + pub fn new() -> Self { + Self { + entries: Vec::new(), + next: 0, + len: 0, + } } /// Construct a new, empty `Slab` with the specified capacity. @@ -877,6 +898,7 @@ impl Slab { /// slab.key_of(bad); // this will panic /// unreachable!(); /// ``` + #[cfg_attr(not(slab_no_track_caller), track_caller)] pub fn key_of(&self, present_element: &T) -> usize { let element_ptr = present_element as *const T as usize; let base_ptr = self.entries.as_ptr() as usize; @@ -1045,6 +1067,7 @@ impl Slab { /// assert_eq!(slab.remove(hello), "hello"); /// assert!(!slab.contains(hello)); /// ``` + #[cfg_attr(not(slab_no_track_caller), track_caller)] pub fn remove(&mut self, key: usize) -> T { self.try_remove(key).expect("invalid key") } @@ -1152,6 +1175,7 @@ impl Slab { impl ops::Index for Slab { type Output = T; + #[cfg_attr(not(slab_no_track_caller), track_caller)] fn index(&self, key: usize) -> &T { match self.entries.get(key) { Some(&Entry::Occupied(ref v)) => v, @@ -1161,6 +1185,7 @@ impl ops::Index for Slab { } impl ops::IndexMut for Slab { + #[cfg_attr(not(slab_no_track_caller), track_caller)] fn index_mut(&mut self, key: usize) -> &mut T { match self.entries.get_mut(key) { Some(&mut Entry::Occupied(ref mut v)) => v, diff --git a/tests/slab.rs b/tests/slab.rs index 41360fa..fa89ebb 100644 --- a/tests/slab.rs +++ b/tests/slab.rs @@ -696,3 +696,9 @@ fn try_remove() { assert_eq!(slab.try_remove(key), None); assert_eq!(slab.get(key), None); } + +#[rustversion::since(1.39)] +#[test] +fn const_new() { + static _SLAB: Slab<()> = Slab::new(); +}