Skip to content

Commit

Permalink
simplify SizeError
Browse files Browse the repository at this point in the history
This commit
1. makes `SizeError` struct with one generic field, instead of `enum<T> { Less(usize, T), Greater(usize, T) }`
2. removes `SizeError::{expect,expect_size}` methods
3. changes `Display` output to just "wrong size"

This is done to make API clearer and remove overhead on errors caused by calculating the difference between sizes
  • Loading branch information
WaffleLapkin committed Mar 19, 2020
1 parent 1e5d034 commit 387125e
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 80 deletions.
48 changes: 6 additions & 42 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,11 @@
use core::{
cmp::Ordering,
fmt::{Display, Error, Formatter},
};
use core::fmt::{self, Display, Formatter};

/// Error that represents difference in expected sizes of an array.
#[derive(Debug, PartialEq, Eq)]
pub enum SizeError<T = ()> {
/// Size is less than expected by `.0`
Less(usize, T),
/// Size is greater than expected by `.0`
Greater(usize, T),
}

impl<T> SizeError<T> {
pub(crate) fn expect(x: usize, expected: usize, data: T) -> Result<T, Self> {
match x.cmp(&expected) {
Ordering::Equal => Ok(data),
Ordering::Less => Err(SizeError::Less(expected - x, data)),
Ordering::Greater => Err(SizeError::Greater(x - expected, data)),
}
}

pub(crate) fn expect_size<Item>(slice: &[Item], expected: usize, data: T) -> Result<T, Self> {
Self::expect(slice.len(), expected, data)
}
}
/// Error that is caused by wrong sizes of slices/arrays
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
pub struct SizeError<T = ()>(pub T);

