Skip to content

Commit 52fa186

Browse files
Allow RAND_MAX to be set to 32767.
Might be useful if your newlib assumes that, even with 32-bit integers. Also adds "rand" to list of features in "all" and fixes missing portable-atomic.
1 parent c549fe2 commit 52fa186

File tree

3 files changed

+49
-23
lines changed

3 files changed

+49
-23
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ all = [
3030
"memchr",
3131
"qsort",
3232
"rand_r",
33+
"rand",
3334
"snprintf",
3435
"strcat",
3536
"strchr",
@@ -61,7 +62,8 @@ itoa = []
6162
memchr = []
6263
qsort = []
6364
rand_r = []
64-
rand = ["rand_r"]
65+
rand = ["rand_r", "dep:portable-atomic"]
66+
rand_max_i16 = []
6567
signal = ["dep:portable-atomic"]
6668
signal-cs = ["portable-atomic/critical-section"]
6769
snprintf = []

src/rand.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! Licensed under the Blue Oak Model Licence 1.0.0
44
use core::{
5-
ffi::{c_int, c_uint},
5+
ffi::{c_int, c_uint, c_ulong},
66
sync::atomic::Ordering,
77
};
88

@@ -13,15 +13,18 @@ static RAND_STATE: AtomicU32 = AtomicU32::new(1);
1313
/// Rust implementation of C library function `srand`
1414
#[cfg_attr(feature = "rand", no_mangle)]
1515
pub extern "C" fn srand(seed: c_uint) {
16-
RAND_STATE.store(seed, Ordering::Relaxed);
16+
// we do this cast to support platforms where c_uint is u16.
17+
// but it complains on platforms where c_uint is u32.
18+
#[allow(clippy::unnecessary_cast)]
19+
RAND_STATE.store(seed as u32, Ordering::Relaxed);
1720
}
1821

1922
/// Rust implementation of C library function `rand`.
2023
#[cfg_attr(feature = "rand", no_mangle)]
2124
pub extern "C" fn rand() -> c_int {
22-
let mut state = RAND_STATE.load(Ordering::Relaxed);
25+
let mut state = RAND_STATE.load(Ordering::Relaxed) as c_ulong;
2326
let result = unsafe { crate::rand_r(&mut state) };
24-
RAND_STATE.store(state);
27+
RAND_STATE.store(state as u32, Ordering::Relaxed);
2528
result
2629
}
2730

@@ -30,12 +33,24 @@ mod test {
3033
use super::*;
3134
#[test]
3235
fn test_rand() {
33-
assert_eq!(rand(), 1012484);
34-
assert_eq!(rand(), 1716955679);
35-
assert_eq!(rand(), 1792309082);
36-
srand(5);
37-
assert_eq!(rand(), 234104184);
38-
assert_eq!(rand(), 1214203244);
39-
assert_eq!(rand(), 1803669308);
36+
if c_int::MAX == 32767 || cfg!(feature = "rand_max_i16") {
37+
srand(1);
38+
assert_eq!(rand(), 16838);
39+
assert_eq!(rand(), 5758);
40+
assert_eq!(rand(), 10113);
41+
srand(5);
42+
assert_eq!(rand(), 18655);
43+
assert_eq!(rand(), 8457);
44+
assert_eq!(rand(), 10616);
45+
} else {
46+
srand(1);
47+
assert_eq!(rand(), 476707713);
48+
assert_eq!(rand(), 1186278907);
49+
assert_eq!(rand(), 505671508);
50+
srand(5);
51+
assert_eq!(rand(), 234104184);
52+
assert_eq!(rand(), 1214203244);
53+
assert_eq!(rand(), 1803669308);
54+
}
4055
}
4156
}

src/rand_r.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Rust implementation of C library function `rand_r`
22
//!
33
//! Licensed under the Blue Oak Model Licence 1.0.0
4-
use core::ffi::{c_int, c_uint};
4+
use core::ffi::{c_int, c_uint, c_ulong};
55

66
#[cfg_attr(not(feature = "rand_r"), export_name = "tinyrlibc_RAND_MAX")]
77
#[cfg_attr(feature = "rand_r", no_mangle)]
@@ -12,21 +12,21 @@ pub static RAND_MAX: c_int = c_int::MAX;
1212
/// Passing NULL (core::ptr::null()) gives undefined behaviour.
1313
#[cfg_attr(not(feature = "rand_r"), export_name = "tinyrlibc_rand_r")]
1414
#[cfg_attr(feature = "rand_r", no_mangle)]
15-
pub unsafe extern "C" fn rand_r(seedp: *mut c_uint) -> c_int {
16-
let mut result;
15+
pub unsafe extern "C" fn rand_r(seedp: *mut c_ulong) -> c_int {
16+
let mut result: c_ulong;
1717

18-
fn pump(input: c_uint) -> c_uint {
18+
fn pump(input: c_ulong) -> c_ulong {
1919
// This algorithm is mentioned in the ISO C standard
2020
input.wrapping_mul(1103515245).wrapping_add(12345)
2121
}
2222

23-
fn select_top(state: c_uint, bits: usize) -> c_uint {
23+
fn select_top(state: c_ulong, bits: usize) -> c_ulong {
2424
// ignore the lower 16 bits, as they are low quality
2525
(state >> 16) & ((1 << bits) - 1)
2626
}
2727

2828
let mut next = *seedp;
29-
if c_int::MAX == 32767 {
29+
if c_int::MAX == 32767 || cfg!(feature = "rand_max_i16") {
3030
// pull 15 bits in one go
3131
next = pump(next);
3232
result = select_top(next, 15);
@@ -49,11 +49,20 @@ mod test {
4949
use super::*;
5050
#[test]
5151
fn test_rand_r() {
52-
unsafe {
53-
let mut seed = 5;
54-
assert_eq!(rand_r(&mut seed), 234104184);
55-
assert_eq!(rand_r(&mut seed), 1214203244);
56-
assert_eq!(rand_r(&mut seed), 1803669308);
52+
if c_int::MAX == 32767 || cfg!(feature = "rand_max_i16") {
53+
unsafe {
54+
let mut seed = 5;
55+
assert_eq!(rand_r(&mut seed), 18655);
56+
assert_eq!(rand_r(&mut seed), 8457);
57+
assert_eq!(rand_r(&mut seed), 10616);
58+
}
59+
} else {
60+
unsafe {
61+
let mut seed = 5;
62+
assert_eq!(rand_r(&mut seed), 234104184);
63+
assert_eq!(rand_r(&mut seed), 1214203244);
64+
assert_eq!(rand_r(&mut seed), 1803669308);
65+
}
5766
}
5867
}
5968
}

0 commit comments

Comments
 (0)