FEAT: Port ArrayString to const generics

This commit is contained in:
bluss
2021-03-23 17:31:27 +01:00
parent fc9c4068f5
commit c9b095f263
4 changed files with 84 additions and 159 deletions
+84 -109
View File
@@ -3,6 +3,7 @@ use std::cmp;
use std::convert::TryFrom;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem::MaybeUninit;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::slice;
@@ -10,16 +11,12 @@ use std::str;
use std::str::FromStr;
use std::str::Utf8Error;
use crate::array::Array;
use crate::array::Index;
use crate::CapacityError;
use crate::char::encode_utf8;
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use super::MaybeUninit as MaybeUninitCopy;
/// A string with a fixed capacity.
///
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
@@ -28,24 +25,21 @@ use super::MaybeUninit as MaybeUninitCopy;
/// The string is a contiguous value that you can store directly on the stack
/// if needed.
#[derive(Copy)]
pub struct ArrayString<A>
where A: Array<Item=u8> + Copy
{
xs: MaybeUninitCopy<A>,
len: A::Index,
pub struct ArrayString<const CAP: usize> {
// the `len` first elements of the array are initialized
xs: [MaybeUninit<u8>; CAP],
len: usize,
}
impl<A> Default for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> Default for ArrayString<CAP>
{
/// Return an empty `ArrayString`
fn default() -> ArrayString<A> {
fn default() -> ArrayString<CAP> {
ArrayString::new()
}
}
impl<A> ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> ArrayString<CAP>
{
/// Create a new empty `ArrayString`.
///
@@ -54,34 +48,28 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 16]>::new();
/// let mut string = ArrayString::<16>::new();
/// string.push_str("foo");
/// assert_eq!(&string[..], "foo");
/// assert_eq!(string.capacity(), 16);
/// ```
#[cfg(not(feature="unstable-const-fn"))]
pub fn new() -> ArrayString<A> {
pub fn new() -> ArrayString<CAP> {
unsafe {
ArrayString {
xs: MaybeUninitCopy::uninitialized(),
len: Index::ZERO,
}
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
}
}
#[cfg(feature="unstable-const-fn")]
pub const fn new() -> ArrayString<A> {
pub const fn new() -> ArrayString<CAP> {
unsafe {
ArrayString {
xs: MaybeUninitCopy::uninitialized(),
len: Index::ZERO,
}
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
}
}
/// Return the length of the string.
#[inline]
pub fn len(&self) -> usize { self.len.to_usize() }
pub fn len(&self) -> usize { self.len }
/// Returns whether the string is empty.
#[inline]
@@ -96,7 +84,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 3]>::from("foo").unwrap();
/// let mut string = ArrayString::<3>::from("foo").unwrap();
/// assert_eq!(&string[..], "foo");
/// assert_eq!(string.len(), 3);
/// assert_eq!(string.capacity(), 3);
@@ -116,13 +104,16 @@ impl<A> ArrayString<A>
///
/// let string = ArrayString::from_byte_string(b"hello world").unwrap();
/// ```
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);
Ok(ArrayString {
xs: MaybeUninitCopy::from(*b),
len: Index::from(A::CAPACITY),
})
pub fn from_byte_string(b: &[u8; CAP]) -> Result<Self, Utf8Error> {
let len = str::from_utf8(b)?.len();
debug_assert_eq!(len, CAP);
let mut vec = Self::new();
unsafe {
(b as *const [u8; CAP] as *const [MaybeUninit<u8>; CAP])
.copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit<u8>; CAP], 1);
vec.set_len(CAP);
}
Ok(vec)
}
/// Return the capacity of the `ArrayString`.
@@ -130,18 +121,18 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let string = ArrayString::<[_; 3]>::new();
/// let string = ArrayString::<3>::new();
/// assert_eq!(string.capacity(), 3);
/// ```
#[inline(always)]
pub fn capacity(&self) -> usize { A::CAPACITY }
pub fn capacity(&self) -> usize { CAP }
/// Return if the `ArrayString` is completely filled.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 1]>::new();
/// let mut string = ArrayString::<1>::new();
/// assert!(!string.is_full());
/// string.push_str("A");
/// assert!(string.is_full());
@@ -155,7 +146,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
/// let mut string = ArrayString::<2>::new();
///
/// string.push('a');
/// string.push('b');
@@ -175,7 +166,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
/// let mut string = ArrayString::<2>::new();
///
/// string.try_push('a').unwrap();
/// string.try_push('b').unwrap();
@@ -187,7 +178,7 @@ impl<A> ArrayString<A>
pub fn try_push(&mut self, c: char) -> Result<(), CapacityError<char>> {
let len = self.len();
unsafe {
let ptr = self.xs.ptr_mut().add(len);
let ptr = self.as_mut_ptr().add(len);
let remaining_cap = self.capacity() - len;
match encode_utf8(c, ptr, remaining_cap) {
Ok(n) => {
@@ -206,7 +197,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
/// let mut string = ArrayString::<2>::new();
///
/// string.push_str("a");
/// string.push_str("d");
@@ -226,7 +217,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
/// let mut string = ArrayString::<2>::new();
///
/// string.try_push_str("a").unwrap();
/// let overflow1 = string.try_push_str("bc");
@@ -242,7 +233,7 @@ impl<A> ArrayString<A>
return Err(CapacityError::new(s));
}
unsafe {
let dst = self.xs.ptr_mut().add(self.len());
let dst = self.as_mut_ptr().add(self.len());
let src = s.as_ptr();
ptr::copy_nonoverlapping(src, dst, s.len());
let newl = self.len() + s.len();
@@ -258,7 +249,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut s = ArrayString::<[_; 3]>::from("foo").unwrap();
/// let mut s = ArrayString::<3>::from("foo").unwrap();
///
/// assert_eq!(s.pop(), Some('o'));
/// assert_eq!(s.pop(), Some('o'));
@@ -288,7 +279,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 6]>::from("foobar").unwrap();
/// let mut string = ArrayString::<6>::from("foobar").unwrap();
/// string.truncate(3);
/// assert_eq!(&string[..], "foo");
/// string.truncate(4);
@@ -318,7 +309,7 @@ impl<A> ArrayString<A>
/// ```
/// use arrayvec::ArrayString;
///
/// let mut s = ArrayString::<[_; 3]>::from("foo").unwrap();
/// let mut s = ArrayString::<3>::from("foo").unwrap();
///
/// assert_eq!(s.remove(0), 'f');
/// assert_eq!(s.remove(1), 'o');
@@ -333,8 +324,8 @@ impl<A> ArrayString<A>
let next = idx + ch.len_utf8();
let len = self.len();
unsafe {
ptr::copy(self.xs.ptr().add(next),
self.xs.ptr_mut().add(idx),
ptr::copy(self.as_ptr().add(next),
self.as_mut_ptr().add(idx),
len - next);
self.set_len(len - (next - idx));
}
@@ -357,103 +348,99 @@ impl<A> ArrayString<A>
/// and may use other debug assertions.
pub unsafe fn set_len(&mut self, length: usize) {
debug_assert!(length <= self.capacity());
self.len = Index::from(length);
self.len = length;
}
/// Return a string slice of the whole `ArrayString`.
pub fn as_str(&self) -> &str {
self
}
fn as_ptr(&self) -> *const u8 {
self.xs.as_ptr() as *const u8
}
impl<A> Deref for ArrayString<A>
where A: Array<Item=u8> + Copy
fn as_mut_ptr(&mut self) -> *mut u8 {
self.xs.as_mut_ptr() as *mut u8
}
}
impl<const CAP: usize> Deref for ArrayString<CAP>
{
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe {
let sl = slice::from_raw_parts(self.xs.ptr(), self.len.to_usize());
let sl = slice::from_raw_parts(self.as_ptr(), self.len);
str::from_utf8_unchecked(sl)
}
}
}
impl<A> DerefMut for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> DerefMut for ArrayString<CAP>
{
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe {
let sl = slice::from_raw_parts_mut(self.xs.ptr_mut(), self.len.to_usize());
let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), self.len);
str::from_utf8_unchecked_mut(sl)
}
}
}
impl<A> PartialEq for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> PartialEq for ArrayString<CAP>
{
fn eq(&self, rhs: &Self) -> bool {
**self == **rhs
}
}
impl<A> PartialEq<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> PartialEq<str> for ArrayString<CAP>
{
fn eq(&self, rhs: &str) -> bool {
&**self == rhs
}
}
impl<A> PartialEq<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
impl<const CAP: usize> PartialEq<ArrayString<CAP>> for str
{
fn eq(&self, rhs: &ArrayString<A>) -> bool {
fn eq(&self, rhs: &ArrayString<CAP>) -> bool {
self == &**rhs
}
}
impl<A> Eq for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> Eq for ArrayString<CAP>
{ }
impl<A> Hash for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> Hash for ArrayString<CAP>
{
fn hash<H: Hasher>(&self, h: &mut H) {
(**self).hash(h)
}
}
impl<A> Borrow<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> Borrow<str> for ArrayString<CAP>
{
fn borrow(&self) -> &str { self }
}
impl<A> AsRef<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> AsRef<str> for ArrayString<CAP>
{
fn as_ref(&self) -> &str { self }
}
impl<A> fmt::Debug for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> fmt::Debug for ArrayString<CAP>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}
impl<A> fmt::Display for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> fmt::Display for ArrayString<CAP>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}
/// `Write` appends written data to the end of the string.
impl<A> fmt::Write for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> fmt::Write for ArrayString<CAP>
{
fn write_char(&mut self, c: char) -> fmt::Result {
self.try_push(c).map_err(|_| fmt::Error)
@@ -464,10 +451,9 @@ impl<A> fmt::Write for ArrayString<A>
}
}
impl<A> Clone for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> Clone for ArrayString<CAP>
{
fn clone(&self) -> ArrayString<A> {
fn clone(&self) -> ArrayString<CAP> {
*self
}
fn clone_from(&mut self, rhs: &Self) {
@@ -477,8 +463,7 @@ impl<A> Clone for ArrayString<A>
}
}
impl<A> PartialOrd for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> PartialOrd for ArrayString<CAP>
{
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**rhs)
@@ -489,8 +474,7 @@ impl<A> PartialOrd for ArrayString<A>
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
}
impl<A> PartialOrd<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> PartialOrd<str> for ArrayString<CAP>
{
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
(**self).partial_cmp(rhs)
@@ -501,28 +485,25 @@ impl<A> PartialOrd<str> for ArrayString<A>
fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
}
impl<A> PartialOrd<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
impl<const CAP: usize> PartialOrd<ArrayString<CAP>> for str
{
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
fn partial_cmp(&self, rhs: &ArrayString<CAP>) -> Option<cmp::Ordering> {
self.partial_cmp(&**rhs)
}
fn lt(&self, rhs: &ArrayString<A>) -> bool { self < &**rhs }
fn le(&self, rhs: &ArrayString<A>) -> bool { self <= &**rhs }
fn gt(&self, rhs: &ArrayString<A>) -> bool { self > &**rhs }
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
fn lt(&self, rhs: &ArrayString<CAP>) -> bool { self < &**rhs }
fn le(&self, rhs: &ArrayString<CAP>) -> bool { self <= &**rhs }
fn gt(&self, rhs: &ArrayString<CAP>) -> bool { self > &**rhs }
fn ge(&self, rhs: &ArrayString<CAP>) -> bool { self >= &**rhs }
}
impl<A> Ord for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> Ord for ArrayString<CAP>
{
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
(**self).cmp(&**rhs)
}
}
impl<A> FromStr for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> FromStr for ArrayString<CAP>
{
type Err = CapacityError;
@@ -533,8 +514,7 @@ impl<A> FromStr for ArrayString<A>
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<A> Serialize for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<const CAP: usize> Serialize for ArrayString<CAP>
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
@@ -545,8 +525,7 @@ impl<A> Serialize for ArrayString<A>
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<'de, A> Deserialize<'de> for ArrayString<A>
where A: Array<Item=u8> + Copy
impl<'de, const CAP: usize> Deserialize<'de> for ArrayString<CAP>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
@@ -554,13 +533,13 @@ impl<'de, A> Deserialize<'de> for ArrayString<A>
use serde::de::{self, Visitor};
use std::marker::PhantomData;
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
struct ArrayStringVisitor<const CAP: usize>(PhantomData([u8; CAP]));
impl<'de, A: Copy + Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
type Value = ArrayString<A>;
impl<'de, const CAP: usize> Visitor<'de> for ArrayStringVisitor {
type Value = ArrayString;
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", CAP)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
@@ -578,13 +557,11 @@ impl<'de, A> Deserialize<'de> for ArrayString<A>
}
}
deserializer.deserialize_str(ArrayStringVisitor::<A>(PhantomData))
deserializer.deserialize_str(ArrayStringVisitor(PhantomData))
}
}
impl<'a, A> TryFrom<&'a str> for ArrayString<A>
where
A: Array<Item = u8> + Copy
impl<'a, const CAP: usize> TryFrom<&'a str> for ArrayString<CAP>
{
type Error = CapacityError<&'a str>;
@@ -595,9 +572,7 @@ where
}
}
impl<'a, A> TryFrom<fmt::Arguments<'a>> for ArrayString<A>
where
A: Array<Item = u8> + Copy
impl<'a, const CAP: usize> TryFrom<fmt::Arguments<'a>> for ArrayString<CAP>
{
type Error = CapacityError<fmt::Error>;
-3
View File
@@ -17,9 +17,6 @@ use std::io;
use std::mem::ManuallyDrop;
use std::mem::MaybeUninit;
//use crate::maybe_uninit::MaybeUninit;
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
-3
View File
@@ -34,9 +34,6 @@ extern crate serde;
#[cfg(not(feature="std"))]
extern crate core as std;
mod maybe_uninit;
use crate::maybe_uninit::MaybeUninit;
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
-44
View File
@@ -1,44 +0,0 @@
use crate::array::Array;
use std::mem::MaybeUninit as StdMaybeUninit;
#[derive(Copy)]
pub struct MaybeUninit<T> {
inner: StdMaybeUninit<T>,
}
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 const 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
{
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
}
}