use std::marker::PhantomData;
use bevy::{
prelude::{FromWorld, World},
reflect::{PartialReflect, Reflect},
};
pub trait Strategy {
type Target;
type Stored;
fn store(target: &Self::Target) -> Self::Stored;
fn load(stored: &Self::Stored) -> Self::Target;
fn update(target: &mut Self::Target, stored: &Self::Stored) {
*target = Self::load(stored);
}
}
pub struct CopyStrategy<T: Copy>(PhantomData<T>);
impl<T: Copy> Strategy for CopyStrategy<T> {
type Target = T;
type Stored = T;
#[inline(always)]
fn store(target: &Self::Target) -> Self::Stored {
*target
}
#[inline(always)]
fn load(stored: &Self::Stored) -> Self::Target {
*stored
}
}
pub struct CloneStrategy<T: Clone>(PhantomData<T>);
impl<T: Clone> Strategy for CloneStrategy<T> {
type Target = T;
type Stored = T;
#[inline(always)]
fn store(target: &Self::Target) -> Self::Stored {
target.clone()
}
#[inline(always)]
fn load(stored: &Self::Stored) -> Self::Target {
stored.clone()
}
#[inline(always)]
fn update(target: &mut Self::Target, stored: &Self::Stored) {
target.clone_from(stored);
}
}
pub struct ReflectStrategy<T: Reflect + FromWorld>(PhantomData<T>);
impl<T: Reflect + FromWorld> Strategy for ReflectStrategy<T> {
type Target = T;
type Stored = Box<dyn PartialReflect>;
#[inline(always)]
fn store(target: &Self::Target) -> Self::Stored {
target.as_reflect().to_dynamic()
}
#[inline(always)]
fn update(target: &mut Self::Target, stored: &Self::Stored) {
target.apply(stored.as_ref());
}
#[inline(always)]
fn load(stored: &Self::Stored) -> Self::Target {
let mut world: World = Default::default();
let mut target = Self::Target::from_world(&mut world);
Self::update(&mut target, stored);
target
}
}
#[cfg(test)]
mod tests {
use bevy::prelude::*;
use super::{ReflectStrategy, Strategy};
#[derive(Reflect, Default, PartialEq, Debug)]
struct Foo {
x: f32,
y: u32,
}
#[test]
fn reflect_strategy_round_trip() {
let value = Foo { x: 1.5, y: 7 };
let stored = ReflectStrategy::<Foo>::store(&value);
let loaded = ReflectStrategy::<Foo>::load(&stored);
assert_eq!(loaded, value);
}
}