Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TryFrom/From Conversion Methods for Vec<_> and Box<[_]> #195

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
138 changes: 138 additions & 0 deletions src/array_string.rs
Expand Up @@ -365,6 +365,102 @@ impl<const CAP: usize> ArrayString<CAP>
self.len = length as LenUint;
}

/// Converts `self` into an allocated byte-vector with the given capacity.
///
/// # Safety
///
/// The caller is responsible for ensuring that `capacity >= self.len()`.
pub unsafe fn into_bytes_with_capacity(self, capacity: usize) -> Vec<u8> {
debug_assert!(capacity >= self.len());

let mut vec = Vec::with_capacity(capacity);
let me = core::mem::ManuallyDrop::new(self);
let len = me.len();

// SAFETY: The caller ensures that we own a region of memory at least as large as `len`
// at the location pointed to by `vec`.
me.as_ptr().copy_to_nonoverlapping(vec.as_mut_ptr(), len);
vec.set_len(len);

vec
}

/// Converts `self` into an allocated vector of bytes.
///
/// # Allocation
///
/// This method allocates a vector with capacity equal to the capacity of the original
/// `ArrayString`.
///
/// To only allocate exactly enough space for the string stored in `self`, use the
/// [`into_boxed_str`](Self::into_boxed_str) method.
///
/// To allocate a specific amount of space, see the
/// [`into_bytes_with_capacity`](Self::into_bytes_with_capacity) method.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use arrayvec::ArrayString;
///
/// let s = ArrayString::<5>::from("hello").unwrap();
/// let bytes = s.into_bytes();
///
/// assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]);
/// ```
#[inline]
pub fn into_bytes(self) -> Vec<u8> {
// SAFETY: The capacity of `self` is at least as large as the length of `self`.
unsafe {
self.into_bytes_with_capacity(CAP)
}
}

/// Converts this `ArrayString` into a [`Box`]`<`[`str`]`>`.
///
/// This will drop any excess capacity.
///
/// [`str`]: prim@str
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use arrayvec::ArrayString;
///
/// let s = ArrayString::<5>::from("hello").unwrap();
///
/// let b = s.into_boxed_str();
/// ```
#[inline]
pub fn into_boxed_str(self) -> Box<str> {
let len = self.len();
// SAFETY: We only require the memory capacity equal to the length of the initialized data region in `self`.
unsafe {
str::from_boxed_utf8_unchecked(self.into_bytes_with_capacity(len).into_boxed_slice())
}
}

/// Create a new `ArrayString` by consuming a boxed string, moving the heap-allocated `str` to a
/// stack-allocated array.
///
/// # Safety
///
/// The caller is responsible for ensuring that the string has a length no larger than the
/// capacity of `ArrayString`.
pub unsafe fn from_boxed_str_unchecked(boxed_string: Box<str>) -> Self {
debug_assert!(CAP >= boxed_string.len());
assert_capacity_limit!(CAP);
let len = boxed_string.len() as LenUint;
Self {
xs: *Box::from_raw(Box::into_raw(boxed_string) as *mut [MaybeUninit<u8>; CAP]) ,
len,
}
}

/// Return a string slice of the whole `ArrayString`.
pub fn as_str(&self) -> &str {
self
Expand Down Expand Up @@ -581,6 +677,48 @@ impl<'de, const CAP: usize> Deserialize<'de> for ArrayString<CAP>
}
}

impl<const CAP: usize> From<ArrayString<CAP>> for Box<str> {
#[inline]
fn from(array: ArrayString<CAP>) -> Self {
array.into_boxed_str()
}
}

impl<const CAP: usize> TryFrom<Box<str>> for ArrayString<CAP> {
type Error = CapacityError;

fn try_from(string: Box<str>) -> Result<Self, Self::Error> {
if CAP < string.len() {
Err(CapacityError::new(()))
} else {
Ok(unsafe { Self::from_boxed_str_unchecked(string) })
}
}
}

impl<const CAP: usize> From<ArrayString<CAP>> for Vec<u8> {
#[inline]
fn from(array: ArrayString<CAP>) -> Self {
array.into_bytes()
}
}

impl<const CAP: usize> From<ArrayString<CAP>> for String {
#[inline]
fn from(array: ArrayString<CAP>) -> Self {
array.to_string()
}
}

