Skip to content

feat+refactor: Bump MSRV to 1.83.0 and maximize const #294

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches: [ master ]
branches: [master]

name: Continuous integration

@@ -17,12 +17,10 @@ jobs:
strategy:
matrix:
include:
- rust: 1.51.0 # MSRV
- rust: 1.83.0 # MSRV
features: serde
experimental: false
# doctest of `ArrayVec::spare_capacity_mut` has MSRV 1.55
test-args: --skip spare_capacity_mut
- rust: 1.70.0
- rust: 1.85.0
features: serde
experimental: false
- rust: stable
@@ -42,7 +40,7 @@ jobs:
with:
toolchain: ${{ matrix.rust }}
- name: Pin versions for MSRV
if: "${{ matrix.rust == '1.51.0' }}"
if: "${{ matrix.rust == '1.83.0' }}"
run: |
cargo update -p serde_test --precise 1.0.163
cargo update -p serde --precise 1.0.69
@@ -80,7 +78,6 @@ jobs:
run: |
cargo rustc "--target=${{ matrix.target }}" --no-default-features --features "${{ matrix.features }}"


miri:
runs-on: ubuntu-latest
steps:
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ version = "0.7.6"
authors = ["bluss"]
license = "MIT OR Apache-2.0"
edition = "2018"
rust-version = "1.51"
rust-version = "1.83"

