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
+21 -22
View File
@@ -4,43 +4,42 @@ env:
- FEATURES='serde-1'
matrix:
include:
- rust: 1.20.0
- rust: stable
env:
- NODEFAULT=1
- NODROP_FEATURES='use_needs_drop'
- rust: 1.22.1
- rust: 1.24.1
env:
- FEATURES='array-sizes-33-128 array-sizes-129-255'
- rust: stable
- rust: stable
env:
- FEATURES='serde-1'
- rust: stable
env:
- FEATURES='array-sizes-33-128 array-sizes-129-255'
- rust: beta
- rust: nightly
env:
- NODEFAULT=1
- ARRAYVECTEST_ENSURE_UNION=1
- rust: nightly
env:
- NODROP_FEATURES='use_needs_drop'
- ARRAYVECTEST_ENSURE_UNION=1
- rust: nightly
env:
- FEATURES='serde use_union'
- NODROP_FEATURES='use_union'
- 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'
branches:
only:
- master
- 0.4
script:
- |
([ ! -z "$NODROP_FEATURES" ] || cargo build --verbose --features "$FEATURES") &&
([ "$NODEFAULT" != 1 ] || cargo build --verbose --no-default-features) &&
([ ! -z "$NODROP_FEATURES" ] || cargo test --verbose --features "$FEATURES") &&
([ ! -z "$NODROP_FEATURES" ] || cargo test --release --verbose --features "$FEATURES") &&
([ ! -z "$NODROP_FEATURES" ] || cargo bench --verbose --features "$FEATURES" -- --test) &&
([ ! -z "$NODROP_FEATURES" ] || cargo doc --verbose --features "$FEATURES") &&
([ "$NODEFAULT" != 1 ] || cargo build --verbose --manifest-path=nodrop/Cargo.toml --no-default-features) &&
cargo test --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" &&
cargo bench --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" -- --test
cargo build -v --no-default-features &&
cargo build -v --features "$FEATURES" &&
cargo test -v --features "$FEATURES" &&
cargo test -v --release --features "$FEATURES" &&
cargo bench -v --features "$FEATURES" --no-run &&
cargo doc -v --features "$FEATURES" &&
cargo build -v --manifest-path=nodrop/Cargo.toml &&
cargo test -v --manifest-path=nodrop/Cargo.toml
-3
View File
@@ -44,9 +44,6 @@ serde-1 = ["serde"]
array-sizes-33-128 = []
array-sizes-129-255 = []
# has no effect
use_union = []
[package.metadata.docs.rs]
features = ["serde-1"]
+4 -6
View File
@@ -15,14 +15,14 @@
pub unsafe trait Array {
/// The arrays element type
type Item;
/// The smallest type that can index and tell the length of the array.
#[doc(hidden)]
/// The smallest index type that indexes the array.
type Index: Index;
/// The array's element capacity
const CAPACITY: usize;
#[doc(hidden)]
fn as_ptr(&self) -> *const Self::Item;
#[doc(hidden)]
fn as_mut_ptr(&mut self) -> *mut Self::Item;
#[doc(hidden)]
fn capacity() -> usize;
}
@@ -91,14 +91,12 @@ macro_rules! fix_array_impl {
unsafe impl<T> Array for [T; $len] {
type Item = T;
type Index = $index_type;
const CAPACITY: usize = $len;
#[doc(hidden)]
#[inline(always)]
fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
#[doc(hidden)]
#[inline(always)]
fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
#[doc(hidden)]
#[inline(always)]
fn capacity() -> usize { $len }
}
)
+83 -39
View File
@@ -2,7 +2,6 @@ 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;
@@ -17,6 +16,8 @@ use char::encode_utf8;
#[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use super::MaybeUninitCopy;
/// A string with a fixed capacity.
///
/// 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
/// if needed.
#[derive(Copy)]
pub struct ArrayString<A: Array<Item=u8>> {
// FIXME: Use Copyable union for xs when we can
xs: A,
pub struct ArrayString<A>
where A: Array<Item=u8> + Copy
{
xs: MaybeUninitCopy<A>,
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`
fn default() -> ArrayString<A> {
ArrayString::new()
}
}
impl<A: Array<Item=u8>> ArrayString<A> {
impl<A> ArrayString<A>
where A: Array<Item=u8> + Copy
{
/// Create a new empty `ArrayString`.
///
/// Capacity is inferred from the type parameter.
@@ -54,8 +60,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
pub fn new() -> ArrayString<A> {
unsafe {
ArrayString {
// FIXME: Use Copyable union for xs when we can
xs: mem::zeroed(),
xs: MaybeUninitCopy::uninitialized(),
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();
/// ```
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
let mut arraystr = Self::new();
let s = try!(str::from_utf8(b.as_slice()));
let _result = arraystr.try_push_str(s);
debug_assert!(_result.is_ok());
Ok(arraystr)
let len = str::from_utf8(b.as_slice())?.len();
debug_assert_eq!(len, A::capacity());
Ok(ArrayString {
xs: MaybeUninitCopy::from(*b),
len: Index::from(A::capacity()),
})
}
/// Return the capacity of the `ArrayString`.
@@ -213,7 +219,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
return Err(CapacityError::new(s));
}
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();
ptr::copy_nonoverlapping(src, dst, 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 len = self.len();
unsafe {
ptr::copy(self.xs.as_ptr().offset(next as isize),
self.xs.as_mut_ptr().offset(idx as isize),
ptr::copy(self.xs.ptr().offset(next as isize),
self.xs.ptr_mut().offset(idx as isize),
len - next);
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
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;
#[inline]
fn deref(&self) -> &str {
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)
}
}
}
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> {
impl<A> DerefMut for ArrayString<A>
where A: Array<Item=u8> + Copy
{
#[inline]
fn deref_mut(&mut self) -> &mut str {
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)
}
}
}
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 {
**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 {
&**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 {
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) {
(**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 }
}
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 }
}
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) }
}
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) }
}
/// `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 {
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> {
*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> {
(**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 }
}
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> {
(**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 }
}
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> {
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 }
}
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 {
(**self).cmp(&**rhs)
}
@@ -469,7 +509,9 @@ impl<A: Array<Item=u8>> Ord for ArrayString<A> {
#[cfg(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>
where S: Serializer
{
@@ -479,7 +521,9 @@ impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
#[cfg(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>
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>);
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>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+4 -4
View File
@@ -16,7 +16,7 @@
//!
//! ## 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/")]
#![cfg_attr(not(feature="std"), no_std)]
@@ -56,7 +56,10 @@ mod maybe_uninit;
#[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};
@@ -614,9 +617,6 @@ impl<A: Array> ArrayVec<A> {
///
/// Return an `Ok` value with the array if length equals capacity,
/// 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> {
if self.len() < self.capacity() {
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
}
}