bevy_rand 0.15.0

A plugin to integrate rand for ECS optimised RNG for the Bevy game engine.
Documentation
use core::{marker::PhantomData, ops::Deref};

#[cfg(feature = "bevy_reflect")]
use bevy_ecs::prelude::ReflectComponent;
use bevy_ecs::{
    component::{Immutable, StorageType},
    prelude::Component,
};
use bevy_prng::EntropySource;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::prelude::{Reflect, ReflectDefault, ReflectFromReflect};

use crate::traits::SeedSource;

/// The initial seed/state for an [`EntropySource`]. Adding this component to an `Entity` will cause
/// an `EntropySource` to be initialised as well. To force a reseed, just insert this component to an
/// `Entity` to overwrite the old value, and the `EntropySource` will be overwritten with the new seed
/// in turn.
///
/// ## Examples
///
/// Randomised Seed via `Default`:
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_prng::WyRand;
/// use bevy_rand::prelude::RngSeed;
///
/// #[derive(Component)]
/// struct Source;
///
/// fn setup_source(mut commands: Commands) {
///     commands
///         .spawn((
///             Source,
///             RngSeed::<WyRand>::default(),
///         ));
/// }
/// ```
#[derive(Debug, Clone)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(
    feature = "bevy_reflect",
    reflect(Debug, Component, PartialEq, Clone, FromReflect, Default)
)]
pub struct RngSeed<R: EntropySource> {
    seed: R::Seed,
    #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
    rng: PhantomData<R>,
}

impl<R: EntropySource> SeedSource<R> for RngSeed<R>
where
    R::Seed: Sync + Send,
{
    /// Create a new instance of [`RngSeed`] from a given `seed` value.
    #[inline]
    fn from_seed(seed: R::Seed) -> Self {
        Self {
            seed,
            rng: PhantomData,
        }
    }

    #[inline]
    fn get_seed(&self) -> &R::Seed {
        &self.seed
    }

    #[inline]
    fn clone_seed(&self) -> R::Seed {
        self.seed.clone()
    }
}

impl<R: EntropySource + 'static> Component for RngSeed<R>
where
    R::Seed: Sync + Send,
{
    const STORAGE_TYPE: StorageType = StorageType::Table;
    type Mutability = Immutable;

    fn on_insert() -> Option<bevy_ecs::lifecycle::ComponentHook> {
        Some(|mut world, context| {
            let seed = world
                .get::<RngSeed<R>>(context.entity)
                .map(|seed| seed.clone_seed())
                .unwrap();
            world
                .commands()
                .entity(context.entity)
                .insert(R::from_seed(seed));
        })
    }

    fn on_remove() -> Option<bevy_ecs::lifecycle::ComponentHook> {
        Some(|mut world, context| {
            world.commands().entity(context.entity).try_remove::<R>();
        })
    }
}

impl<R: EntropySource> Default for RngSeed<R>
where
    R::Seed: Sync + Send,
{
    #[inline]
    fn default() -> Self {
        #[cfg(feature = "thread_local_entropy")]
        {
            Self::from_local_entropy()
        }
        #[cfg(not(feature = "thread_local_entropy"))]
        {
            Self::from_os_rng()
        }
    }
}

impl<R: EntropySource> Deref for RngSeed<R>
where
    R::Seed: Sync + Send,
{
    type Target = R::Seed;

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.get_seed()
    }
}

impl<R: EntropySource> PartialEq for RngSeed<R>
where
    R::Seed: Sync + Send,
{
    fn eq(&self, other: &Self) -> bool {
        self.seed.as_ref() == other.seed.as_ref()
    }
}

impl<R: EntropySource> Eq for RngSeed<R> where R::Seed: Sync + Send {}