+79
| use std::env; | ||
| use std::io::Write; | ||
| use std::process::{Command, Stdio}; | ||
| fn main() { | ||
| // we need to output *some* file to opt out of the default | ||
| println!("cargo:rerun-if-changed=build.rs"); | ||
| detect_maybe_uninit(); | ||
| } | ||
| fn detect_maybe_uninit() { | ||
| let has_unstable_union_with_md = probe(&maybe_uninit_code(true)); | ||
| if has_unstable_union_with_md { | ||
| println!("cargo:rustc-cfg=has_manually_drop_in_union"); | ||
| println!("cargo:rustc-cfg=has_union_feature"); | ||
| return; | ||
| } | ||
| let has_stable_union_with_md = probe(&maybe_uninit_code(false)); | ||
| if has_stable_union_with_md { | ||
| println!("cargo:rustc-cfg=has_manually_drop_in_union"); | ||
| } | ||
| } | ||
| // To guard against changes in this currently unstable feature, use | ||
| // a detection tests instead of a Rustc version and/or date test. | ||
| fn maybe_uninit_code(use_feature: bool) -> String { | ||
| let feature = if use_feature { "#![feature(untagged_unions)]" } else { "" }; | ||
| let code = " | ||
| #![allow(warnings)] | ||
| use std::mem::ManuallyDrop; | ||
| #[derive(Copy)] | ||
| pub union MaybeUninit<T> { | ||
| empty: (), | ||
| value: ManuallyDrop<T>, | ||
| } | ||
| impl<T> Clone for MaybeUninit<T> where T: Copy | ||
| { | ||
| fn clone(&self) -> Self { *self } | ||
| } | ||
| fn main() { | ||
| let value1 = MaybeUninit::<[i32; 3]> { empty: () }; | ||
| let value2 = MaybeUninit { value: ManuallyDrop::new([1, 2, 3]) }; | ||
| } | ||
| "; | ||
| [feature, code].concat() | ||
| } | ||
| /// Test if a code snippet can be compiled | ||
| fn probe(code: &str) -> bool { | ||
| let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); | ||
| let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR"); | ||
| let mut child = Command::new(rustc) | ||
| .arg("--out-dir") | ||
| .arg(out_dir) | ||
| .arg("--emit=obj") | ||
| .arg("-") | ||
| .stdin(Stdio::piped()) | ||
| .spawn() | ||
| .expect("rustc probe"); | ||
| child | ||
| .stdin | ||
| .as_mut() | ||
| .expect("rustc stdin") | ||
| .write_all(code.as_bytes()) | ||
| .expect("write rustc stdin"); | ||
| child.wait().expect("rustc probe").success() | ||
| } |
| use array::Array; | ||
| use nodrop::NoDrop; | ||
| use std::mem::uninitialized; | ||
| /// A combination of NoDrop and “maybe uninitialized”; | ||
| /// this wraps a value that can be wholly or partially uninitialized. | ||
| /// | ||
| /// NOTE: This is known to not be a good solution, but it's the one we have kept | ||
| /// working on stable Rust. Stable improvements are encouraged, in any form, | ||
| /// but of course we are waiting for a real, stable, MaybeUninit. | ||
| pub struct MaybeUninit<T>(NoDrop<T>); | ||
| // why don't we use ManuallyDrop here: It doesn't inhibit | ||
| // enum layout optimizations that depend on T, and we support older Rust. | ||
| impl<T> MaybeUninit<T> { | ||
| /// Create a new MaybeUninit with uninitialized interior | ||
| pub unsafe fn uninitialized() -> Self { | ||
| Self::from(uninitialized()) | ||
| } | ||
| /// Create a new MaybeUninit from the value `v`. | ||
| pub fn from(v: T) -> Self { | ||
| MaybeUninit(NoDrop::new(v)) | ||
| } | ||
| /// Return a raw pointer to the start of the interior array | ||
| pub fn ptr(&self) -> *const T::Item | ||
| where T: Array | ||
| { | ||
| &*self.0 as *const T as *const _ | ||
| } | ||
| /// Return a mut raw pointer to the start of the interior array | ||
| pub fn ptr_mut(&mut self) -> *mut T::Item | ||
| where T: Array | ||
| { | ||
| &mut *self.0 as *mut T as *mut _ | ||
| } | ||
| } | ||
| use array::Array; | ||
| use std::mem::ManuallyDrop; | ||
| /// A combination of ManuallyDrop and “maybe uninitialized”; | ||
| /// this wraps a value that can be wholly or partially uninitialized; | ||
| /// it also has no drop regardless of the type of T. | ||
| #[derive(Copy)] | ||
| pub union MaybeUninit<T> { | ||
| empty: (), | ||
| value: ManuallyDrop<T>, | ||
| } | ||
| // Why we don't use std's MaybeUninit on nightly? See the ptr method | ||
| impl<T> Clone for MaybeUninit<T> where T: Copy | ||
| { | ||
| fn clone(&self) -> Self { *self } | ||
| } | ||
| impl<T> MaybeUninit<T> { | ||
| /// Create a new MaybeUninit with uninitialized interior | ||
| pub unsafe fn uninitialized() -> Self { | ||
| MaybeUninit { empty: () } | ||
| } | ||
| /// Create a new MaybeUninit from the value `v`. | ||
| pub fn from(v: T) -> Self { | ||
| MaybeUninit { value: ManuallyDrop::new(v) } | ||
| } | ||
| // Raw pointer casts written so that we don't reference or access the | ||
| // uninitialized interior value | ||
| /// Return a raw pointer to the start of the interior array | ||
| pub fn ptr(&self) -> *const T::Item | ||
| where T: Array | ||
| { | ||
| // std MaybeUninit creates a &self.value reference here which is | ||
| // not guaranteed to be sound in our case - we will partially | ||
| // initialize the value, not always wholly. | ||
| self as *const _ as *const T::Item | ||
| } | ||
| /// Return a mut raw pointer to the start of the interior array | ||
| pub fn ptr_mut(&mut self) -> *mut T::Item | ||
| where T: Array | ||
| { | ||
| self as *mut _ as *mut T::Item | ||
| } | ||
| } |
| { | ||
| "git": { | ||
| "sha1": "c8d12cecb372a7bcf9cd213b6db72e359fbc6fb3" | ||
| "sha1": "2316b85fbce3dc5380ec07f9ae8feb31a2baf82a" | ||
| } | ||
| } |
+4
-1
@@ -22,5 +22,7 @@ language: rust | ||
| - NODEFAULT=1 | ||
| - ARRAYVECTEST_ENSURE_UNION=1 | ||
| - rust: nightly | ||
| env: | ||
| - NODROP_FEATURES='use_needs_drop' | ||
| - ARRAYVECTEST_ENSURE_UNION=1 | ||
| - rust: nightly | ||
@@ -30,6 +32,7 @@ env: | ||
| - NODROP_FEATURES='use_union' | ||
| - ARRAYVECTEST_ENSURE_UNION=1 | ||
| branches: | ||
| only: | ||
| - master | ||
| - 0.3 | ||
| - 0.4 | ||
| script: | ||
@@ -36,0 +39,0 @@ - | |
+3
-1
@@ -15,3 +15,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "arrayvec" | ||
| version = "0.4.8" | ||
| version = "0.4.9" | ||
| authors = ["bluss"] | ||
@@ -54,2 +54,4 @@ description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString." | ||
| [build-dependencies] | ||
| [features] | ||
@@ -56,0 +58,0 @@ array-sizes-129-255 = [] |
+14
-0
@@ -25,2 +25,16 @@ | ||
| - 0.4.9 | ||
| - Use ``union`` in the implementation on when this is detected to be supported | ||
| (nightly only for now). This is a better solution for treating uninitialized | ||
| regions correctly, and we'll use it in stable Rust as soon as we are able. | ||
| When this is enabled, the ``ArrayVec`` has no space overhead in its memory | ||
| layout, although the size of the vec should not be relied upon. (See `#114`_) | ||
| - ``ArrayString`` updated to not use uninitialized memory, it instead zeros its | ||
| backing array. This will be refined in the next version, since we | ||
| need to make changes to the user visible API. | ||
| - The ``use_union`` feature now does nothing (like its documentation foretold). | ||
| .. _`#114`: https://github.com/bluss/arrayvec/pull/114 | ||
| - 0.4.8 | ||
@@ -27,0 +41,0 @@ |
@@ -29,2 +29,3 @@ use std::borrow::Borrow; | ||
| pub struct ArrayString<A: Array<Item=u8>> { | ||
| // FIXME: Use Copyable union for xs when we can | ||
| xs: A, | ||
@@ -57,3 +58,4 @@ len: A::Index, | ||
| ArrayString { | ||
| xs: ::new_array(), | ||
| // FIXME: Use Copyable union for xs when we can | ||
| xs: mem::zeroed(), | ||
| len: Index::from(0), | ||
@@ -60,0 +62,0 @@ } |
+18
-28
@@ -10,10 +10,2 @@ //! **arrayvec** provides the types `ArrayVec` and `ArrayString`: | ||
| //! | ||
| //! - `use_union` | ||
| //! - Optional | ||
| //! - Requires Rust nightly channel | ||
| //! - Experimental: This flag uses nightly so it *may break* unexpectedly | ||
| //! at some point; since it doesn't change API this flag may also change | ||
| //! to do nothing in the future. | ||
| //! - Use the unstable feature untagged unions for the internal implementation, | ||
| //! which may have reduced space overhead | ||
| //! - `serde-1` | ||
@@ -32,3 +24,4 @@ //! - Optional | ||
| #![cfg_attr(not(feature="std"), no_std)] | ||
| extern crate nodrop; | ||
| #![cfg_attr(has_union_feature, feature(untagged_unions))] | ||
| #[cfg(feature="serde-1")] | ||
@@ -40,2 +33,5 @@ extern crate serde; | ||
| #[cfg(not(has_manually_drop_in_union))] | ||
| extern crate nodrop; | ||
| use std::cmp; | ||
@@ -59,8 +55,11 @@ use std::iter; | ||
| #[cfg(not(feature="use_union"))] | ||
| use nodrop::NoDrop; | ||
| #[cfg(feature="use_union")] | ||
| use std::mem::ManuallyDrop as NoDrop; | ||
| #[cfg(has_manually_drop_in_union)] | ||
| mod maybe_uninit; | ||
| #[cfg(not(has_manually_drop_in_union))] | ||
| #[path="maybe_uninit_nodrop.rs"] | ||
| mod maybe_uninit; | ||
| use maybe_uninit::MaybeUninit; | ||
| #[cfg(feature="serde-1")] | ||
@@ -82,10 +81,2 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer}; | ||
| unsafe fn new_array<A: Array>() -> A { | ||
| // Note: Returning an uninitialized value here only works | ||
| // if we can be sure the data is never used. The nullable pointer | ||
| // inside enum optimization conflicts with this this for example, | ||
| // so we need to be extra careful. See `NoDrop` enum. | ||
| mem::uninitialized() | ||
| } | ||
| /// A vector with a fixed capacity. | ||
@@ -104,3 +95,3 @@ /// | ||
| pub struct ArrayVec<A: Array> { | ||
| xs: NoDrop<A>, | ||
| xs: MaybeUninit<A>, | ||
| len: A::Index, | ||
@@ -142,3 +133,3 @@ } | ||
| unsafe { | ||
| ArrayVec { xs: NoDrop::new(new_array()), len: Index::from(0) } | ||
| ArrayVec { xs: MaybeUninit::uninitialized(), len: Index::from(0) } | ||
| } | ||
@@ -527,3 +518,2 @@ } | ||
| /// Create a draining iterator that removes the specified range in the vector | ||
@@ -588,3 +578,3 @@ /// and yields the removed items from start to end. The element range is | ||
| unsafe { | ||
| let array = ptr::read(&*self.xs); | ||
| let array = ptr::read(self.xs.ptr() as *const A); | ||
| mem::forget(self); | ||
@@ -618,3 +608,3 @@ Ok(array) | ||
| unsafe { | ||
| slice::from_raw_parts(self.xs.as_ptr(), self.len()) | ||
| slice::from_raw_parts(self.xs.ptr(), self.len()) | ||
| } | ||
@@ -629,3 +619,3 @@ } | ||
| unsafe { | ||
| slice::from_raw_parts_mut(self.xs.as_mut_ptr(), len) | ||
| slice::from_raw_parts_mut(self.xs.ptr_mut(), len) | ||
| } | ||
@@ -646,3 +636,3 @@ } | ||
| fn from(array: A) -> Self { | ||
| ArrayVec { xs: NoDrop::new(array), len: Index::from(A::capacity()) } | ||
| ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::capacity()) } | ||
| } | ||
@@ -649,0 +639,0 @@ } |
+17
-0
@@ -168,2 +168,10 @@ extern crate arrayvec; | ||
| #[test] | ||
| fn test_still_works_with_option_arrayvec() { | ||
| type RefArray = ArrayVec<[&'static i32; 2]>; | ||
| let array = Some(RefArray::new()); | ||
| assert!(array.is_some()); | ||
| println!("{:?}", array); | ||
| } | ||
| #[test] | ||
| fn test_drain() { | ||
@@ -504,1 +512,10 @@ let mut v = ArrayVec::from([0; 8]); | ||
| #[test] | ||
| fn test_nightly_uses_maybe_uninit() { | ||
| if option_env!("ARRAYVECTEST_ENSURE_UNION").map(|s| !s.is_empty()).unwrap_or(false) { | ||
| assert!(cfg!(has_manually_drop_in_union)); | ||
| type ByteArray = ArrayVec<[u8; 4]>; | ||
| assert!(mem::size_of::<ByteArray>() == 5); | ||
| } | ||
| } |
Sorry, the diff of this file is not supported yet