description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."
documentation = "https://docs.rs/arrayvec/"
61 changes: 33 additions & 28 deletions src/array_string.rs
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ impl<const CAP: usize> ArrayString<CAP>
/// assert_eq!(&string[..], "foo");
/// assert_eq!(string.capacity(), 16);
/// ```
pub fn new() -> ArrayString<CAP> {
pub const fn new() -> ArrayString<CAP> {
assert_capacity_limit!(CAP);
unsafe {
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
@@ -105,10 +105,12 @@ impl<const CAP: usize> ArrayString<CAP>
/// assert_eq!(string.len(), 3);
/// assert_eq!(string.capacity(), 3);
/// ```
pub fn from(s: &str) -> Result<Self, CapacityError<&str>> {
pub const fn from(s: &str) -> Result<Self, CapacityError<&str>> {
let mut arraystr = Self::new();
arraystr.try_push_str(s)?;
Ok(arraystr)
match arraystr.try_push_str(s) {
Ok(()) => Ok(arraystr),
Err(e) => Err(e),
}
}

/// Create a new `ArrayString` from a byte string literal.
@@ -120,9 +122,12 @@ impl<const CAP: usize> ArrayString<CAP>
///
/// let string = ArrayString::from_byte_string(b"hello world").unwrap();
/// ```
pub fn from_byte_string(b: &[u8; CAP]) -> Result<Self, Utf8Error> {
let len = str::from_utf8(b)?.len();
debug_assert_eq!(len, CAP);
pub const fn from_byte_string(b: &[u8; CAP]) -> Result<Self, Utf8Error> {
let len = match str::from_utf8(b) {
Ok(str) => str.len(),
Err(e) => return Err(e),
};
debug_assert!(len == CAP);
let mut vec = Self::new();
unsafe {
(b as *const [u8; CAP] as *const [MaybeUninit<u8>; CAP])
@@ -142,7 +147,7 @@ impl<const CAP: usize> ArrayString<CAP>
/// assert_eq!(string.len(), 16);
/// ```
#[inline]
pub fn zero_filled() -> Self {
pub const fn zero_filled() -> Self {
assert_capacity_limit!(CAP);
// SAFETY: `assert_capacity_limit` asserts that `len` won't overflow and
// `zeroed` fully fills the array with nulls.
@@ -227,7 +232,7 @@ impl<const CAP: usize> ArrayString<CAP>
/// assert_eq!(&string[..], "ab");
/// assert_eq!(overflow.unwrap_err().element(), 'c');
/// ```
pub fn try_push(&mut self, c: char) -> Result<(), CapacityError<char>> {
pub const fn try_push(&mut self, c: char) -> Result<(), CapacityError<char>> {
let len = self.len();
unsafe {
let ptr = self.as_mut_ptr().add(len);
@@ -281,7 +286,7 @@ impl<const CAP: usize> ArrayString<CAP>
/// assert_eq!(overflow1.unwrap_err().element(), "bc");
/// assert_eq!(overflow2.unwrap_err().element(), "ef");
/// ```
pub fn try_push_str<'a>(&mut self, s: &'a str) -> Result<(), CapacityError<&'a str>> {
pub const fn try_push_str<'a>(&mut self, s: &'a str) -> Result<(), CapacityError<&'a str>> {
if s.len() > self.capacity() - self.len() {
return Err(CapacityError::new(s));
}
@@ -340,7 +345,7 @@ impl<const CAP: usize> ArrayString<CAP>
/// ```
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(self.is_char_boundary(new_len));
assert!(self.as_str().is_char_boundary(new_len));
unsafe {
// In libstd truncate is called on the underlying vector,
// which in turns drops each element.
@@ -388,7 +393,7 @@ impl<const CAP: usize> ArrayString<CAP>
}

/// Make the string empty.
pub fn clear(&mut self) {
pub const fn clear(&mut self) {
unsafe {
self.set_len(0);
}
@@ -401,29 +406,36 @@ impl<const CAP: usize> ArrayString<CAP>
///
/// This method uses *debug assertions* to check the validity of `length`
/// and may use other debug assertions.
pub unsafe fn set_len(&mut self, length: usize) {
pub const unsafe fn set_len(&mut self, length: usize) {
// type invariant that capacity always fits in LenUint
debug_assert!(length <= self.capacity());
self.len = length as LenUint;
}

/// Return a string slice of the whole `ArrayString`.
pub fn as_str(&self) -> &str {
self
pub const fn as_str(&self) -> &str {
unsafe {
let sl = slice::from_raw_parts(self.as_ptr(), self.len());
str::from_utf8_unchecked(sl)
}
}

/// Return a mutable string slice of the whole `ArrayString`.
pub fn as_mut_str(&mut self) -> &mut str {
self
pub const fn as_mut_str(&mut self) -> &mut str {
unsafe {
let len = self.len();
let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), len);
str::from_utf8_unchecked_mut(sl)
}
}

/// Return a raw pointer to the string's buffer.
pub fn as_ptr(&self) -> *const u8 {
pub const fn as_ptr(&self) -> *const u8 {
self.xs.as_ptr() as *const u8
}

/// Return a raw mutable pointer to the string's buffer.
pub fn as_mut_ptr(&mut self) -> *mut u8 {
pub const fn as_mut_ptr(&mut self) -> *mut u8 {
self.xs.as_mut_ptr() as *mut u8
}
}
@@ -433,22 +445,15 @@ impl<const CAP: usize> Deref for ArrayString<CAP>
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe {
let sl = slice::from_raw_parts(self.as_ptr(), self.len());
str::from_utf8_unchecked(sl)
}
self.as_str()
}
}

impl<const CAP: usize> DerefMut for ArrayString<CAP>
{
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe {
let len = self.len();
let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), len);
str::from_utf8_unchecked_mut(sl)
}
self.as_mut_str()
}
}

124 changes: 67 additions & 57 deletions src/arrayvec.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,6 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};

use crate::LenUint;
use crate::errors::CapacityError;
use crate::arrayvec_impl::ArrayVecImpl;
use crate::utils::MakeMaybeUninit;

/// A vector with a fixed capacity.
@@ -80,7 +79,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
/// ```
#[inline]
#[track_caller]
pub fn new() -> ArrayVec<T, CAP> {
pub const fn new() -> ArrayVec<T, CAP> {
assert_capacity_limit!(CAP);
unsafe {
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
@@ -177,7 +176,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
/// ```
#[track_caller]
pub fn push(&mut self, element: T) {
ArrayVecImpl::push(self, element)
self.try_push(element).unwrap()
}

/// Push `element` to the end of the vector.
@@ -202,8 +201,15 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
///
/// assert!(overflow.is_err());
/// ```
pub fn try_push(&mut self, element: T) -> Result<(), CapacityError<T>> {
ArrayVecImpl::try_push(self, element)
pub const fn try_push(&mut self, element: T) -> Result<(), CapacityError<T>> {
if self.len() < Self::CAPACITY {
unsafe {
self.push_unchecked(element);
}
Ok(())
} else {
Err(CapacityError::new(element))
}
}

/// Push `element` to the end of the vector without checking the capacity.
@@ -227,8 +233,11 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
///
/// assert_eq!(&array[..], &[1, 2]);
/// ```
pub unsafe fn push_unchecked(&mut self, element: T) {
ArrayVecImpl::push_unchecked(self, element)
pub const unsafe fn push_unchecked(&mut self, element: T) {
let len = self.len();
debug_assert!(len < Self::CAPACITY);
ptr::write(self.as_mut_ptr().add(len), element);
self.set_len(len + 1);
}

/// Shortens the vector, keeping the first `len` elements and dropping
@@ -247,17 +256,24 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
/// assert_eq!(&array[..], &[1, 2, 3]);
/// ```
pub fn truncate(&mut self, new_len: usize) {
ArrayVecImpl::truncate(self, new_len)
unsafe {
let len = self.len();
if new_len < len {
self.set_len(new_len);
let tail = slice::from_raw_parts_mut(self.as_mut_ptr().add(new_len), len - new_len);
ptr::drop_in_place(tail);
}
}
}

/// Remove all elements in the vector.
pub fn clear(&mut self) {
ArrayVecImpl::clear(self)
self.truncate(0)
}


/// Get pointer to where element at `index` would be
unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut T {
const unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut T {
self.as_mut_ptr().add(index)
}

@@ -346,8 +362,15 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
/// assert_eq!(array.pop(), Some(1));
/// assert_eq!(array.pop(), None);
/// ```
pub fn pop(&mut self) -> Option<T> {
ArrayVecImpl::pop(self)
pub const fn pop(&mut self) -> Option<T> {
if self.len() == 0 {
return None;
}
unsafe {
let new_len = self.len() - 1;
self.set_len(new_len);
Some(ptr::read(self.as_ptr().add(new_len)))
}
}

/// Remove the element at `index` and swap the last element into its place.
@@ -565,9 +588,9 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
///
/// assert_eq!(&v[..], &[0, 1, 2]);
/// ```
pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
pub const fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
let len = self.len();
&mut self.xs[len..]
self.xs.split_at_mut(len).1
}

/// Set the vector’s length without dropping or moving out elements
@@ -577,7 +600,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
///
/// This method uses *debug assertions* to check that `length` is
/// not greater than the capacity.
pub unsafe fn set_len(&mut self, length: usize) {
pub const unsafe fn set_len(&mut self, length: usize) {
// type invariant that capacity always fits in LenUint
debug_assert!(length <= self.capacity());
self.len = length as LenUint;
@@ -601,7 +624,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
/// slice.
///
/// [`remaining_capacity`]: #method.remaining_capacity
pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError>
pub const fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError>
where T: Copy,
{
if self.remaining_capacity() < other.len() {
@@ -689,7 +712,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
///
/// Return an `Ok` value with the array if length equals capacity,
/// return an `Err` with self otherwise.
pub fn into_inner(self) -> Result<[T; CAP], Self> {
pub const fn into_inner(self) -> Result<[T; CAP], Self> {
if self.len() < self.capacity() {
Err(self)
} else {
@@ -701,11 +724,11 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
///
/// 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
pub const unsafe fn into_inner_unchecked(self) -> [T; CAP] {
debug_assert!(self.len() == self.capacity());
let ptr = self.as_ptr();
mem::forget(self);
ptr::read(ptr as *const [T; CAP])
}

/// Returns the ArrayVec, replacing the original with a new empty ArrayVec.
@@ -717,49 +740,36 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
/// assert_eq!([0, 1, 2, 3], v.take().into_inner().unwrap());
/// assert!(v.is_empty());
/// ```
pub fn take(&mut self) -> Self {
mem::replace(self, Self::new())
pub const fn take(&mut self) -> Self {
mem::replace(self, Self::new_const())
}

/// Return a slice containing all elements of the vector.
pub fn as_slice(&self) -> &[T] {
ArrayVecImpl::as_slice(self)
pub const fn as_slice(&self) -> &[T] {
let len = self.len();
unsafe {
slice::from_raw_parts(self.as_ptr(), len)
}
}

/// Return a mutable slice containing all elements of the vector.
pub fn as_mut_slice(&mut self) -> &mut [T] {
ArrayVecImpl::as_mut_slice(self)
pub const fn as_mut_slice(&mut self) -> &mut [T] {
let len = self.len();
unsafe {
std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
}
}

/// Return a raw pointer to the vector's buffer.
pub fn as_ptr(&self) -> *const T {
ArrayVecImpl::as_ptr(self)
}

/// Return a raw mutable pointer to the vector's buffer.
pub fn as_mut_ptr(&mut self) -> *mut T {
ArrayVecImpl::as_mut_ptr(self)
}
}

impl<T, const CAP: usize> ArrayVecImpl for ArrayVec<T, CAP> {
type Item = T;
const CAPACITY: usize = CAP;

fn len(&self) -> usize { self.len() }

unsafe fn set_len(&mut self, length: usize) {
debug_assert!(length <= CAP);
self.len = length as LenUint;
}

fn as_ptr(&self) -> *const Self::Item {
pub const fn as_ptr(&self) -> *const T {
self.xs.as_ptr() as _
}

fn as_mut_ptr(&mut self) -> *mut Self::Item {
/// Return a raw mutable pointer to the vector's buffer.
pub const fn as_mut_ptr(&mut self) -> *mut T {
self.xs.as_mut_ptr() as _
}

}

impl<T, const CAP: usize> Deref for ArrayVec<T, CAP> {
@@ -917,13 +927,13 @@ pub struct IntoIter<T, const CAP: usize> {
}
impl<T, const CAP: usize> IntoIter<T, CAP> {
/// Returns the remaining items of this iterator as a slice.
pub fn as_slice(&self) -> &[T] {
&self.v[self.index..]
pub const fn as_slice(&self) -> &[T] {
self.v.as_slice().split_at(self.index).1
}

/// Returns the remaining items of this iterator as a mutable slice.
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.v[self.index..]
pub const fn as_mut_slice(&mut self) -> &mut [T] {
self.v.as_mut_slice().split_at_mut(self.index).1
}
}

@@ -1100,7 +1110,7 @@ impl<T, const CAP: usize> Extend<T> for ArrayVec<T, CAP> {
#[inline(never)]
#[cold]
#[track_caller]
fn extend_panic() {
const fn extend_panic() {
panic!("ArrayVec: capacity exceeded in extend/from_iter");
}

@@ -1161,7 +1171,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
}

/// Rawptr add but uses arithmetic distance for ZST
unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
const unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
if mem::size_of::<T>() == 0 {
// Special case for ZST
ptr.cast::<u8>().wrapping_add(offset).cast::<T>()
87 changes: 0 additions & 87 deletions src/arrayvec_impl.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/char.rs
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ pub struct EncodeUtf8Error;
///
/// Safety: `ptr` must be writable for `len` bytes.
#[inline]
pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result<usize, EncodeUtf8Error>
pub const unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result<usize, EncodeUtf8Error>
{
let code = ch as u32;
if code < MAX_ONE_B && len >= 1 {
3 changes: 1 addition & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
//!
//! ## Rust Version
//!
//! This version of arrayvec requires Rust 1.51 or later.
//! This version of arrayvec requires Rust 1.83 or later.
//!
#![doc(html_root_url="https://docs.rs/arrayvec/0.7/")]
#![cfg_attr(not(feature="std"), no_std)]
@@ -57,7 +57,6 @@ macro_rules! assert_capacity_limit_const {
}
}

mod arrayvec_impl;
mod arrayvec;
mod array_string;
mod char;