Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/Cargo.lock
/target
7 changes: 0 additions & 7 deletions Cargo.lock

This file was deleted.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "num-primitive"
version = "0.1.1"
version = "0.2.0"
description = "Traits for primitive numeric types"
repository = "https://github.com/rust-num/num-primitive"
license = "MIT OR Apache-2.0"
Expand Down
54 changes: 52 additions & 2 deletions src/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,22 @@ struct SealedToken;
/// assert_eq!(distance_squared::<f64>(&[0., 1., 2.], &[1., 3., 0.]), 9.);
/// ```
pub trait PrimitiveFloat:
PrimitiveNumber + From<i8> + From<u8> + core::ops::Neg<Output = Self>
PrimitiveNumber
+ PrimitiveFloatToInt<i8>
+ PrimitiveFloatToInt<i16>
+ PrimitiveFloatToInt<i32>
+ PrimitiveFloatToInt<i64>
+ PrimitiveFloatToInt<i128>
+ PrimitiveFloatToInt<isize>
+ PrimitiveFloatToInt<u8>
+ PrimitiveFloatToInt<u16>
+ PrimitiveFloatToInt<u32>
+ PrimitiveFloatToInt<u64>
+ PrimitiveFloatToInt<u128>
+ PrimitiveFloatToInt<usize>
+ core::convert::From<i8>
+ core::convert::From<u8>
+ core::ops::Neg<Output = Self>
{
/// Approximate number of significant digits in base 10.
const DIGITS: u32;
Expand Down Expand Up @@ -405,7 +420,42 @@ pub trait PrimitiveFloatRef<T>: PrimitiveNumberRef<T> + core::ops::Neg<Output =
///
/// This is effectively the same as the unstable [`core::convert::FloatToInt`], implemented for all
/// combinations of [`PrimitiveFloat`] and [`PrimitiveInteger`][crate::PrimitiveInteger].
pub trait PrimitiveFloatToInt<Int>: PrimitiveFloat {
///
/// # Examples
///
/// `PrimitiveFloatToInt<{integer}>` is a supertrait of [`PrimitiveFloat`] for all primitive
/// integers, so you do not need to use this trait directly with concrete integer types.
///
/// ```
/// use num_primitive::PrimitiveFloat;
///
/// fn pi<Float: PrimitiveFloat>() -> i32 {
/// // SAFETY: π is finite, and truncated to 3 fits any int
/// unsafe { Float::PI.to_int_unchecked() }
/// }
///
/// assert_eq!(pi::<f32>(), 3i32);
/// assert_eq!(pi::<f64>(), 3i32);
/// ```
///
/// However, if the integer type is also generic, an explicit type constraint is needed.
///
/// ```
/// use num_primitive::{PrimitiveFloat, PrimitiveFloatToInt};
///
/// fn tau<Float, Int>() -> Int
/// where
/// Float: PrimitiveFloat + PrimitiveFloatToInt<Int>,
/// {
/// // SAFETY: τ is finite, and truncated to 6 fits any int
/// unsafe { Float::TAU.to_int_unchecked() }
/// }
///
/// assert_eq!(tau::<f32, i64>(), 6i64);
/// assert_eq!(tau::<f64, u8>(), 6u8);
/// ```
///
pub trait PrimitiveFloatToInt<Int> {
#[doc(hidden)]
#[expect(private_interfaces)]
unsafe fn __to_int_unchecked(x: Self, _: SealedToken) -> Int;
Expand Down
12 changes: 1 addition & 11 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extern crate alloc;
use alloc::boxed::Box;
use core::error::Error;

use crate::{PrimitiveError, PrimitiveFloatToInt, PrimitiveInteger, PrimitiveNumber};
use crate::{PrimitiveError, PrimitiveInteger, PrimitiveNumber};

fn check_result<'a, T: PrimitiveNumber, E: PrimitiveError>(r: Result<T, E>, ok: T) {
// Cloning and equating results requires `E: Clone + PartialEq`
Expand Down Expand Up @@ -58,13 +58,3 @@ fn try_into() {
}
check(0i32, 0u32);
}

#[test]
fn to_int_unchecked() {
fn pi<T: PrimitiveFloatToInt<Int>, Int>() -> Int {
// SAFETY: π is finite, and truncated to 3 fits any int
unsafe { T::PI.to_int_unchecked() }
}
assert_eq!(pi::<f32, i64>(), 3i64);
assert_eq!(pi::<f64, u8>(), 3u8);
}