impl<const CAP: usize> TryFrom<String> for ArrayString<CAP> {
type Error = CapacityError;

#[inline]
fn try_from(string: String) -> Result<Self, Self::Error> {
Self::try_from(string.into_boxed_str())
}
}

impl<'a, const CAP: usize> TryFrom<&'a str> for ArrayString<CAP>
{
type Error = CapacityError<&'a str>;
Expand Down
181 changes: 173 additions & 8 deletions src/arrayvec.rs
@@ -1,5 +1,5 @@

use std::cmp;
use std::convert::TryFrom;
use std::iter;
use std::mem;
use std::ops::{Bound, Deref, DerefMut, RangeBounds};
Expand Down Expand Up @@ -61,9 +61,6 @@ macro_rules! panic_oob {
}

impl<T, const CAP: usize> ArrayVec<T, CAP> {
/// Capacity
const CAPACITY: usize = CAP;

/// Create a new empty `ArrayVec`.
///
/// The maximum capacity is given by the generic parameter `CAP`.
Expand Down Expand Up @@ -642,14 +639,83 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {

/// Return the inner fixed size array.
///
/// Safety:
/// # Safety
///
/// This operation is safe if and only if length equals capacity.
pub unsafe fn into_inner_unchecked(self) -> [T; CAP] {
debug_assert_eq!(self.len(), self.capacity());
let self_ = ManuallyDrop::new(self);
let array = ptr::read(self_.as_ptr() as *const [T; CAP]);
array
}

/// Converts `self` into an allocated vector with the given capacity.
///
/// # Safety
///
/// The caller is responsible for ensuring that `capacity >= self.len()`.
pub unsafe fn into_vec_with_capacity(self, capacity: usize) -> Vec<T> {
debug_assert!(capacity >= self.len());

let mut vec = Vec::with_capacity(capacity);
let me = ManuallyDrop::new(self);
let len = me.len();

// SAFETY: The caller ensures that we own a region of memory at least as large as `len`
// at the location pointed to by `vec`.
me.as_ptr().copy_to_nonoverlapping(vec.as_mut_ptr(), len);
vec.set_len(len);

vec
}

/// Converts `self` into an allocated vector.
///
/// # Allocation
///
/// This method allocates a vector with capacity equal to the capacity of the original `ArrayVec`.
///
/// To only allocate exactly enough space for the elements stored in `self`, use the
/// [`into_boxed_slice`](Self::into_boxed_slice) method.
///
/// To allocate a specific amount of space, see the
/// [`into_vec_with_capacity`](Self::into_vec_with_capacity) method.
#[inline]
pub fn into_vec(self) -> Vec<T> {
// SAFETY: The capacity of `self` is at least as large as the length of `self`.
unsafe {
self.into_vec_with_capacity(CAP)
}
}

/// Converts the `ArrayVec` into `Box<[T]>`.
///
/// Note that this will drop any excess capacity.
#[inline]
pub fn into_boxed_slice(self) -> Box<[T]> {
let len = self.len();
// SAFETY: We only require the memory capacity equal to the length of the initialized data region in `self`.
unsafe {
self.into_vec_with_capacity(len).into_boxed_slice()
}
}

/// Create a new `ArrayVec` by consuming a boxed slice, moving the heap-allocated slice to a
/// stack-allocated array.
///
/// # Safety
///
/// The caller is responsible for ensuring that the slice has a length no larger than the
/// capacity of `ArrayVec`.
pub unsafe fn from_boxed_slice_unchecked(boxed_slice: Box<[T]>) -> Self {
debug_assert!(CAP >= boxed_slice.len());
assert_capacity_limit!(CAP);
let len = boxed_slice.len() as LenUint;
Self {
xs: *Box::from_raw(Box::into_raw(boxed_slice) as *mut [MaybeUninit<T>; CAP]) ,
len,
}
}

/// Returns the ArrayVec, replacing the original with a new empty ArrayVec.
///
Expand Down Expand Up @@ -743,7 +809,6 @@ impl<T, const CAP: usize> From<[T; CAP]> for ArrayVec<T, CAP> {
}
}


/// Try to create an `ArrayVec` from a slice. This will return an error if the slice was too big to
/// fit.
///
Expand All @@ -755,13 +820,13 @@ impl<T, const CAP: usize> From<[T; CAP]> for ArrayVec<T, CAP> {
/// assert_eq!(array.len(), 3);
/// assert_eq!(array.capacity(), 4);
/// ```
impl<T, const CAP: usize> std::convert::TryFrom<&[T]> for ArrayVec<T, CAP>
impl<T, const CAP: usize> TryFrom<&[T]> for ArrayVec<T, CAP>
where T: Clone,
{
type Error = CapacityError;

fn try_from(slice: &[T]) -> Result<Self, Self::Error> {
if Self::CAPACITY < slice.len() {
if CAP < slice.len() {
Err(CapacityError::new(()))
} else {
let mut array = Self::new();
Expand All @@ -771,6 +836,106 @@ impl<T, const CAP: usize> std::convert::TryFrom<&[T]> for ArrayVec<T, CAP>
}
}

/// Create a `Box<[T]>` from an `ArrayVec<T>`.
///
/// ```
/// use arrayvec::ArrayVec;
///
/// let array = ArrayVec::from([1, 2, 3]);
/// let slice = Box::<[_]>::from(array.clone());
/// assert_eq!(array.as_slice(), slice.as_ref());
/// ```
impl<T, const CAP: usize> From<ArrayVec<T, CAP>> for Box<[T]> {
#[inline]
fn from(array: ArrayVec<T, CAP>) -> Self {
array.into_boxed_slice()
}
}

/// Try to create an `ArrayVec` from a `Box<[_]>`. This will return an error if the boxed slice was too big to
/// fit.
///
/// ```
/// use arrayvec::ArrayVec;
/// use std::convert::TryInto as _;
///
/// let slice: Box<[_]> = Box::new([1, 2, 3]);
/// let array: ArrayVec<_, 4> = slice.clone().try_into().unwrap();
/// assert_eq!(array.len(), 3);
/// assert_eq!(array.capacity(), 4);
/// ```
impl<T, const CAP: usize> TryFrom<Box<[T]>> for ArrayVec<T, CAP> {
type Error = CapacityError;

fn try_from(slice: Box<[T]>) -> Result<Self, Self::Error> {
if CAP < slice.len() {
Err(CapacityError::new(()))
} else {
Ok(unsafe { Self::from_boxed_slice_unchecked(slice) })
}
}
}

/// Try to create an `ArrayVec` from a `Box<[_; N]>`. This will return an error if the boxed array was too big to
/// fit.
///
/// ```
/// use arrayvec::ArrayVec;
/// use std::convert::TryInto as _;
///
/// let slice: Box<[_; 3]> = Box::new([1, 2, 3]);
/// let array: ArrayVec<_, 4> = slice.clone().try_into().unwrap();
/// assert_eq!(array.len(), 3);
/// assert_eq!(array.capacity(), 4);
/// ```
impl<T, const N: usize, const CAP: usize> TryFrom<Box<[T; N]>> for ArrayVec<T, CAP> {
type Error = CapacityError;

#[inline]
fn try_from(array: Box<[T; N]>) -> Result<Self, Self::Error> {
Self::try_from(array as Box<[_]>)
}
}

/// Create a `Vec<T>` from an `ArrayVec<T>`.
///
/// ```
/// use arrayvec::ArrayVec;
/// use std::convert::TryInto as _;
///
/// let array: ArrayVec<_, 4> = vec![1, 2, 3].try_into().unwrap();
/// let vector = Vec::from(array.clone());
/// assert_eq!(array.capacity(), vector.capacity());
/// assert_eq!(array.as_slice(), vector.as_slice());
/// ```
impl<T, const CAP: usize> From<ArrayVec<T, CAP>> for Vec<T> {
#[inline]
fn from(array: ArrayVec<T, CAP>) -> Self {
array.into_vec()
}
}

/// Try to create an `ArrayVec` from a `Vec`. This will return an error if the vector was too big to
/// fit.
///
/// ```
/// use arrayvec::ArrayVec;
/// use std::convert::TryInto as _;
///
/// let vec = vec![1, 2, 3];
/// let array: ArrayVec<_, 4> = vec.clone().try_into().unwrap();
/// assert_eq!(array.len(), 3);
/// assert_eq!(array.capacity(), 4);
/// assert_eq!(vec.as_slice(), array.as_slice());
/// ```
impl<T, const CAP: usize> TryFrom<Vec<T>> for ArrayVec<T, CAP> {
type Error = CapacityError;

#[inline]
fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
Self::try_from(vec.into_boxed_slice())
}
}

/// Iterate the `ArrayVec` with references to each element.
///
Expand Down