From 30d4c15dba5ec61aa96807353f37dd53e7668c77 Mon Sep 17 00:00:00 2001 From: Daniel Bloom Date: Sun, 23 Feb 2025 02:17:01 -0800 Subject: [PATCH 1/7] feat+refactor: Maximize `const` --- src/array_string.rs | 61 +++++++++++---------- src/arrayvec.rs | 124 +++++++++++++++++++++++-------------------- src/arrayvec_impl.rs | 87 ------------------------------ src/char.rs | 2 +- src/lib.rs | 1 - 5 files changed, 101 insertions(+), 174 deletions(-) delete mode 100644 src/arrayvec_impl.rs diff --git a/src/array_string.rs b/src/array_string.rs index 227e01d..c49e321 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -62,7 +62,7 @@ impl ArrayString /// assert_eq!(&string[..], "foo"); /// assert_eq!(string.capacity(), 16); /// ``` - pub fn new() -> ArrayString { + pub const fn new() -> ArrayString { assert_capacity_limit!(CAP); unsafe { ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 } @@ -105,10 +105,12 @@ impl ArrayString /// assert_eq!(string.len(), 3); /// assert_eq!(string.capacity(), 3); /// ``` - pub fn from(s: &str) -> Result> { + pub const fn from(s: &str) -> Result> { 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 ArrayString /// /// let string = ArrayString::from_byte_string(b"hello world").unwrap(); /// ``` - pub fn from_byte_string(b: &[u8; CAP]) -> Result { - let len = str::from_utf8(b)?.len(); - debug_assert_eq!(len, CAP); + pub const fn from_byte_string(b: &[u8; CAP]) -> Result { + 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; CAP]) @@ -142,7 +147,7 @@ impl ArrayString /// 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 ArrayString /// assert_eq!(&string[..], "ab"); /// assert_eq!(overflow.unwrap_err().element(), 'c'); /// ``` - pub fn try_push(&mut self, c: char) -> Result<(), CapacityError> { + pub const fn try_push(&mut self, c: char) -> Result<(), CapacityError> { let len = self.len(); unsafe { let ptr = self.as_mut_ptr().add(len); @@ -281,7 +286,7 @@ impl ArrayString /// 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 ArrayString /// ``` 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 ArrayString } /// 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 ArrayString /// /// 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,10 +445,7 @@ impl Deref for ArrayString 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() } } @@ -444,11 +453,7 @@ impl DerefMut for ArrayString { #[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() } } diff --git a/src/arrayvec.rs b/src/arrayvec.rs index e5ea52d..7bd95b4 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -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 ArrayVec { /// ``` #[inline] #[track_caller] - pub fn new() -> ArrayVec { + pub const fn new() -> ArrayVec { assert_capacity_limit!(CAP); unsafe { ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 } @@ -177,7 +176,7 @@ impl ArrayVec { /// ``` #[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 ArrayVec { /// /// assert!(overflow.is_err()); /// ``` - pub fn try_push(&mut self, element: T) -> Result<(), CapacityError> { - ArrayVecImpl::try_push(self, element) + pub const fn try_push(&mut self, element: T) -> Result<(), CapacityError> { + 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 ArrayVec { /// /// 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 ArrayVec { /// 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 ArrayVec { /// assert_eq!(array.pop(), Some(1)); /// assert_eq!(array.pop(), None); /// ``` - pub fn pop(&mut self) -> Option { - ArrayVecImpl::pop(self) + pub const fn pop(&mut self) -> Option { + 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 ArrayVec { /// /// assert_eq!(&v[..], &[0, 1, 2]); /// ``` - pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { + pub const fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { 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 ArrayVec { /// /// 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 ArrayVec { /// 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 ArrayVec { /// /// 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 ArrayVec { /// /// 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 ArrayVec { /// 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 ArrayVecImpl for ArrayVec { - 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 Deref for ArrayVec { @@ -917,13 +927,13 @@ pub struct IntoIter { } impl IntoIter { /// 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 Extend for ArrayVec { #[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 ArrayVec { } /// Rawptr add but uses arithmetic distance for ZST -unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { +const unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { if mem::size_of::() == 0 { // Special case for ZST ptr.cast::().wrapping_add(offset).cast::() diff --git a/src/arrayvec_impl.rs b/src/arrayvec_impl.rs deleted file mode 100644 index c5ebe7b..0000000 --- a/src/arrayvec_impl.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::ptr; -use std::slice; - -use crate::CapacityError; - -/// Implements basic arrayvec methods - based on a few required methods -/// for length and element access. -pub(crate) trait ArrayVecImpl { - type Item; - const CAPACITY: usize; - - fn len(&self) -> usize; - - unsafe fn set_len(&mut self, new_len: usize); - - /// Return a slice containing all elements of the vector. - fn as_slice(&self) -> &[Self::Item] { - let len = self.len(); - unsafe { - slice::from_raw_parts(self.as_ptr(), len) - } - } - - /// Return a mutable slice containing all elements of the vector. - fn as_mut_slice(&mut self) -> &mut [Self::Item] { - 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. - fn as_ptr(&self) -> *const Self::Item; - - /// Return a raw mutable pointer to the vector's buffer. - fn as_mut_ptr(&mut self) -> *mut Self::Item; - - #[track_caller] - fn push(&mut self, element: Self::Item) { - self.try_push(element).unwrap() - } - - fn try_push(&mut self, element: Self::Item) -> Result<(), CapacityError> { - if self.len() < Self::CAPACITY { - unsafe { - self.push_unchecked(element); - } - Ok(()) - } else { - Err(CapacityError::new(element)) - } - } - - unsafe fn push_unchecked(&mut self, element: Self::Item) { - let len = self.len(); - debug_assert!(len < Self::CAPACITY); - ptr::write(self.as_mut_ptr().add(len), element); - self.set_len(len + 1); - } - - fn pop(&mut self) -> Option { - 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))) - } - } - - fn clear(&mut self) { - self.truncate(0) - } - - fn truncate(&mut self, new_len: usize) { - 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); - } - } - } -} - diff --git a/src/char.rs b/src/char.rs index 939b6b4..87eab23 100644 --- a/src/char.rs +++ b/src/char.rs @@ -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 +pub const unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result { let code = ch as u32; if code < MAX_ONE_B && len >= 1 { diff --git a/src/lib.rs b/src/lib.rs index 5c4bcee..7300319 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,6 @@ macro_rules! assert_capacity_limit_const { } } -mod arrayvec_impl; mod arrayvec; mod array_string; mod char; From 52b3b1843bf7e9c5f62d8630ecc34f581aeecca0 Mon Sep 17 00:00:00 2001 From: Daniel Bloom Date: Sun, 23 Feb 2025 02:32:29 -0800 Subject: [PATCH 2/7] bump msrv --- .github/workflows/ci.yml | 11 +++++------ src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a390ff5..8d789cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,8 @@ on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] name: Continuous integration @@ -17,12 +17,12 @@ 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.84.0 features: serde experimental: false - rust: stable @@ -42,7 +42,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 +80,6 @@ jobs: run: | cargo rustc "--target=${{ matrix.target }}" --no-default-features --features "${{ matrix.features }}" - miri: runs-on: ubuntu-latest steps: diff --git a/src/lib.rs b/src/lib.rs index 7300319..5ab12c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)] From a074b5c0333da60e169bed5daf2d00cbc351fc3c Mon Sep 17 00:00:00 2001 From: Daniel Bloom Date: Sun, 23 Feb 2025 02:34:07 -0800 Subject: [PATCH 3/7] bump --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d789cf..8cb8188 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: experimental: false # doctest of `ArrayVec::spare_capacity_mut` has MSRV 1.55 test-args: --skip spare_capacity_mut - - rust: 1.84.0 + - rust: 1.85.0 features: serde experimental: false - rust: stable From e2ea8679140da95f498fc0de165c33922db09490 Mon Sep 17 00:00:00 2001 From: Daniel Bloom Date: Sun, 23 Feb 2025 02:35:06 -0800 Subject: [PATCH 4/7] remove skip --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cb8188..657917e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,8 +20,6 @@ jobs: - 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.85.0 features: serde experimental: false From e3caaa3f25de54e258b4859da8610b044534b324 Mon Sep 17 00:00:00 2001 From: Daniel Bloom Date: Mon, 24 Feb 2025 14:03:45 -0800 Subject: [PATCH 5/7] cargo toml version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 13917b0..2d157dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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/" From 49e19df5ce3919beeacf52d5ee484e03a9a8408f Mon Sep 17 00:00:00 2001 From: Daniel Bloom <7810950-Daniel.Aaron.Bloom@users.noreply.gitlab.com> Date: Thu, 27 Mar 2025 16:53:49 -0700 Subject: [PATCH 6/7] Minimize msrv using a feature controlled macro --- .github/workflows/ci.yml | 19 +++++++------- Cargo.toml | 5 ++-- src/array_string.rs | 35 +++++++++++++++++--------- src/arrayvec.rs | 53 ++++++++++++++++++++++++++-------------- src/char.rs | 4 +-- src/lib.rs | 20 ++++++++++++++- 6 files changed, 93 insertions(+), 43 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 657917e..a239a41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,8 @@ on: push: - branches: [master] + branches: [ master ] pull_request: - branches: [master] + branches: [ master ] name: Continuous integration @@ -17,21 +17,21 @@ jobs: strategy: matrix: include: - - rust: 1.83.0 # MSRV + - rust: 1.57.0 # MSRV features: serde experimental: false - - rust: 1.85.0 - features: serde + - rust: 1.70.0 + features: serde, const experimental: false - rust: stable - features: + features: const bench: true experimental: false - rust: beta - features: serde + features: serde, const experimental: false - rust: nightly - features: serde, borsh, zeroize + features: serde, borsh, zeroize, const experimental: false steps: @@ -40,7 +40,7 @@ jobs: with: toolchain: ${{ matrix.rust }} - name: Pin versions for MSRV - if: "${{ matrix.rust == '1.83.0' }}" + if: "${{ matrix.rust == '1.57.0' }}" run: | cargo update -p serde_test --precise 1.0.163 cargo update -p serde --precise 1.0.69 @@ -78,6 +78,7 @@ jobs: run: | cargo rustc "--target=${{ matrix.target }}" --no-default-features --features "${{ matrix.features }}" + miri: runs-on: ubuntu-latest steps: diff --git a/Cargo.toml b/Cargo.toml index 2d157dc..bdfe19f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.7.6" authors = ["bluss"] license = "MIT OR Apache-2.0" edition = "2018" -rust-version = "1.83" +rust-version = "1.57" 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/" @@ -48,6 +48,7 @@ harness = false [features] default = ["std"] std = [] +const = [] [profile.bench] debug = true @@ -55,7 +56,7 @@ debug = true debug = true [package.metadata.docs.rs] -features = ["borsh", "serde", "zeroize"] +features = ["borsh", "serde", "zeroize", "const"] [package.metadata.release] no-dev-version = true diff --git a/src/array_string.rs b/src/array_string.rs index c49e321..41963a3 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -17,6 +17,7 @@ use crate::CapacityError; use crate::LenUint; use crate::char::encode_utf8; use crate::utils::MakeMaybeUninit; +use crate::const_fn; #[cfg(feature="serde")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; @@ -50,6 +51,8 @@ impl Default for ArrayString impl ArrayString { + + const_fn!{ /// Create a new empty `ArrayString`. /// /// Capacity is inferred from the type parameter. @@ -67,7 +70,7 @@ impl ArrayString unsafe { ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 } } - } + }} /// Create a new empty `ArrayString` (const fn). /// @@ -91,6 +94,7 @@ impl ArrayString #[inline] pub const fn is_empty(&self) -> bool { self.len() == 0 } + const_fn!{ /// Create a new `ArrayString` from a `str`. /// /// Capacity is inferred from the type parameter. @@ -111,8 +115,9 @@ impl ArrayString Ok(()) => Ok(arraystr), Err(e) => Err(e), } - } + }} + const_fn!{ /// Create a new `ArrayString` from a byte string literal. /// /// **Errors** if the byte string literal is not valid UTF-8. @@ -135,8 +140,9 @@ impl ArrayString vec.set_len(CAP); } Ok(vec) - } + }} + const_fn!{ /// Create a new `ArrayString` value fully filled with ASCII NULL characters (`\0`). Useful /// to be used as a buffer to collect external data or as a buffer for intermediate processing. /// @@ -157,7 +163,7 @@ impl ArrayString len: CAP as _ } } - } + }} /// Return the capacity of the `ArrayString`. /// @@ -214,6 +220,7 @@ impl ArrayString self.try_push(c).unwrap(); } + const_fn!{ /// Adds the given char to the end of the string. /// /// Returns `Ok` if the push succeeds. @@ -245,7 +252,7 @@ impl ArrayString Err(_) => Err(CapacityError::new(c)), } } - } + }} /// Adds the given string slice to the end of the string. /// @@ -266,6 +273,7 @@ impl ArrayString self.try_push_str(s).unwrap() } + const_fn!{ /// Adds the given string slice to the end of the string. /// /// Returns `Ok` if the push succeeds. @@ -298,7 +306,7 @@ impl ArrayString self.set_len(newl); } Ok(()) - } + }} /// Removes the last character from the string and returns it. /// @@ -392,13 +400,15 @@ impl ArrayString ch } + const_fn!{ /// Make the string empty. pub const fn clear(&mut self) { unsafe { self.set_len(0); } - } + }} + const_fn!{ /// Set the strings’s length. /// /// This function is `unsafe` because it changes the notion of the @@ -410,16 +420,18 @@ impl ArrayString // type invariant that capacity always fits in LenUint debug_assert!(length <= self.capacity()); self.len = length as LenUint; - } + }} + const_fn!{ /// Return a string slice of the whole `ArrayString`. pub const fn as_str(&self) -> &str { unsafe { let sl = slice::from_raw_parts(self.as_ptr(), self.len()); str::from_utf8_unchecked(sl) } - } + }} + const_fn!{ /// Return a mutable string slice of the whole `ArrayString`. pub const fn as_mut_str(&mut self) -> &mut str { unsafe { @@ -427,17 +439,18 @@ impl ArrayString 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 const fn as_ptr(&self) -> *const u8 { self.xs.as_ptr() as *const u8 } + const_fn!{ /// Return a raw mutable pointer to the string's buffer. pub const fn as_mut_ptr(&mut self) -> *mut u8 { self.xs.as_mut_ptr() as *mut u8 - } + }} } impl Deref for ArrayString diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 7bd95b4..eb9086c 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -23,6 +23,7 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer}; use crate::LenUint; use crate::errors::CapacityError; use crate::utils::MakeMaybeUninit; +use crate::const_fn; /// A vector with a fixed capacity. /// @@ -64,6 +65,7 @@ impl ArrayVec { /// Capacity const CAPACITY: usize = CAP; + const_fn!{ /// Create a new empty `ArrayVec`. /// /// The maximum capacity is given by the generic parameter `CAP`. @@ -84,7 +86,7 @@ impl ArrayVec { unsafe { ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 } } - } + }} /// Create a new empty `ArrayVec` (const fn). /// @@ -179,6 +181,7 @@ impl ArrayVec { self.try_push(element).unwrap() } + const_fn!{ /// Push `element` to the end of the vector. /// /// Return `Ok` if the push succeeds, or return an error if the vector @@ -210,8 +213,9 @@ impl ArrayVec { } else { Err(CapacityError::new(element)) } - } + }} + const_fn!{ /// Push `element` to the end of the vector without checking the capacity. /// /// It is up to the caller to ensure the capacity of the vector is @@ -238,7 +242,7 @@ impl ArrayVec { 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 /// the rest. @@ -272,10 +276,11 @@ impl ArrayVec { } + const_fn!{ /// Get pointer to where element at `index` would be const unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut T { self.as_mut_ptr().add(index) - } + }} /// Insert `element` at position `index`. /// @@ -348,6 +353,7 @@ impl ArrayVec { Ok(()) } + const_fn!{ /// Remove the last element in the vector and return it. /// /// Return `Some(` *element* `)` if the vector is non-empty, else `None`. @@ -371,7 +377,7 @@ impl ArrayVec { 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. /// @@ -558,6 +564,7 @@ impl ArrayVec { drop(g); } + const_fn!{ /// Returns the remaining spare capacity of the vector as a slice of /// `MaybeUninit`. /// @@ -591,8 +598,9 @@ impl ArrayVec { pub const fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { let len = self.len(); self.xs.split_at_mut(len).1 - } + }} + const_fn!{ /// Set the vector’s length without dropping or moving out elements /// /// This method is `unsafe` because it changes the notion of the @@ -604,8 +612,9 @@ impl ArrayVec { // type invariant that capacity always fits in LenUint debug_assert!(length <= self.capacity()); self.len = length as LenUint; - } + }} + const_fn!{ /// Copy all elements from the slice and append to the `ArrayVec`. /// /// ``` @@ -640,7 +649,7 @@ impl ArrayVec { self.set_len(self_len + other_len); } Ok(()) - } + }} /// Create a draining iterator that removes the specified range in the vector /// and yields the removed items from start to end. The element range is @@ -708,6 +717,7 @@ impl ArrayVec { } } + const_fn!{ /// Return the inner fixed size array, if it is full to its capacity. /// /// Return an `Ok` value with the array if length equals capacity, @@ -718,8 +728,9 @@ impl ArrayVec { } else { unsafe { Ok(self.into_inner_unchecked()) } } - } + }} + const_fn!{ /// Return the inner fixed size array. /// /// Safety: @@ -729,8 +740,9 @@ impl ArrayVec { let ptr = self.as_ptr(); mem::forget(self); ptr::read(ptr as *const [T; CAP]) - } + }} + const_fn!{ /// Returns the ArrayVec, replacing the original with a new empty ArrayVec. /// /// ``` @@ -742,34 +754,36 @@ impl ArrayVec { /// ``` pub const fn take(&mut self) -> Self { mem::replace(self, Self::new_const()) - } + }} + const_fn!{ /// Return a slice containing all elements of the vector. pub const fn as_slice(&self) -> &[T] { let len = self.len(); unsafe { slice::from_raw_parts(self.as_ptr(), len) } - } + }} + const_fn!{ /// Return a mutable slice containing all elements of the vector. 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 const fn as_ptr(&self) -> *const T { self.xs.as_ptr() as _ } + const_fn!{ /// 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 Deref for ArrayVec { @@ -926,15 +940,17 @@ pub struct IntoIter { v: ArrayVec, } impl IntoIter { + const_fn!{ /// Returns the remaining items of this iterator as a slice. pub const fn as_slice(&self) -> &[T] { self.v.as_slice().split_at(self.index).1 - } + }} + const_fn!{ /// Returns the remaining items of this iterator as a mutable slice. pub const fn as_mut_slice(&mut self) -> &mut [T] { self.v.as_mut_slice().split_at_mut(self.index).1 - } + }} } impl Iterator for IntoIter { @@ -1170,6 +1186,7 @@ impl ArrayVec { } } +const_fn!{ /// Rawptr add but uses arithmetic distance for ZST const unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { if mem::size_of::() == 0 { @@ -1178,7 +1195,7 @@ const unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { } else { ptr.add(offset) } -} +}} /// Create an `ArrayVec` from an iterator. /// diff --git a/src/char.rs b/src/char.rs index 87eab23..8969eec 100644 --- a/src/char.rs +++ b/src/char.rs @@ -22,6 +22,7 @@ const MAX_THREE_B: u32 = 0x10000; /// Placeholder pub struct EncodeUtf8Error; +crate::const_fn!{ /// Encode a char into buf using UTF-8. /// /// On success, return the byte length of the encoding (1, 2, 3 or 4).
@@ -52,7 +53,7 @@ pub const unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result { + $(#[$($metas)*])* + $v $($t)+ + }; +} + +#[cfg(feature = "const")] +macro_rules! const_fn { + ($(#[$($metas:meta)*])* $v:vis const $($t:tt)+) => { + $(#[$($metas)*])* + $v const $($t)+ + }; +} + +pub(crate) use const_fn; From a41f13823c91ce6a928cfbeac987a31a6286eaf9 Mon Sep 17 00:00:00 2001 From: Daniel Bloom <7810950-Daniel.Aaron.Bloom@users.noreply.gitlab.com> Date: Thu, 27 Mar 2025 16:56:23 -0700 Subject: [PATCH 7/7] disable const in 1.70 matrix --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a239a41..e8a01e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: features: serde experimental: false - rust: 1.70.0 - features: serde, const + features: serde experimental: false - rust: stable features: const