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;
#[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,
{
#[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 {}