Skip to content
Draft
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
12 changes: 7 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ jobs:
strategy:
matrix:
rust: [
1.91.0, # MSRV
stable,
beta,
# 1.91.0, # MSRV
# stable,
# beta,
nightly,
]
steps:
Expand All @@ -32,7 +32,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
# - uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/rust-toolchain@nightly
with:
# try a target that doesn't have std at all
target: thumbv6m-none-eabi
Expand All @@ -42,7 +43,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
# - uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/rust-toolchain@nightly
with:
components: clippy
- run: cargo clippy --all-features
Expand Down
129 changes: 0 additions & 129 deletions src/bytes.rs

This file was deleted.

5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@

#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![feature(min_generic_const_args)]
#![cfg_attr(test, feature(associated_const_equality))]
#![expect(incomplete_features)]

#[cfg(feature = "std")]
extern crate std;

#[macro_use]
mod macros;

mod bytes;
mod error;
mod float;
mod integer;
Expand All @@ -70,7 +72,6 @@ mod unsigned;
#[cfg(test)]
mod tests;

pub use self::bytes::PrimitiveBytes;
pub use self::error::PrimitiveError;
pub use self::float::{PrimitiveFloat, PrimitiveFloatRef, PrimitiveFloatToInt};
pub use self::integer::{PrimitiveInteger, PrimitiveIntegerRef};
Expand Down
36 changes: 19 additions & 17 deletions src/number.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{PrimitiveBytes, PrimitiveError};
use crate::PrimitiveError;

trait Sealed {}
struct SealedToken;
Expand Down Expand Up @@ -100,30 +100,31 @@ pub trait PrimitiveNumber:
+ for<'a> core::ops::Sub<&'a Self, Output = Self>
+ for<'a> core::ops::SubAssign<&'a Self>
{
/// An array of bytes used by methods like [`from_be_bytes`][Self::from_be_bytes] and
/// [`to_be_bytes`][Self::to_be_bytes]. It is effectively `[u8; size_of::<Self>()]`.
type Bytes: PrimitiveBytes;
/// The number of bytes used by methods like [`from_be_bytes`][Self::from_be_bytes] and
/// [`to_be_bytes`][Self::to_be_bytes]. It is effectively `size_of::<Self>()`.
#[type_const]
const BYTES: usize;

/// Creates a number from its representation as a byte array in big endian.
fn from_be_bytes(bytes: Self::Bytes) -> Self;
fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self;

/// Creates a number from its representation as a byte array in little endian.
fn from_le_bytes(bytes: Self::Bytes) -> Self;
fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self;

/// Creates a number from its representation as a byte array in native endian.
fn from_ne_bytes(bytes: Self::Bytes) -> Self;
fn from_ne_bytes(bytes: [u8; Self::BYTES]) -> Self;

/// Calculates the midpoint (average) between `self` and `other`.
fn midpoint(self, other: Self) -> Self;

/// Returns the memory representation of this number as a byte array in little-endian order.
fn to_be_bytes(self) -> Self::Bytes;
fn to_be_bytes(self) -> [u8; Self::BYTES];

/// Returns the memory representation of this number as a byte array in big-endian order.
fn to_le_bytes(self) -> Self::Bytes;
fn to_le_bytes(self) -> [u8; Self::BYTES];

/// Returns the memory representation of this number as a byte array in native-endian order.
fn to_ne_bytes(self) -> Self::Bytes;
fn to_ne_bytes(self) -> [u8; Self::BYTES];

/// Creates a number using a type cast, `value as Self`.
///
Expand Down Expand Up @@ -251,18 +252,19 @@ macro_rules! impl_primitive {
impl Sealed for &$Number {}

impl PrimitiveNumber for $Number {
type Bytes = [u8; size_of::<Self>()];
#[type_const]
const BYTES: usize = const { size_of::<Self>() };

forward! {
fn from_be_bytes(bytes: Self::Bytes) -> Self;
fn from_le_bytes(bytes: Self::Bytes) -> Self;
fn from_ne_bytes(bytes: Self::Bytes) -> Self;
fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self;
fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self;
fn from_ne_bytes(bytes: [u8; Self::BYTES]) -> Self;
}
forward! {
fn midpoint(self, other: Self) -> Self;
fn to_be_bytes(self) -> Self::Bytes;
fn to_le_bytes(self) -> Self::Bytes;
fn to_ne_bytes(self) -> Self::Bytes;
fn to_be_bytes(self) -> [u8; Self::BYTES];
fn to_le_bytes(self) -> [u8; Self::BYTES];
fn to_ne_bytes(self) -> [u8; Self::BYTES];
}
}

Expand Down
40 changes: 40 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,43 @@ fn try_into() {
}
check(0i32, 0u32);
}

// The following tests use `#![feature(min_generic_const_args)]`

#[test]
fn bytes1() {
// Return a value with the most significant bit set
fn msb<T: PrimitiveNumber>() -> T {
let mut bytes = [0; T::BYTES];
bytes[0] = 0x80;
T::from_be_bytes(bytes)
}

assert_eq!(msb::<i64>(), i64::MIN);
assert_eq!(msb::<u16>(), 1u16 << 15);
assert!(msb::<f64>().total_cmp(&-0.0).is_eq());
}

#[test]
fn bytes2() {
// Return a value with all bits set
fn all_ones<T: PrimitiveNumber>() -> T {
T::from_ne_bytes(core::array::repeat(0xff))
}

assert_eq!(all_ones::<i32>(), -1);
assert_eq!(all_ones::<usize>(), usize::MAX);
assert!(all_ones::<f64>().is_nan());
}

#[test]
fn bytes3() {
// This also needs `#![feature(associated_const_equality)]`
fn rust<T: PrimitiveNumber<BYTES = 4>>() -> T {
T::from_be_bytes(*b"Rust")
}

assert_eq!(rust::<i32>(), 0x52_75_73_74_i32);
assert_eq!(rust::<u32>(), 0x52_75_73_74_u32);
assert_eq!(rust::<f32>(), 2.63551e11);
}
Loading