impl<T: Display> Display for SizeError<T> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
match self {
Self::Less(n, data) => write!(
f,
"Size is less than expected by {n}; data: {data}",
n = n,
data = data
),
Self::Greater(n, data) => write!(
f,
"Size is less than expected by {n}; data: {data}",
n = n,
data = data
),
}
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("wrong size")
}
}
31 changes: 19 additions & 12 deletions src/ext/array_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,14 @@ pub trait ArrayExt: Array {
where
A: Array<Item = Self::Item>,
{
let slf = SizeError::expect(Self::SIZE, A::SIZE, self)?;
// ## Safety
//
// Item types and sizes are same for both `Self` and `A`, so it's the same type.
Ok(unsafe { extremely_unsafe_transmute::<Self, A>(slf) })
if Self::SIZE == A::SIZE {
// ## Safety
//
// Item types and sizes are same for both `Self` and `A`, so it's the same type.
Ok(unsafe { extremely_unsafe_transmute::<Self, A>(self) })
} else {
Err(SizeError(self))
}
}

/// Copies `self` into a new `Vec`.
Expand Down Expand Up @@ -201,16 +204,18 @@ pub trait ArrayExt: Array {
/// let slice = &[1, 2, 3, 4];
/// let arr = <[i32; 2]>::from_slice(slice);
/// // ^^^^^^ ---- wrong size, slice len = 4, arr len = 2
/// assert_eq!(arr, Err(SizeError::Greater(2, ())));
/// assert_eq!(arr, Err(SizeError::default()));
/// ```
#[inline]
fn from_slice(slice: &[Self::Item]) -> Result<Self, SizeError>
where
Self::Item: Copy,
{
SizeError::expect_size(slice, Self::SIZE, ())?;

Ok(Self::from_iter(slice.iter().copied()).unwrap())
if slice.len() == Self::SIZE {
Ok(Self::from_iter(slice.iter().copied()).unwrap())
} else {
Err(SizeError::default())
}
}

/// Create array from slice. Return `Err(())` if `slice.len != Self::SIZE`.
Expand All @@ -235,9 +240,11 @@ pub trait ArrayExt: Array {
where
Self::Item: Clone,
{
SizeError::expect_size(slice, Self::SIZE, ())?;

Ok(Self::from_iter(slice.iter().cloned()).unwrap())
if slice.len() == Self::SIZE {
Ok(Self::from_iter(slice.iter().cloned()).unwrap())
} else {
Err(SizeError::default())
}
}

/// Wrap `self` into [`ArrayWrapper`](crate::ArrayWrapper)
Expand Down
8 changes: 4 additions & 4 deletions src/ext/slice_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ pub trait Slice {
///
/// let slice: &[i32] = &[0, 1, 2, 3, 4];
/// let array: [i32; 5] = slice.copied().unwrap();
/// assert_eq!(array, [0, 1, 2, 3, 4])
/// assert_eq!(array, [0, 1, 2, 3, 4]);
/// ```
///
/// ```
/// use arraylib::{SizeError, Slice};
///
/// let slice: &[i32] = &[0, 1, 2, 3, 4];
/// let result = slice.copied::<[i32; 2]>();
/// assert_eq!(result, Err(SizeError::Greater(3, ())))
/// assert_eq!(result, Err(SizeError::default()));
/// ```
fn copied<A>(&self) -> Result<A, SizeError>
where
Expand All @@ -51,7 +51,7 @@ pub trait Slice {
/// // Range is not `Copy`
/// let slice: &[Range<usize>] = &[0..1, 1..3, 2..10];
/// let array: [Range<usize>; 3] = slice.cloned().unwrap();
/// assert_eq!(array, [0..1, 1..3, 2..10])
/// assert_eq!(array, [0..1, 1..3, 2..10]);
/// ```
///
/// ```
Expand All @@ -60,7 +60,7 @@ pub trait Slice {
///
/// let slice: &[Range<usize>] = &[0..1, 1..3, 2..10];
/// let result = slice.cloned::<[Range<usize>; 5]>();
/// assert_eq!(result, Err(SizeError::Less(2, ())))
/// assert_eq!(result, Err(SizeError::default()));
/// ```
fn cloned<A>(&self) -> Result<A, SizeError>
where
Expand Down
51 changes: 29 additions & 22 deletions src/wrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,17 +241,21 @@ where

#[inline]
fn try_from(slice: &'a [A::Item]) -> Result<Self, SizeError> {
unsafe {
SizeError::expect_size(slice, <ArrayWrapper<A>>::SIZE, ())?;

// ## Safety
//
// Slice and array of the same size must have the same ABI, so we can safely get
// `&ArrayWrapper` from `&[A::Item]`.
//
// But we can't transmute slice ref directly to array ref because
// first is fat pointer and second is not.
Ok(&*(slice.as_ptr() as *const ArrayWrapper<A>))
// TODO: >=?
if slice.len() == <ArrayWrapper<A>>::SIZE {
unsafe {

// ## Safety
//
// Slice and array of the same size must have the same ABI, so we can safely get
// `&ArrayWrapper` from `&[A::Item]`.
//
// But we can't transmute slice ref directly to array ref because
// first is fat pointer and second is not.
Ok(&*(slice.as_ptr() as *const ArrayWrapper<A>))
}
} else {
Err(SizeError::default())
}
}
}
Expand All @@ -272,17 +276,20 @@ where

#[inline]
fn try_from(slice: &'a mut [A::Item]) -> Result<Self, SizeError> {
unsafe {
SizeError::expect_size(slice, <ArrayWrapper<A>>::SIZE, ())?;

// ## Safety
//
// Slice and array of the same size must have the same ABI, so we can safely get
// `&mut ArrayWrapper` from `&mut [A::Item]`.
//
// But we can't transmute slice ref directly to array ref because
// first is fat pointer and second is not.
Ok(&mut *(slice.as_mut_ptr() as *mut ArrayWrapper<A>))
// TODO: >=?
if slice.len() == <ArrayWrapper<A>>::SIZE {
unsafe {
// ## Safety
//
// Slice and array of the same size must have the same ABI, so we can safely get
// `&mut ArrayWrapper` from `&mut [A::Item]`.
//
// But we can't transmute slice ref directly to array ref because
// first is fat pointer and second is not.
Ok(&mut *(slice.as_mut_ptr() as *mut ArrayWrapper<A>))
}
} else {
Err(SizeError::default())
}
}
}
Expand Down

0 comments on commit 387125e

Please sign in to comment.