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

Undo NonZero length optimisation to fix ZST usage #5

Merged
merged 2 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
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
42 changes: 6 additions & 36 deletions src/array.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
use core::{fmt::Debug, hash::Hash, mem::ManuallyDrop, ptr::NonNull};

use crate::length::{InvalidLength, NonZero, SmallLen, ValidLength};
use crate::length::{InvalidLength, SmallLen, ValidLength};

#[cold]
fn truncate_vec<T>(err: InvalidLength<T>, max_len: usize) -> Vec<T> {
Expand All @@ -16,7 +16,7 @@ fn truncate_vec<T>(err: InvalidLength<T>, max_len: usize) -> Vec<T> {
#[repr(packed)]
pub struct FixedArray<T, LenT: ValidLength = SmallLen> {
ptr: NonNull<T>,
len: LenT::NonZero,
len: LenT,
}

impl<T, LenT: ValidLength> FixedArray<T, LenT> {
Expand All @@ -31,34 +31,14 @@ impl<T, LenT: ValidLength> FixedArray<T, LenT> {
pub fn empty() -> Self {
Self {
ptr: NonNull::dangling(),
len: LenT::DANGLING,
len: LenT::ZERO,
}
}

/// # Safety
/// - `len` must be equal to `ptr.len()`
unsafe fn from_box(ptr: Box<[T]>, len: LenT) -> Self {
let len = LenT::NonZero::new(len).unwrap_or(LenT::DANGLING);

// If the length was 0, the above `unwrap_or` has just set the value to `LenT::DANGLING`.
// If the length was not 0, the invariant is held by the caller.
Self::from_box_with_nonzero(ptr, len)
}

/// # Safety
/// If the slice is empty:
/// - `len` must be equal to `LenT::DANGLING`
///
/// If the slice is not empty:
/// - `len` must be equal to `ptr.len()`
#[must_use]
unsafe fn from_box_with_nonzero(ptr: Box<[T]>, len: LenT::NonZero) -> Self {
#[cfg(debug_assertions)]
if ptr.is_empty() {
assert_eq!(len, LenT::DANGLING);
} else {
assert_eq!(len.into().to_usize(), ptr.len());
}
debug_assert_eq!(len.into().to_usize(), ptr.len());

let array_ptr = Box::into_raw(ptr).cast::<T>();
Self {
Expand All @@ -79,11 +59,7 @@ impl<T, LenT: ValidLength> FixedArray<T, LenT> {
/// Returns the length of the [`FixedArray`].
#[must_use]
pub fn len(&self) -> LenT {
if self.is_empty() {
LenT::ZERO
} else {
self.len.into()
}
self.len
}

/// Returns if the length is equal to 0.
Expand Down Expand Up @@ -165,7 +141,7 @@ impl<T: Clone, LenT: ValidLength> Clone for FixedArray<T, LenT> {
let ptr = self.as_slice().to_vec().into_boxed_slice();

// SAFETY: The Box::from cannot make the length mismatch.
unsafe { Self::from_box_with_nonzero(ptr, self.len) }
unsafe { Self::from_box(ptr, self.len) }
}

#[allow(clippy::assigning_clones)]
Expand Down Expand Up @@ -198,12 +174,6 @@ impl<T: Hash, LenT: ValidLength> Hash for FixedArray<T, LenT> {
}

impl<T: PartialEq, LenT: ValidLength> PartialEq for FixedArray<T, LenT> {
// https://github.com/rust-lang/rust-clippy/issues/12154
#[allow(
unknown_lints,
unconditional_recursion,
clippy::unconditional_recursion
)]
fn eq(&self, other: &Self) -> bool {
self.as_slice().eq(other.as_slice())
}
Expand Down
7 changes: 7 additions & 0 deletions src/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl TryFrom<InvalidLength<u8>> for InvalidStrLength {
pub trait NonZero<Int: ValidLength>:
sealed::NonZeroSealed + Into<Int> + Sized + Copy + PartialEq + Debug
{
#[allow(unused)]
fn new(val: Int) -> Option<Self>;
}

Expand Down Expand Up @@ -138,8 +139,11 @@ pub trait ValidLength:
{
const ZERO: Self;
const MAX: Self;
#[deprecated = "will be removed in the next major release"]
#[allow(deprecated)]
const DANGLING: Self::NonZero;

#[deprecated = "will be removed in the next major release"]
type NonZero: NonZero<Self>;
#[cfg(feature = "typesize")]
type InlineStrRepr: Copy + AsRef<[u8]> + AsMut<[u8]> + Default + typesize::TypeSize;
Expand All @@ -158,6 +162,7 @@ pub trait ValidLength:
impl ValidLength for u8 {
const ZERO: Self = 0;
const MAX: Self = Self::MAX;
#[allow(deprecated)]
const DANGLING: Self::NonZero = Self::NonZero::MAX;

type NonZero = NonZeroU8;
Expand All @@ -171,6 +176,7 @@ impl ValidLength for u8 {
impl ValidLength for u16 {
const ZERO: Self = 0;
const MAX: Self = Self::MAX;
#[allow(deprecated)]
const DANGLING: Self::NonZero = Self::NonZero::MAX;

type NonZero = NonZeroU16;
Expand All @@ -185,6 +191,7 @@ impl ValidLength for u16 {
impl ValidLength for u32 {
const ZERO: Self = 0;
const MAX: Self = Self::MAX;
#[allow(deprecated)]
const DANGLING: Self::NonZero = Self::NonZero::MAX;

type NonZero = NonZeroU32;
Expand Down
7 changes: 7 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use small_fixed_array::FixedArray;

#[test]
fn check_zst_functionality() {
let array = FixedArray::<(), u32>::from_vec_trunc(vec![(); 16]);
assert_eq!(array.len(), 16);
}
Loading