nodrop: Add nightly feature use_union

Use a separate crate (nodrop-union) so that we can conditionally use the
new union keyword without disrupting compatibility.
This commit is contained in:
bluss
2016-09-06 11:21:40 +02:00
parent ddd09cf04d
commit 57348a2677
5 changed files with 287 additions and 109 deletions
+3
View File
@@ -13,6 +13,9 @@ matrix:
- rust: nightly - rust: nightly
env: env:
- NODROP_FEATURES='use_needs_drop' - NODROP_FEATURES='use_needs_drop'
- rust: nightly
env:
- NODROP_FEATURES='use_union'
branches: branches:
only: only:
- master - master
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "nodrop-union"
version = "0.1.8"
authors = ["bluss"]
license = "MIT/Apache-2.0"
description = "A wrapper type to inhibit drop (destructor). Implementation crate for nodrop, the untagged unions implementation (which is unstable / requires nightly) as of this writing."
documentation = "http://bluss.github.io/arrayvec/doc/nodrop"
repository = "https://github.com/bluss/arrayvec"
keywords = ["container", "drop", "no_std"]
+135
View File
@@ -0,0 +1,135 @@
//!
//! The **nodrop** crate has the following cargo feature flags:
//!
//! - `std`
//! - Optional, enabled by default
//! - Requires Rust 1.6 *to disable*
//! - Use libstd
//! - `use_needs_drop`
//! - Optional
//! - Requires nightly channel.
//! - Use `needs_drop` to skip overwriting if not necessary
//! - `use_union`
//! - Optional
//! - Requires nightly channel
//! - Using untagged union, finally we have an implementation of `NoDrop` without hacks,
//! for example the fact that `NoDrop<T>` never has a destructor anymore.
//!
#![feature(untagged_unions)]
#![cfg_attr(not(test), no_std)]
#[cfg(not(test))]
extern crate core as std;
use std::ops::{Deref, DerefMut};
#[allow(unions_with_drop_fields)]
union UnionFlag<T> {
value: T,
}
pub struct NoDrop<T>(UnionFlag<T>);
impl<T> NoDrop<T> {
/// Create a new **NoDrop**.
#[inline]
pub fn new(value: T) -> Self {
NoDrop(UnionFlag { value: value })
}
/// Extract the inner value.
///
/// Once extracted, the value can of course drop again.
#[inline]
pub fn into_inner(self) -> T {
unsafe {
self.0.value
}
}
}
impl<T> Deref for NoDrop<T> {
type Target = T;
// Use type invariant, always initialized
#[inline]
fn deref(&self) -> &T {
unsafe {
&self.0.value
}
}
}
impl<T> DerefMut for NoDrop<T> {
// Use type invariant, always initialized
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe {
&mut self.0.value
}
}
}
#[cfg(test)]
mod tests {
use super::NoDrop;
use std::mem;
#[test]
fn test_drop() {
use std::cell::Cell;
let flag = &Cell::new(0);
struct Bump<'a>(&'a Cell<i32>);
impl<'a> Drop for Bump<'a> {
fn drop(&mut self) {
let n = self.0.get();
self.0.set(n + 1);
}
}
{
let _ = NoDrop::new([Bump(flag), Bump(flag)]);
}
assert_eq!(flag.get(), 0);
// test something with the nullable pointer optimization
flag.set(0);
{
let mut array = NoDrop::new(Vec::new());
array.push(vec![Bump(flag)]);
array.push(vec![Bump(flag), Bump(flag)]);
array.push(vec![]);
array.push(vec![Bump(flag)]);
drop(array.pop());
assert_eq!(flag.get(), 1);
drop(array.pop());
assert_eq!(flag.get(), 1);
drop(array.pop());
assert_eq!(flag.get(), 3);
}
// last one didn't drop.
assert_eq!(flag.get(), 3);
flag.set(0);
{
let array = NoDrop::new(Bump(flag));
array.into_inner();
assert_eq!(flag.get(), 1);
}
assert_eq!(flag.get(), 1);
}
#[test]
fn test_size_of() {
assert!(mem::size_of::<NoDrop<&i32>>() == mem::size_of::<&i32>());
assert!(mem::size_of::<NoDrop<Vec<i32>>>() == mem::size_of::<Vec<i32>>());
// No non-nullable pointer optimization!
assert!(mem::size_of::<Option<NoDrop<&i32>>>() > mem::size_of::<NoDrop<&i32>>());
}
}
+7
View File
@@ -22,6 +22,13 @@ std = ["odds/std"]
# Use `needs_drop` to skip overwriting if not necessary # Use `needs_drop` to skip overwriting if not necessary
use_needs_drop = [] use_needs_drop = []
# Optional, nightly channel
use_union = ["nodrop-union"]
[dependencies.odds] [dependencies.odds]
version = "0.2.12" version = "0.2.12"
default-features = false default-features = false
[dependencies.nodrop-union]
path = "../nodrop-union"
optional = true
+22 -2
View File
@@ -9,6 +9,11 @@
//! - Optional //! - Optional
//! - Requires nightly channel. //! - Requires nightly channel.
//! - Use `needs_drop` to skip overwriting if not necessary //! - Use `needs_drop` to skip overwriting if not necessary
//! - `use_union`
//! - Optional
//! - Requires nightly channel
//! - Using untagged union, finally we have an implementation of `NoDrop` without hacks,
//! for example the fact that `NoDrop<T>` never has a destructor anymore.
//! //!
#![cfg_attr(feature="use_needs_drop", feature(core_intrinsics))] #![cfg_attr(feature="use_needs_drop", feature(core_intrinsics))]
@@ -17,13 +22,22 @@
#[cfg(not(any(test, feature="std")))] #[cfg(not(any(test, feature="std")))]
extern crate core as std; extern crate core as std;
#[cfg(not(feature = "use_union"))]
extern crate odds; extern crate odds;
use odds::debug_assert_unreachable; #[cfg(feature = "use_union")]
extern crate nodrop_union as imp;
use std::ops::{Deref, DerefMut}; pub use imp::NoDrop;
#[cfg(not(feature = "use_union"))]
mod imp {
use std;
use odds::debug_assert_unreachable;
use std::ptr; use std::ptr;
use std::mem; use std::mem;
use std::ops::{Deref, DerefMut};
/// repr(u8) - Make sure the non-nullable pointer optimization does not occur! /// repr(u8) - Make sure the non-nullable pointer optimization does not occur!
#[repr(u8)] #[repr(u8)]
@@ -32,6 +46,7 @@ enum Flag<T> {
Dropped, Dropped,
} }
/// A type holding **T** that will not call its destructor on drop /// A type holding **T** that will not call its destructor on drop
pub struct NoDrop<T>(Flag<T>); pub struct NoDrop<T>(Flag<T>);
@@ -114,8 +129,12 @@ fn test_no_nonnullable_opt() {
assert!(mem::size_of::<Flag<Vec<i32>>>() > mem::size_of::<Vec<i32>>()); assert!(mem::size_of::<Flag<Vec<i32>>>() > mem::size_of::<Vec<i32>>());
assert!(mem::size_of::<Option<Flag<&i32>>>() > mem::size_of::<Flag<&i32>>()); assert!(mem::size_of::<Option<Flag<&i32>>>() > mem::size_of::<Flag<&i32>>());
} }
}
#[cfg(test)] #[cfg(test)]
mod tests {
use super::NoDrop;
#[test] #[test]
fn test_drop() { fn test_drop() {
use std::cell::Cell; use std::cell::Cell;
@@ -164,3 +183,4 @@ fn test_drop() {
} }
assert_eq!(flag.get(), 1); assert_eq!(flag.get(), 1);
} }
}