diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a390ff5..657917e 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,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:
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/"
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<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,10 +445,7 @@ 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()
     }
 }
 
@@ -444,11 +453,7 @@ 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()
     }
 }
 
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<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>()
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<Self::Item>> {
-        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<Self::Item> {
-        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<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 {
diff --git a/src/lib.rs b/src/lib.rs
index 5c4bcee..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)]
@@ -57,7 +57,6 @@ macro_rules! assert_capacity_limit_const {
     }
 }
 
-mod arrayvec_impl;
 mod arrayvec;
 mod array_string;
 mod char;