Merge pull request #116 from bluss/maybe-uninit-for-0.5

Update ArrayString to use union and prepare for 0.5
This commit is contained in:
bluss
2018-12-18 22:03:24 +01:00
committed by GitHub
6 changed files with 154 additions and 74 deletions
+18 -19
View File
@@ -4,43 +4,42 @@ env:
- FEATURES='serde-1' - FEATURES='serde-1'
matrix: matrix:
include: include:
- rust: 1.20.0 - rust: 1.24.1
- rust: stable
env:
- NODEFAULT=1
- NODROP_FEATURES='use_needs_drop'
- rust: 1.22.1
env: env:
- FEATURES='array-sizes-33-128 array-sizes-129-255' - FEATURES='array-sizes-33-128 array-sizes-129-255'
- rust: stable
- rust: stable
env:
- FEATURES='serde-1'
- rust: stable - rust: stable
env: env:
- FEATURES='array-sizes-33-128 array-sizes-129-255' - FEATURES='array-sizes-33-128 array-sizes-129-255'
- rust: beta - rust: beta
- rust: nightly - rust: nightly
env: env:
- NODEFAULT=1
- ARRAYVECTEST_ENSURE_UNION=1 - ARRAYVECTEST_ENSURE_UNION=1
- rust: nightly - rust: nightly
env: env:
- NODROP_FEATURES='use_needs_drop' - FEATURES='serde'
- ARRAYVECTEST_ENSURE_UNION=1 - ARRAYVECTEST_ENSURE_UNION=1
- rust: nightly - rust: nightly
env: env:
- FEATURES='serde use_union' - FEATURES='serde-1'
- NODROP_FEATURES='use_union'
- ARRAYVECTEST_ENSURE_UNION=1 - ARRAYVECTEST_ENSURE_UNION=1
- rust: nightly
env:
- FEATURES='array-sizes-33-128 array-sizes-129-255'
branches: branches:
only: only:
- master - master
- 0.4 - 0.4
script: script:
- | - |
([ ! -z "$NODROP_FEATURES" ] || cargo build --verbose --features "$FEATURES") && cargo build -v --no-default-features &&
([ "$NODEFAULT" != 1 ] || cargo build --verbose --no-default-features) && cargo build -v --features "$FEATURES" &&
([ ! -z "$NODROP_FEATURES" ] || cargo test --verbose --features "$FEATURES") && cargo test -v --features "$FEATURES" &&
([ ! -z "$NODROP_FEATURES" ] || cargo test --release --verbose --features "$FEATURES") && cargo test -v --release --features "$FEATURES" &&
([ ! -z "$NODROP_FEATURES" ] || cargo bench --verbose --features "$FEATURES" -- --test) && cargo bench -v --features "$FEATURES" --no-run &&
([ ! -z "$NODROP_FEATURES" ] || cargo doc --verbose --features "$FEATURES") && cargo doc -v --features "$FEATURES" &&
([ "$NODEFAULT" != 1 ] || cargo build --verbose --manifest-path=nodrop/Cargo.toml --no-default-features) && cargo build -v --manifest-path=nodrop/Cargo.toml &&
cargo test --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" && cargo test -v --manifest-path=nodrop/Cargo.toml
cargo bench --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" -- --test
-3
View File
@@ -44,9 +44,6 @@ serde-1 = ["serde"]
array-sizes-33-128 = [] array-sizes-33-128 = []
array-sizes-129-255 = [] array-sizes-129-255 = []
# has no effect
use_union = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["serde-1"] features = ["serde-1"]
+4 -6
View File
@@ -15,14 +15,14 @@
pub unsafe trait Array { pub unsafe trait Array {
/// The arrays element type /// The arrays element type
type Item; type Item;
/// The smallest type that can index and tell the length of the array.
#[doc(hidden)] #[doc(hidden)]
/// The smallest index type that indexes the array.
type Index: Index; type Index: Index;
/// The array's element capacity
const CAPACITY: usize;
#[doc(hidden)] #[doc(hidden)]
fn as_ptr(&self) -> *const Self::Item; fn as_ptr(&self) -> *const Self::Item;
#[doc(hidden)] #[doc(hidden)]
fn as_mut_ptr(&mut self) -> *mut Self::Item;
#[doc(hidden)]
fn capacity() -> usize; fn capacity() -> usize;
} }
@@ -91,14 +91,12 @@ macro_rules! fix_array_impl {
unsafe impl<T> Array for [T; $len] { unsafe impl<T> Array for [T; $len] {
type Item = T; type Item = T;
type Index = $index_type; type Index = $index_type;
const CAPACITY: usize = $len;
#[doc(hidden)] #[doc(hidden)]
#[inline(always)] #[inline(always)]
fn as_ptr(&self) -> *const T { self as *const _ as *const _ } fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
#[doc(hidden)] #[doc(hidden)]
#[inline(always)] #[inline(always)]
fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
#[doc(hidden)]
#[inline(always)]
fn capacity() -> usize { $len } fn capacity() -> usize { $len }
} }
) )
+83 -39
View File
@@ -2,7 +2,6 @@ use std::borrow::Borrow;
use std::cmp; use std::cmp;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr; use std::ptr;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::str; use std::str;
@@ -17,6 +16,8 @@ use char::encode_utf8;
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use serde::{Serialize, Deserialize, Serializer, Deserializer};
use super::MaybeUninitCopy;
/// A string with a fixed capacity. /// A string with a fixed capacity.
/// ///
/// The `ArrayString` is a string backed by a fixed size array. It keeps track /// The `ArrayString` is a string backed by a fixed size array. It keeps track
@@ -25,20 +26,25 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
/// The string is a contiguous value that you can store directly on the stack /// The string is a contiguous value that you can store directly on the stack
/// if needed. /// if needed.
#[derive(Copy)] #[derive(Copy)]
pub struct ArrayString<A: Array<Item=u8>> { pub struct ArrayString<A>
// FIXME: Use Copyable union for xs when we can where A: Array<Item=u8> + Copy
xs: A, {
xs: MaybeUninitCopy<A>,
len: A::Index, len: A::Index,
} }
impl<A: Array<Item=u8>> Default for ArrayString<A> { impl<A> Default for ArrayString<A>
where A: Array<Item=u8> + Copy
{
/// Return an empty `ArrayString` /// Return an empty `ArrayString`
fn default() -> ArrayString<A> { fn default() -> ArrayString<A> {
ArrayString::new() ArrayString::new()
} }
} }
impl<A: Array<Item=u8>> ArrayString<A> { impl<A> ArrayString<A>
where A: Array<Item=u8> + Copy
{
/// Create a new empty `ArrayString`. /// Create a new empty `ArrayString`.
/// ///
/// Capacity is inferred from the type parameter. /// Capacity is inferred from the type parameter.
@@ -54,8 +60,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
pub fn new() -> ArrayString<A> { pub fn new() -> ArrayString<A> {
unsafe { unsafe {
ArrayString { ArrayString {
// FIXME: Use Copyable union for xs when we can xs: MaybeUninitCopy::uninitialized(),
xs: mem::zeroed(),
len: Index::from(0), len: Index::from(0),
} }
} }
@@ -91,11 +96,12 @@ impl<A: Array<Item=u8>> ArrayString<A> {
/// let string = ArrayString::from_byte_string(b"hello world").unwrap(); /// let string = ArrayString::from_byte_string(b"hello world").unwrap();
/// ``` /// ```
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> { pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
let mut arraystr = Self::new(); let len = str::from_utf8(b.as_slice())?.len();
let s = try!(str::from_utf8(b.as_slice())); debug_assert_eq!(len, A::capacity());
let _result = arraystr.try_push_str(s); Ok(ArrayString {
debug_assert!(_result.is_ok()); xs: MaybeUninitCopy::from(*b),
Ok(arraystr) len: Index::from(A::capacity()),
})
} }
/// Return the capacity of the `ArrayString`. /// Return the capacity of the `ArrayString`.
@@ -213,7 +219,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
return Err(CapacityError::new(s)); return Err(CapacityError::new(s));
} }
unsafe { unsafe {
let dst = self.xs.as_mut_ptr().offset(self.len() as isize); let dst = self.xs.ptr_mut().offset(self.len() as isize);
let src = s.as_ptr(); let src = s.as_ptr();
ptr::copy_nonoverlapping(src, dst, s.len()); ptr::copy_nonoverlapping(src, dst, s.len());
let newl = self.len() + s.len(); let newl = self.len() + s.len();
@@ -307,8 +313,8 @@ impl<A: Array<Item=u8>> ArrayString<A> {
let next = idx + ch.len_utf8(); let next = idx + ch.len_utf8();
let len = self.len(); let len = self.len();
unsafe { unsafe {
ptr::copy(self.xs.as_ptr().offset(next as isize), ptr::copy(self.xs.ptr().offset(next as isize),
self.xs.as_mut_ptr().offset(idx as isize), self.xs.ptr_mut().offset(idx as isize),
len - next); len - next);
self.set_len(len - (next - idx)); self.set_len(len - (next - idx));
} }
@@ -342,75 +348,99 @@ impl<A: Array<Item=u8>> ArrayString<A> {
/// Return a mutable slice of the whole strings buffer /// Return a mutable slice of the whole strings buffer
unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] { unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity()) slice::from_raw_parts_mut(self.xs.ptr_mut(), self.capacity())
} }
} }
impl<A: Array<Item=u8>> Deref for ArrayString<A> { impl<A> Deref for ArrayString<A>
where A: Array<Item=u8> + Copy
{
type Target = str; type Target = str;
#[inline] #[inline]
fn deref(&self) -> &str { fn deref(&self) -> &str {
unsafe { unsafe {
let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize()); let sl = slice::from_raw_parts(self.xs.ptr(), self.len.to_usize());
str::from_utf8_unchecked(sl) str::from_utf8_unchecked(sl)
} }
} }
} }
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> { impl<A> DerefMut for ArrayString<A>
where A: Array<Item=u8> + Copy
{
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut str { fn deref_mut(&mut self) -> &mut str {
unsafe { unsafe {
let sl = slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.len.to_usize()); let sl = slice::from_raw_parts_mut(self.xs.ptr_mut(), self.len.to_usize());
str::from_utf8_unchecked_mut(sl) str::from_utf8_unchecked_mut(sl)
} }
} }
} }
impl<A: Array<Item=u8>> PartialEq for ArrayString<A> { impl<A> PartialEq for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
**self == **rhs **self == **rhs
} }
} }
impl<A: Array<Item=u8>> PartialEq<str> for ArrayString<A> { impl<A> PartialEq<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &str) -> bool { fn eq(&self, rhs: &str) -> bool {
&**self == rhs &**self == rhs
} }
} }
impl<A: Array<Item=u8>> PartialEq<ArrayString<A>> for str { impl<A> PartialEq<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &ArrayString<A>) -> bool { fn eq(&self, rhs: &ArrayString<A>) -> bool {
self == &**rhs self == &**rhs
} }
} }
impl<A: Array<Item=u8>> Eq for ArrayString<A> { } impl<A> Eq for ArrayString<A>
where A: Array<Item=u8> + Copy
{ }
impl<A: Array<Item=u8>> Hash for ArrayString<A> { impl<A> Hash for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn hash<H: Hasher>(&self, h: &mut H) { fn hash<H: Hasher>(&self, h: &mut H) {
(**self).hash(h) (**self).hash(h)
} }
} }
impl<A: Array<Item=u8>> Borrow<str> for ArrayString<A> { impl<A> Borrow<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn borrow(&self) -> &str { self } fn borrow(&self) -> &str { self }
} }
impl<A: Array<Item=u8>> AsRef<str> for ArrayString<A> { impl<A> AsRef<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn as_ref(&self) -> &str { self } fn as_ref(&self) -> &str { self }
} }
impl<A: Array<Item=u8>> fmt::Debug for ArrayString<A> { impl<A> fmt::Debug for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
} }
impl<A: Array<Item=u8>> fmt::Display for ArrayString<A> { impl<A> fmt::Display for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
} }
/// `Write` appends written data to the end of the string. /// `Write` appends written data to the end of the string.
impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> { impl<A> fmt::Write for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn write_char(&mut self, c: char) -> fmt::Result { fn write_char(&mut self, c: char) -> fmt::Result {
self.try_push(c).map_err(|_| fmt::Error) self.try_push(c).map_err(|_| fmt::Error)
} }
@@ -420,7 +450,9 @@ impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
} }
} }
impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> { impl<A> Clone for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn clone(&self) -> ArrayString<A> { fn clone(&self) -> ArrayString<A> {
*self *self
} }
@@ -431,7 +463,9 @@ impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
} }
} }
impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> { impl<A> PartialOrd for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> { fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**rhs) (**self).partial_cmp(&**rhs)
} }
@@ -441,7 +475,9 @@ impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs } fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
} }
impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> { impl<A> PartialOrd<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> { fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
(**self).partial_cmp(rhs) (**self).partial_cmp(rhs)
} }
@@ -451,7 +487,9 @@ impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
fn ge(&self, rhs: &str) -> bool { &**self >= rhs } fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
} }
impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str { impl<A> PartialOrd<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> { fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
self.partial_cmp(&**rhs) self.partial_cmp(&**rhs)
} }
@@ -461,7 +499,9 @@ impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs } fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
} }
impl<A: Array<Item=u8>> Ord for ArrayString<A> { impl<A> Ord for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn cmp(&self, rhs: &Self) -> cmp::Ordering { fn cmp(&self, rhs: &Self) -> cmp::Ordering {
(**self).cmp(&**rhs) (**self).cmp(&**rhs)
} }
@@ -469,7 +509,9 @@ impl<A: Array<Item=u8>> Ord for ArrayString<A> {
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"` /// Requires crate feature `"serde-1"`
impl<A: Array<Item=u8>> Serialize for ArrayString<A> { impl<A> Serialize for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer where S: Serializer
{ {
@@ -479,7 +521,9 @@ impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"` /// Requires crate feature `"serde-1"`
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> { impl<'de, A> Deserialize<'de> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> where D: Deserializer<'de>
{ {
@@ -488,7 +532,7 @@ impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>); struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> { impl<'de, A: Copy + Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
type Value = ArrayString<A>; type Value = ArrayString<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+4 -4
View File
@@ -16,7 +16,7 @@
//! //!
//! ## Rust Version //! ## Rust Version
//! //!
//! This version of arrayvec requires Rust 1.13 or later. //! This version of arrayvec requires Rust 1.24 or later.
//! //!
#![doc(html_root_url="https://docs.rs/arrayvec/0.4/")] #![doc(html_root_url="https://docs.rs/arrayvec/0.4/")]
#![cfg_attr(not(feature="std"), no_std)] #![cfg_attr(not(feature="std"), no_std)]
@@ -56,7 +56,10 @@ mod maybe_uninit;
#[path="maybe_uninit_nodrop.rs"] #[path="maybe_uninit_nodrop.rs"]
mod maybe_uninit; mod maybe_uninit;
mod maybe_uninit_copy;
use maybe_uninit::MaybeUninit; use maybe_uninit::MaybeUninit;
use maybe_uninit_copy::MaybeUninitCopy;
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use serde::{Serialize, Deserialize, Serializer, Deserializer};
@@ -614,9 +617,6 @@ impl<A: Array> ArrayVec<A> {
/// ///
/// Return an `Ok` value with the array if length equals capacity, /// Return an `Ok` value with the array if length equals capacity,
/// return an `Err` with self otherwise. /// return an `Err` with self otherwise.
///
/// `Note:` This function may incur unproportionally large overhead
/// to move the array out, its performance is not optimal.
pub fn into_inner(self) -> Result<A, Self> { pub fn into_inner(self) -> Result<A, Self> {
if self.len() < self.capacity() { if self.len() < self.capacity() {
Err(self) Err(self)
+42
View File
@@ -0,0 +1,42 @@
use array::Array;
#[derive(Copy, Clone)]
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
}
}