Merge pull request #129 from bluss/prepare-0.5
Always use MaybeUninit and stop using nodrop fallback, prepare next release
This commit is contained in:
+1
-7
@@ -4,7 +4,7 @@ env:
|
||||
- FEATURES='serde-1'
|
||||
matrix:
|
||||
include:
|
||||
- rust: 1.24.1
|
||||
- rust: 1.36.0
|
||||
env:
|
||||
- FEATURES='array-sizes-33-128 array-sizes-129-255'
|
||||
- rust: stable
|
||||
@@ -14,23 +14,17 @@ matrix:
|
||||
- rust: stable
|
||||
env:
|
||||
- FEATURES='array-sizes-33-128 array-sizes-129-255'
|
||||
- ARRAYVECTEST_ENSURE_MAYBEUNINIT=1
|
||||
- rust: beta
|
||||
- rust: nightly
|
||||
env:
|
||||
- ARRAYVECTEST_ENSURE_UNION=1
|
||||
- rust: nightly
|
||||
env:
|
||||
- FEATURES='serde'
|
||||
- ARRAYVECTEST_ENSURE_UNION=1
|
||||
- rust: nightly
|
||||
env:
|
||||
- FEATURES='serde-1'
|
||||
- ARRAYVECTEST_ENSURE_UNION=1
|
||||
- rust: nightly
|
||||
env:
|
||||
- FEATURES='array-sizes-33-128 array-sizes-129-255'
|
||||
- ARRAYVECTEST_ENSURE_MAYBEUNINIT=1
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
@@ -13,9 +13,6 @@ categories = ["data-structures", "no-std"]
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
[dependencies]
|
||||
nodrop = { version = "0.1.12", path = "nodrop", default-features = false }
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
+14
@@ -22,6 +22,20 @@ __ https://docs.rs/arrayvec
|
||||
Recent Changes (arrayvec)
|
||||
-------------------------
|
||||
|
||||
- 0.5.0 (not released yet)
|
||||
|
||||
- Add ``FromStr`` impl for ``ArrayString`` by @despawnerer
|
||||
- Use a union in the implementation of ``ArrayString`` (stable Rust),
|
||||
while this is only used for ``ArrayVec`` on nightly.
|
||||
- Add method ``try_extend_from_slice`` to ``ArrayVec``, which is always
|
||||
effecient by @Thomasdezeeuw.
|
||||
- Add method ``remaining_capacity`` by @Thomasdezeeuw
|
||||
- Improve performance of the ``extend`` method.
|
||||
- The index type of zero capacity vectors is now itself zero size, by
|
||||
@clarcharr
|
||||
- Use ``drop_in_place`` for truncate and clear methods. This affects drop order
|
||||
and resume from panic during drop.
|
||||
|
||||
- 0.4.11
|
||||
|
||||
- In Rust 1.36 or later, use newly stable MaybeUninit. This extends the
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
|
||||
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_stable_maybe_uninit = probe(&stable_maybe_uninit());
|
||||
if has_stable_maybe_uninit {
|
||||
println!("cargo:rustc-cfg=has_stable_maybe_uninit");
|
||||
return;
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
// To guard against changes in this currently unstable feature, use
|
||||
// a detection tests instead of a Rustc version and/or date test.
|
||||
fn stable_maybe_uninit() -> String {
|
||||
let code = "
|
||||
#![allow(warnings)]
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
fn main() { }
|
||||
";
|
||||
code.to_string()
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
+6
-21
@@ -20,10 +20,8 @@ pub unsafe trait Array {
|
||||
type Index: Index;
|
||||
/// The array's element capacity
|
||||
const CAPACITY: usize;
|
||||
#[doc(hidden)]
|
||||
fn as_ptr(&self) -> *const Self::Item;
|
||||
#[doc(hidden)]
|
||||
fn capacity() -> usize;
|
||||
fn as_slice(&self) -> &[Self::Item];
|
||||
fn as_mut_slice(&mut self) -> &mut [Self::Item];
|
||||
}
|
||||
|
||||
pub trait Index : PartialEq + Copy {
|
||||
@@ -31,19 +29,6 @@ pub trait Index : PartialEq + Copy {
|
||||
fn from(usize) -> Self;
|
||||
}
|
||||
|
||||
use std::slice::{from_raw_parts};
|
||||
|
||||
pub trait ArrayExt : Array {
|
||||
#[inline(always)]
|
||||
fn as_slice(&self) -> &[Self::Item] {
|
||||
unsafe {
|
||||
from_raw_parts(self.as_ptr(), Self::capacity())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> ArrayExt for A where A: Array { }
|
||||
|
||||
impl Index for () {
|
||||
#[inline(always)]
|
||||
fn to_usize(self) -> usize { 0 }
|
||||
@@ -93,11 +78,11 @@ macro_rules! fix_array_impl {
|
||||
type Index = $index_type;
|
||||
const CAPACITY: usize = $len;
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
|
||||
#[inline]
|
||||
fn as_slice(&self) -> &[Self::Item] { self }
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
fn capacity() -> usize { $len }
|
||||
#[inline]
|
||||
fn as_mut_slice(&mut self) -> &mut [Self::Item] { self }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
+6
-6
@@ -9,7 +9,7 @@ use std::str::FromStr;
|
||||
use std::str::Utf8Error;
|
||||
use std::slice;
|
||||
|
||||
use array::{Array, ArrayExt};
|
||||
use array::Array;
|
||||
use array::Index;
|
||||
use CapacityError;
|
||||
use char::encode_utf8;
|
||||
@@ -17,7 +17,7 @@ use char::encode_utf8;
|
||||
#[cfg(feature="serde-1")]
|
||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||
|
||||
use super::MaybeUninitCopy;
|
||||
use super::MaybeUninit as MaybeUninitCopy;
|
||||
|
||||
/// A string with a fixed capacity.
|
||||
///
|
||||
@@ -98,10 +98,10 @@ impl<A> ArrayString<A>
|
||||
/// ```
|
||||
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
|
||||
let len = str::from_utf8(b.as_slice())?.len();
|
||||
debug_assert_eq!(len, A::capacity());
|
||||
debug_assert_eq!(len, A::CAPACITY);
|
||||
Ok(ArrayString {
|
||||
xs: MaybeUninitCopy::from(*b),
|
||||
len: Index::from(A::capacity()),
|
||||
len: Index::from(A::CAPACITY),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ impl<A> ArrayString<A>
|
||||
/// assert_eq!(string.capacity(), 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn capacity(&self) -> usize { A::capacity() }
|
||||
pub fn capacity(&self) -> usize { A::CAPACITY }
|
||||
|
||||
/// Return if the `ArrayString` is completely filled.
|
||||
///
|
||||
@@ -547,7 +547,7 @@ impl<'de, A> Deserialize<'de> for ArrayString<A>
|
||||
type Value = ArrayString<A>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "a string no more than {} bytes long", A::capacity())
|
||||
write!(formatter, "a string no more than {} bytes long", A::CAPACITY)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
|
||||
+7
-21
@@ -16,7 +16,7 @@
|
||||
//!
|
||||
//! ## Rust Version
|
||||
//!
|
||||
//! This version of arrayvec requires Rust 1.24 or later.
|
||||
//! This version of arrayvec requires Rust 1.36 or later.
|
||||
//!
|
||||
#![doc(html_root_url="https://docs.rs/arrayvec/0.4/")]
|
||||
#![cfg_attr(not(feature="std"), no_std)]
|
||||
@@ -28,9 +28,6 @@ extern crate serde;
|
||||
#[cfg(not(feature="std"))]
|
||||
extern crate core as std;
|
||||
|
||||
#[cfg(not(has_manually_drop_in_union))]
|
||||
extern crate nodrop;
|
||||
|
||||
use std::cmp;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
@@ -50,19 +47,8 @@ use std::fmt;
|
||||
use std::io;
|
||||
|
||||
|
||||
#[cfg(has_stable_maybe_uninit)]
|
||||
#[path="maybe_uninit_stable.rs"]
|
||||
mod maybe_uninit;
|
||||
#[cfg(all(not(has_stable_maybe_uninit), has_manually_drop_in_union))]
|
||||
mod maybe_uninit;
|
||||
#[cfg(all(not(has_stable_maybe_uninit), not(has_manually_drop_in_union)))]
|
||||
#[path="maybe_uninit_nodrop.rs"]
|
||||
mod maybe_uninit;
|
||||
|
||||
mod maybe_uninit_copy;
|
||||
|
||||
use maybe_uninit::MaybeUninit;
|
||||
use maybe_uninit_copy::MaybeUninitCopy;
|
||||
|
||||
#[cfg(feature="serde-1")]
|
||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||
@@ -155,7 +141,7 @@ impl<A: Array> ArrayVec<A> {
|
||||
/// assert_eq!(array.capacity(), 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn capacity(&self) -> usize { A::capacity() }
|
||||
pub fn capacity(&self) -> usize { A::CAPACITY }
|
||||
|
||||
/// Return if the `ArrayVec` is completely filled.
|
||||
///
|
||||
@@ -223,7 +209,7 @@ impl<A: Array> ArrayVec<A> {
|
||||
/// assert!(overflow.is_err());
|
||||
/// ```
|
||||
pub fn try_push(&mut self, element: A::Item) -> Result<(), CapacityError<A::Item>> {
|
||||
if self.len() < A::capacity() {
|
||||
if self.len() < A::CAPACITY {
|
||||
unsafe {
|
||||
self.push_unchecked(element);
|
||||
}
|
||||
@@ -258,7 +244,7 @@ impl<A: Array> ArrayVec<A> {
|
||||
#[inline]
|
||||
pub unsafe fn push_unchecked(&mut self, element: A::Item) {
|
||||
let len = self.len();
|
||||
debug_assert!(len < A::capacity());
|
||||
debug_assert!(len < A::CAPACITY);
|
||||
ptr::write(self.get_unchecked_mut(len), element);
|
||||
self.set_len(len + 1);
|
||||
}
|
||||
@@ -680,7 +666,7 @@ impl<A: Array> DerefMut for ArrayVec<A> {
|
||||
/// ```
|
||||
impl<A: Array> From<A> for ArrayVec<A> {
|
||||
fn from(array: A) -> Self {
|
||||
ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::capacity()) }
|
||||
ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::CAPACITY) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1133,7 +1119,7 @@ impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Deserialize<'de> for ArrayVec<A
|
||||
type Value = ArrayVec<A>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "an array with no more than {} items", A::capacity())
|
||||
write!(formatter, "an array with no more than {} items", A::CAPACITY)
|
||||
}
|
||||
|
||||
fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
|
||||
@@ -1143,7 +1129,7 @@ impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Deserialize<'de> for ArrayVec<A
|
||||
|
||||
while let Some(value) = try!(seq.next_element()) {
|
||||
if let Err(_) = values.try_push(value) {
|
||||
return Err(SA::Error::invalid_length(A::capacity() + 1, &self));
|
||||
return Err(SA::Error::invalid_length(A::CAPACITY + 1, &self));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-16
@@ -1,27 +1,28 @@
|
||||
|
||||
|
||||
use array::Array;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::mem::MaybeUninit as StdMaybeUninit;
|
||||
|
||||
/// 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.
|
||||
#[repr(C)] // for cast from self ptr to value
|
||||
pub union MaybeUninit<T> {
|
||||
empty: (),
|
||||
value: ManuallyDrop<T>,
|
||||
#[derive(Copy)]
|
||||
pub struct MaybeUninit<T> {
|
||||
inner: StdMaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for MaybeUninit<T>
|
||||
where T: Copy
|
||||
{
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
// Why we don't use std's MaybeUninit on nightly? See the ptr method
|
||||
|
||||
impl<T> MaybeUninit<T> {
|
||||
/// Create a new MaybeUninit with uninitialized interior
|
||||
pub unsafe fn uninitialized() -> Self {
|
||||
MaybeUninit { empty: () }
|
||||
MaybeUninit { inner: StdMaybeUninit::uninit() }
|
||||
}
|
||||
|
||||
/// Create a new MaybeUninit from the value `v`.
|
||||
pub fn from(v: T) -> Self {
|
||||
MaybeUninit { value: ManuallyDrop::new(v) }
|
||||
MaybeUninit { inner: StdMaybeUninit::new(v) }
|
||||
}
|
||||
|
||||
// Raw pointer casts written so that we don't reference or access the
|
||||
@@ -31,16 +32,13 @@ impl<T> MaybeUninit<T> {
|
||||
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
|
||||
self.inner.as_ptr() 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
|
||||
self.inner.as_mut_ptr() as *mut T::Item
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
|
||||
use array::Array;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)] // for cast from self ptr to value
|
||||
pub union MaybeUninitCopy<T>
|
||||
where T: Copy
|
||||
{
|
||||
empty: (),
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<T> MaybeUninitCopy<T>
|
||||
where T: Copy
|
||||
{
|
||||
/// Create a new MaybeUninit with uninitialized interior
|
||||
pub unsafe fn uninitialized() -> Self {
|
||||
Self { empty: () }
|
||||
}
|
||||
|
||||
/// Create a new MaybeUninit from the value `v`.
|
||||
pub fn from(value: T) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
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 _
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
|
||||
|
||||
use array::Array;
|
||||
use std::mem::MaybeUninit as StdMaybeUninit;
|
||||
|
||||
pub struct MaybeUninit<T> {
|
||||
inner: StdMaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T> MaybeUninit<T> {
|
||||
/// Create a new MaybeUninit with uninitialized interior
|
||||
pub unsafe fn uninitialized() -> Self {
|
||||
MaybeUninit { inner: StdMaybeUninit::uninit() }
|
||||
}
|
||||
|
||||
/// Create a new MaybeUninit from the value `v`.
|
||||
pub fn from(v: T) -> Self {
|
||||
MaybeUninit { inner: StdMaybeUninit::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.inner.as_ptr() 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.inner.as_mut_ptr() as *mut T::Item
|
||||
}
|
||||
}
|
||||
@@ -633,14 +633,6 @@ fn test_sizes_129_255() {
|
||||
ArrayVec::from([0u8; 255]);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_newish_stable_uses_maybe_uninit() {
|
||||
if option_env!("ARRAYVECTEST_ENSURE_MAYBEUNINIT").map(|s| !s.is_empty()).unwrap_or(false) {
|
||||
assert!(cfg!(has_stable_maybe_uninit));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extend_zst() {
|
||||
let mut range = 0..10;
|
||||
|
||||
Reference in New Issue
Block a user