Merge branch '0.4' of https://github.com/bluss/arrayvec into merge-0.4

* '0.4' of https://github.com/bluss/arrayvec:
  0.4.9
  TEST: Add test that ensures the MaybeUninit impl is used on nightly
  FIX: Remove use of uninitialized in ArrayString
  FEAT: Implement a "MaybeUninit" and use it conditionally
  TEST: Add test that Some(ArrayVec<[&_;_]>).is_some()
  MAINT: Test the 0.4 branch in travis
This commit is contained in:
bluss
2018-12-16 18:09:20 +01:00
9 changed files with 234 additions and 31 deletions
+4 -1
View File
@@ -2,6 +2,7 @@ use std::borrow::Borrow;
use std::cmp;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};
use std::str;
@@ -25,6 +26,7 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
/// if needed.
#[derive(Copy)]
pub struct ArrayString<A: Array<Item=u8>> {
// FIXME: Use Copyable union for xs when we can
xs: A,
len: A::Index,
}
@@ -52,7 +54,8 @@ impl<A: Array<Item=u8>> ArrayString<A> {
pub fn new() -> ArrayString<A> {
unsafe {
ArrayString {
xs: ::new_array(),
// FIXME: Use Copyable union for xs when we can
xs: mem::zeroed(),
len: Index::from(0),
}
}
+19 -28
View File
@@ -7,14 +7,6 @@
//! - Optional, enabled by default
//! - Use libstd; disable to use `no_std` instead.
//!
//! - `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`
//! - Optional
//! - Enable serialization for ArrayVec and ArrayString using serde 1.0
@@ -28,13 +20,17 @@
//!
#![doc(html_root_url="https://docs.rs/arrayvec/0.4/")]
#![cfg_attr(not(feature="std"), no_std)]
extern crate nodrop;
#![cfg_attr(has_union_feature, feature(untagged_unions))]
#[cfg(feature="serde-1")]
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;
@@ -53,11 +49,14 @@ use std::fmt;
#[cfg(feature="std")]
use std::io;
#[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")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
@@ -75,14 +74,6 @@ pub use array_string::ArrayString;
pub use errors::CapacityError;
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.
///
/// The `ArrayVec` is a vector backed by a fixed size array. It keeps track of
@@ -96,7 +87,7 @@ unsafe fn new_array<A: Array>() -> A {
///
/// ArrayVec can be converted into a by value iterator.
pub struct ArrayVec<A: Array> {
xs: NoDrop<A>,
xs: MaybeUninit<A>,
len: A::Index,
}
@@ -133,7 +124,7 @@ impl<A: Array> ArrayVec<A> {
/// ```
pub fn new() -> ArrayVec<A> {
unsafe {
ArrayVec { xs: NoDrop::new(new_array()), len: Index::from(0) }
ArrayVec { xs: MaybeUninit::uninitialized(), len: Index::from(0) }
}
}
@@ -565,7 +556,7 @@ impl<A: Array> ArrayVec<A> {
let other_len = other.len();
unsafe {
let dst = self.xs.as_mut_ptr().offset(self_len as isize);
let dst = self.xs.ptr_mut().offset(self_len as isize);
ptr::copy_nonoverlapping(other.as_ptr(), dst, other_len);
self.set_len(self_len + other_len);
}
@@ -631,7 +622,7 @@ impl<A: Array> ArrayVec<A> {
Err(self)
} else {
unsafe {
let array = ptr::read(&*self.xs);
let array = ptr::read(self.xs.ptr() as *const A);
mem::forget(self);
Ok(array)
}
@@ -660,7 +651,7 @@ impl<A: Array> Deref for ArrayVec<A> {
#[inline]
fn deref(&self) -> &[A::Item] {
unsafe {
slice::from_raw_parts(self.xs.as_ptr(), self.len())
slice::from_raw_parts(self.xs.ptr(), self.len())
}
}
}
@@ -670,7 +661,7 @@ impl<A: Array> DerefMut for ArrayVec<A> {
fn deref_mut(&mut self) -> &mut [A::Item] {
let len = self.len();
unsafe {
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), len)
slice::from_raw_parts_mut(self.xs.ptr_mut(), len)
}
}
}
@@ -686,7 +677,7 @@ impl<A: Array> DerefMut for ArrayVec<A> {
/// ```
impl<A: Array> From<A> for ArrayVec<A> {
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()) }
}
}
+51
View File
@@ -0,0 +1,51 @@
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
}
}
+41
View File
@@ -0,0 +1,41 @@
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 _
}
}