macro_rules! impl_vec_types {
(
$t:ty,
$vec2:ident,
$vec3:ident,
$vec4:ident,
$uniform:ident,
$upper_range_multiplier:expr
) => {
use super::{UniformVec2, UniformVec3, UniformVec4};
use rand::{
distr::{
uniform::{Error as UniformError, SampleBorrow, SampleUniform, UniformSampler},
Distribution, StandardUniform,
},
Rng,
};
impl Distribution<$vec2> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $vec2 {
rng.random::<[$t; 2]>().into()
}
}
impl SampleUniform for $vec2 {
type Sampler = UniformVec2<$uniform<$t>>;
}
impl UniformSampler for UniformVec2<$uniform<$t>> {
type X = $vec2;
fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y {
return Err(UniformError::EmptyRange);
}
Ok(Self {
x_gen: $uniform::new(low.x, high.x)?,
y_gen: $uniform::new(low.y, high.y)?,
})
}
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y {
return Err(UniformError::EmptyRange);
}
Ok(Self {
x_gen: $uniform::new_inclusive(low.x, high.x)?,
y_gen: $uniform::new_inclusive(low.y, high.y)?,
})
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
Self::X::from([self.x_gen.sample(rng), self.y_gen.sample(rng)])
}
fn sample_single<R: Rng + ?Sized, B1, B2>(
low_b: B1,
high_b: B2,
rng: &mut R,
) -> Result<Self::X, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y {
return Err(UniformError::EmptyRange);
}
Ok(Self::X::from([
$uniform::<$t>::sample_single(low.x, high.x, rng)?,
$uniform::<$t>::sample_single(low.y, high.y, rng)?,
]))
}
fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
low_b: B1,
high_b: B2,
rng: &mut R,
) -> Result<Self::X, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y {
return Err(UniformError::EmptyRange);
}
Ok(Self::X::from([
$uniform::<$t>::sample_single_inclusive(low.x, high.x, rng)?,
$uniform::<$t>::sample_single_inclusive(low.y, high.y, rng)?,
]))
}
}
impl Distribution<$vec3> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $vec3 {
rng.random::<[$t; 3]>().into()
}
}
impl SampleUniform for $vec3 {
type Sampler = UniformVec3<$uniform<$t>>;
}
impl UniformSampler for UniformVec3<$uniform<$t>> {
type X = $vec3;
fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z {
return Err(UniformError::EmptyRange);
}
Ok(Self {
x_gen: $uniform::new(low.x, high.x)?,
y_gen: $uniform::new(low.y, high.y)?,
z_gen: $uniform::new(low.z, high.z)?,
})
}
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z {
return Err(UniformError::EmptyRange);
}
Ok(Self {
x_gen: $uniform::new_inclusive(low.x, high.x)?,
y_gen: $uniform::new_inclusive(low.y, high.y)?,
z_gen: $uniform::new_inclusive(low.z, high.z)?,
})
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
Self::X::from([
self.x_gen.sample(rng),
self.y_gen.sample(rng),
self.z_gen.sample(rng),
])
}
fn sample_single<R: Rng + ?Sized, B1, B2>(
low_b: B1,
high_b: B2,
rng: &mut R,
) -> Result<Self::X, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z {
return Err(UniformError::EmptyRange);
}
Ok(Self::X::from([
$uniform::<$t>::sample_single(low.x, high.x, rng)?,
$uniform::<$t>::sample_single(low.y, high.y, rng)?,
$uniform::<$t>::sample_single(low.z, high.z, rng)?,
]))
}
fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
low_b: B1,
high_b: B2,
rng: &mut R,
) -> Result<Self::X, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z {
return Err(UniformError::EmptyRange);
}
Ok(Self::X::from([
$uniform::<$t>::sample_single_inclusive(low.x, high.x, rng)?,
$uniform::<$t>::sample_single_inclusive(low.y, high.y, rng)?,
$uniform::<$t>::sample_single_inclusive(low.z, high.z, rng)?,
]))
}
}
impl Distribution<$vec4> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $vec4 {
rng.random::<[$t; 4]>().into()
}
}
impl SampleUniform for $vec4 {
type Sampler = UniformVec4<$uniform<$t>>;
}
impl UniformSampler for UniformVec4<$uniform<$t>> {
type X = $vec4;
fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
return Err(UniformError::EmptyRange);
}
Ok(Self {
x_gen: $uniform::new(low.x, high.x)?,
y_gen: $uniform::new(low.y, high.y)?,
z_gen: $uniform::new(low.z, high.z)?,
w_gen: $uniform::new(low.w, high.w)?,
})
}
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
return Err(UniformError::EmptyRange);
}
Ok(Self {
x_gen: $uniform::new_inclusive(low.x, high.x)?,
y_gen: $uniform::new_inclusive(low.y, high.y)?,
z_gen: $uniform::new_inclusive(low.z, high.z)?,
w_gen: $uniform::new_inclusive(low.w, high.w)?,
})
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
Self::X::from([
self.x_gen.sample(rng),
self.y_gen.sample(rng),
self.z_gen.sample(rng),
self.w_gen.sample(rng),
])
}
fn sample_single<R: Rng + ?Sized, B1, B2>(
low_b: B1,
high_b: B2,
rng: &mut R,
) -> Result<Self::X, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
return Err(UniformError::EmptyRange);
}
Ok(Self::X::from([
$uniform::<$t>::sample_single(low.x, high.x, rng)?,
$uniform::<$t>::sample_single(low.y, high.y, rng)?,
$uniform::<$t>::sample_single(low.z, high.z, rng)?,
$uniform::<$t>::sample_single(low.w, high.w, rng)?,
]))
}
fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
low_b: B1,
high_b: B2,
rng: &mut R,
) -> Result<Self::X, UniformError>
where
B1: SampleBorrow<Self::X> + Sized,
B2: SampleBorrow<Self::X> + Sized,
{
let low = *low_b.borrow();
let high = *high_b.borrow();
if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
return Err(UniformError::EmptyRange);
}
Ok(Self::X::from([
$uniform::<$t>::sample_single_inclusive(low.x, high.x, rng)?,
$uniform::<$t>::sample_single_inclusive(low.y, high.y, rng)?,
$uniform::<$t>::sample_single_inclusive(low.z, high.z, rng)?,
$uniform::<$t>::sample_single_inclusive(low.w, high.w, rng)?,
]))
}
}
#[test]
fn test_vec2_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a: ($t, $t) = rng1.random();
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b: $vec2 = rng2.random();
assert_eq!(a, b.into());
}
#[test]
fn test_vec3_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a: ($t, $t, $t) = rng1.random();
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b: $vec3 = rng2.random();
assert_eq!(a, b.into());
}
#[test]
fn test_vec4_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a: ($t, $t, $t, $t) = rng1.random();
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b: $vec4 = rng2.random();
assert_eq!(a, b.into());
}
test_vec_type_uniform!(
test_vec2_rand_uniform_equality,
$vec2,
$t,
2,
$upper_range_multiplier
);
test_vec_type_uniform!(
test_vec3_rand_uniform_equality,
$vec3,
$t,
3,
$upper_range_multiplier
);
test_vec_type_uniform!(
test_vec4_rand_uniform_equality,
$vec4,
$t,
4,
$upper_range_multiplier
);
};
}
macro_rules! test_vec_type_uniform {
(__repeat_code 2, $code:expr) => {
($code, $code)
};
(__repeat_code 3, $code:expr) => {
($code, $code, $code)
};
(__repeat_code 4, $code:expr) => {
($code, $code, $code, $code)
};
(
$equality_test_name:ident,
$vec:ident,
$t:ty,
$t_count:tt,
$upper_range_divisor:expr
) => {
#[test]
fn $equality_test_name() {
use rand::{distr::Uniform, Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut int_rng = Xoshiro256Plus::seed_from_u64(0);
let mut vec_rng = Xoshiro256Plus::seed_from_u64(0);
macro_rules! test_uniform {
(
__single_test,
$uniform_function_name:ident,
$t_low:expr,
$t_high:expr,
$vec_low:expr,
$vec_high:expr
) => {
let int_u = Uniform::$uniform_function_name($t_low, $t_high).unwrap();
let vec_u = Uniform::$uniform_function_name($vec_low, $vec_high).unwrap();
let v_int = test_vec_type_uniform!(
__repeat_code $t_count,
int_rng.sample(int_u)
);
let v_vec: $vec = vec_rng.sample(vec_u);
assert_eq!(v_int, v_vec.into());
};
(
$uniform_function_name:ident,
$t_low:expr,
$t_high:expr,
$vec_low:expr,
$vec_high:expr
) => {
test_uniform!(
__single_test,
$uniform_function_name,
$t_low, $t_high,
$vec_low, $vec_high
);
test_uniform!(
__single_test,
$uniform_function_name,
&$t_low, &$t_high,
&$vec_low, &$vec_high
);
};
}
test_uniform!(
new,
<$t>::default(),
<$t>::MAX / $upper_range_divisor,
$vec::default(),
$vec::MAX / $upper_range_divisor
);
test_uniform!(
new_inclusive,
<$t>::default(),
<$t>::MAX / $upper_range_divisor,
$vec::default(),
$vec::MAX / $upper_range_divisor
);
macro_rules! test_sample_uniform_sampler {
($sampler_function_name:ident) => {
let v_int = test_vec_type_uniform!(
__repeat_code $t_count,
<$t as SampleUniform>::Sampler::$sampler_function_name(
<$t>::default(),
<$t>::MAX / $upper_range_divisor,
&mut int_rng,
).unwrap()
);
let v_vec: $vec = <$vec as SampleUniform>::Sampler::$sampler_function_name(
$vec::default(),
$vec::MAX / $upper_range_divisor,
&mut vec_rng,
).unwrap();
assert_eq!(v_int, v_vec.into());
};
}
test_sample_uniform_sampler!(sample_single);
test_sample_uniform_sampler!(sample_single_inclusive);
}
};
}
macro_rules! impl_int_types {
($t:ty, $vec2:ident, $vec3:ident, $vec4:ident) => {
use rand::distr::uniform::UniformInt;
impl_vec_types!($t, $vec2, $vec3, $vec4, UniformInt, 1);
};
}
macro_rules! impl_float_types {
($t:ident, $mat2:ident, $mat3:ident, $mat4:ident, $quat:ident, $vec2:ident, $vec3:ident, $vec4:ident) => {
use rand::distr::uniform::UniformFloat;
impl_vec_types!($t, $vec2, $vec3, $vec4, UniformFloat, 10.0);
impl Distribution<$mat2> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $mat2 {
$mat2::from_cols_array(&rng.random())
}
}
impl Distribution<$mat3> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $mat3 {
$mat3::from_cols_array(&rng.random())
}
}
impl Distribution<$mat4> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $mat4 {
$mat4::from_cols_array(&rng.random())
}
}
impl Distribution<$quat> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $quat {
let z = rng.random_range::<$t, _>(-1.0..=1.0);
let (y, x) = math::sin_cos(rng.random_range::<$t, _>(0.0..TAU));
let r = math::sqrt(1.0 - z * z);
let axis = $vec3::new(r * x, r * y, z);
let angle = rng.random_range::<$t, _>(0.0..TAU);
$quat::from_axis_angle(axis, angle)
}
}
#[test]
fn test_mat2_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a = $mat2::from_cols_array(&rng1.random::<[$t; 4]>());
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b = rng2.random::<$mat2>();
assert_eq!(a, b);
}
#[test]
fn test_mat3_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a = $mat3::from_cols_array(&rng1.random::<[$t; 9]>());
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b = rng2.random::<$mat3>();
assert_eq!(a, b);
}
#[test]
fn test_mat4_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a = $mat4::from_cols_array(&rng1.random::<[$t; 16]>());
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b = rng2.random::<$mat4>();
assert_eq!(a, b);
}
#[test]
fn test_quat_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a: $quat = rng1.random();
assert!(a.is_normalized());
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b: $quat = rng2.random();
assert_eq!(a, b);
}
};
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct UniformVec2<G> {
x_gen: G,
y_gen: G,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct UniformVec3<G> {
x_gen: G,
y_gen: G,
z_gen: G,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct UniformVec4<G> {
x_gen: G,
y_gen: G,
z_gen: G,
w_gen: G,
}
mod f32 {
use crate::f32::math;
use crate::{Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4};
use core::f32::consts::TAU;
impl_float_types!(f32, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4);
impl Distribution<Vec3A> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec3A {
rng.random::<[f32; 3]>().into()
}
}
#[test]
fn test_vec3a_rand_standard() {
use rand::{Rng, SeedableRng};
use rand_xoshiro::Xoshiro256Plus;
let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
let a: (f32, f32, f32) = rng1.random();
let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
let b: Vec3A = rng2.random();
assert_eq!(a, b.into());
}
}
mod f64 {
use crate::f64::math;
use crate::{DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4};
use core::f64::consts::TAU;
impl_float_types!(f64, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4);
}
mod i8 {
use crate::{I8Vec2, I8Vec3, I8Vec4};
impl_int_types!(i8, I8Vec2, I8Vec3, I8Vec4);
}
mod i16 {
use crate::{I16Vec2, I16Vec3, I16Vec4};
impl_int_types!(i16, I16Vec2, I16Vec3, I16Vec4);
}
mod i32 {
use crate::{IVec2, IVec3, IVec4};
impl_int_types!(i32, IVec2, IVec3, IVec4);
}
mod i64 {
use crate::{I64Vec2, I64Vec3, I64Vec4};
impl_int_types!(i64, I64Vec2, I64Vec3, I64Vec4);
}
mod u8 {
use crate::{U8Vec2, U8Vec3, U8Vec4};
impl_int_types!(u8, U8Vec2, U8Vec3, U8Vec4);
}
mod u16 {
use crate::{U16Vec2, U16Vec3, U16Vec4};
impl_int_types!(u16, U16Vec2, U16Vec3, U16Vec4);
}
mod u32 {
use crate::{UVec2, UVec3, UVec4};
impl_int_types!(u32, UVec2, UVec3, UVec4);
}
mod u64 {
use crate::{U64Vec2, U64Vec3, U64Vec4};
impl_int_types!(u64, U64Vec2, U64Vec3, U64Vec4);
}