Skip to content

Commit

Permalink
Introduce NonMaxU32 type
Browse files Browse the repository at this point in the history
  • Loading branch information
CYBAI committed Jun 19, 2022
1 parent 80e804c commit 453a9ec
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 0 deletions.
1 change: 1 addition & 0 deletions boa_engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub mod class;
pub mod context;
pub mod environments;
pub mod job;
pub mod nonmaxu32;
pub mod object;
pub mod property;
pub mod realm;
Expand Down
179 changes: 179 additions & 0 deletions boa_engine/src/nonmaxu32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//! This module implements `NonMaxU32`
//! which is known not to equal u32::MAX.
//!
//! This would be useful for integers like https://tc39.es/ecma262/#array-index.
use boa_gc::{unsafe_empty_trace, Finalize, Trace};
use std::fmt;
use std::ops::{BitOr, BitOrAssign};

/// An integer that is known not to equal u32::MAX.
///
/// This enables some memory layout optimization.
/// For example, `Option<NonMaxU32>` is the same size as `u32`:
///
/// ```rust
/// use std::mem::size_of;
/// assert_eq!(size_of::<Option<NonMaxU32>>(), size_of::<u32>());
/// ```
#[derive(Copy, Clone, Eq, Finalize, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct NonMaxU32(u32);

// Safety: NonMaxU32 does not contain any objects which needs to be traced,
// so this is safe.
unsafe impl Trace for NonMaxU32 {
unsafe_empty_trace!();
}

/// An error type returned when a checked integral type conversion fails (mimics [std::num::TryFromIntError])
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TryFromIntError(());

impl fmt::Display for TryFromIntError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
"out of range integral type conversion attempted".fmt(fmt)
}
}

impl From<core::num::TryFromIntError> for TryFromIntError {
fn from(_: core::num::TryFromIntError) -> Self {
Self(())
}
}

impl From<core::convert::Infallible> for TryFromIntError {
fn from(never: core::convert::Infallible) -> Self {
match never {}
}
}

/// An error type returned when an integer cannot be parsed (mimics [std::num::ParseIntError])
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ParseIntError(());

impl fmt::Display for ParseIntError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
"unable to parse integer".fmt(fmt)
}
}

impl From<core::num::ParseIntError> for ParseIntError {
fn from(_: core::num::ParseIntError) -> Self {
Self(())
}
}

impl NonMaxU32 {
/// Creates a non-u32-max without checking the value.
///
/// # Safety
///
/// The value must not be `u32::MAX`.
#[inline]
pub const unsafe fn new_unchecked(n: u32) -> Self {
// SAFETY: this is guaranteed to be safe by the caller.
Self(n)
}

/// Creates a non-u32-max if the given value is not `u32::MAX`.
#[inline]
pub const fn new(n: u32) -> Option<Self> {
if n != u32::MAX {
// SAFETY: we just checked that there's no `u32::MAX`
Some(Self(n))
} else {
None
}
}

/// Returns the value as a primitive type.
#[inline]
pub const fn get(self) -> u32 {
self.0
}
}

impl TryFrom<u32> for NonMaxU32 {
type Error = TryFromIntError;

fn try_from(value: u32) -> Result<Self, Self::Error> {
Self::new(value).ok_or(TryFromIntError(()))
}
}

impl From<NonMaxU32> for u32 {
/// Converts a `NonMaxU32` into an `u32`
fn from(nonzero: NonMaxU32) -> Self {
nonzero.0
}
}

impl core::str::FromStr for NonMaxU32 {
type Err = ParseIntError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Self::new(u32::from_str(value)?).ok_or(ParseIntError(()))
}
}

impl BitOr for NonMaxU32 {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
// Safety: since `self` and `rhs` are both nonzero, the
// result of the bitwise-or will be nonzero.
unsafe { NonMaxU32::new_unchecked(self.get() | rhs.get()) }
}
}

impl BitOr<u32> for NonMaxU32 {
type Output = Self;

#[inline]
fn bitor(self, rhs: u32) -> Self::Output {
// Safety: since `self` is nonzero, the result of the
// bitwise-or will be nonzero regardless of the value of
// `rhs`.
unsafe { NonMaxU32::new_unchecked(self.get() | rhs) }
}
}

impl BitOr<NonMaxU32> for u32 {
type Output = NonMaxU32;

#[inline]
fn bitor(self, rhs: NonMaxU32) -> Self::Output {
// Safety: since `rhs` is nonzero, the result of the
// bitwise-or will be nonzero regardless of the value of
// `self`.
unsafe { NonMaxU32::new_unchecked(self | rhs.get()) }
}
}

impl BitOrAssign for NonMaxU32 {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
}

impl BitOrAssign<u32> for NonMaxU32 {
#[inline]
fn bitor_assign(&mut self, rhs: u32) {
*self = *self | rhs;
}
}

impl fmt::Debug for NonMaxU32 {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get().fmt(f)
}
}

impl fmt::Display for NonMaxU32 {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get().fmt(f)
}
}

0 comments on commit 453a9ec

Please sign in to comment.