Ability to save/load the Rand32/Rand64 state

Hey icefox!

I've been looking into more lightweight alternatives to Rand for my games and oorandom looks super awesome. I do need to be able to save the state of the random generator and load it back up afterwards, though.

Is that something you're open to add?

I could see either optionally implementing the Serde traits (though you might be against that level of bloat) or just letting us get at the internals of the Rand32/Rand64 structs (i.e. returning the state and reconstructing a new struct from it). Or just make the fields pub YOLO :-D.

Cheers, Tomas Sedovic

Tomáš Šedovič
Assigned to
4 months ago
4 months ago

~icefox 4 months ago

Oh snap, congrats on getting first post on the issue tracker. ;-)

I'm totally down for adding this ability. Serde might be possible, it would be easy to do and easy to make optional. In the interests of keeping everything as brain-dead as possible though, I think for the moment there should just be a function to return the internal states so they can be be fed back to ::new_inc(). Making the internal fields pub is tempting but tinkering with them directly is not something to be encouraged so let's make a consistent interface.

~icefox 4 months ago

Whoops, new_inc() does extra initialization work so we need a separate create from saved state function. Or to undo its setup to produce the stored state, but that doesn't seem worth the trouble and maybe not even possible.

Implementation in https://hg.sr.ht/~icefox/oorandom/rev/9aefacac1a3b47aaf8831f98fe2477a9ae5c486e , any thoughts?

~tomassedovic 4 months ago

Looks perfect, thanks!

It'll be some time before I can test this in my game. But I'm so down with a no questions asked simple seedable prng. Thanks for building this!

~icefox REPORTED FIXED 4 months ago

Published as version 11.0.1, let me know how it works out!

~tomassedovic 4 months ago

Okay, here's a little report: I've replaced Rand with oorandom without much trouble \o/.

Had to write a few extra things I was using in Rand (generating the initial seed, choose, choose_weighted) but that was all pretty small stuff.

I've tried to benchmark it but my mapgen is so fast I had to generate over 8000 worlds in a row before I could see some numerical differences. oorandom is about a third faster than Rand (I was using a csprng there so yea of course) in my use case, but the actual impact on the speed of the game is pretty much nil because it's all so fast anyway (yay rust & simple level gen).

The actual Serde implementation took me some time to figure out, but it's not too bad:

#[derive(Serialize, Deserialize)]
pub struct Game {
     // a bunch of other fields

    #[serde(with = "Rand32Serde")]
    rng: Rand32,

fn rand32_get_state(r: &Rand32) -> u64 {

fn rand32_get_inc(r: &Rand32) -> u64 {

#[derive(Serialize, Deserialize)]
#[serde(remote = "Rand32")]
struct Rand32Serde {
    #[serde(getter = "rand32_get_state")]
    state: u64,
    #[serde(getter = "rand32_get_inc")]
    inc: u64,

impl From<Rand32Serde> for Rand32 {
    fn from(r: Rand32Serde) -> Rand32 {
        Rand32::from_state((r.state, r.inc))

This could be made a little easier by providing two separate getters for the state and inc fields -- that would let me get rid of the rand32_get_* functions. Or of course implementing the Serde traits in oorandom.

But yeah this is pretty okay anyway and honestly, I'm glad I can just put this in my Cargo.toml and forget about it breaking every release like Rand does.

~icefox 4 months ago

Nice, glad to hear it works for you! Serde support might happen sooner or later, I'll play with it.

~icefox referenced this from #2 4 months ago

~tomassedovic referenced this from #2 4 months ago

Register here or Log in to comment, or comment via email.