Created
November 27, 2023 08:09
-
-
Save stepancheg/64d76e78599a5dec32595cf18195bf45 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::ops::Deref; | |
use std::ops::DerefMut; | |
use bevy::app::App; | |
use bevy::ecs::schedule::InternedScheduleLabel; | |
use bevy::ecs::schedule::ScheduleLabel; | |
use bevy::prelude::{IntoSystem, IntoSystemConfigs}; | |
use crate::bevy_util::auto_deps::res::{read_in_system, write_out_system}; | |
use crate::bevy_util::auto_deps::value::AutoSystemValue; | |
use crate::bevy_util::auto_deps::value::AutoSystemValueId; | |
#[derive(Default)] | |
struct AutoSystemValueStatus { | |
in_filled: bool, | |
out_filled: bool, | |
schedule: Option<InternedScheduleLabel>, | |
} | |
impl AutoSystemValueStatus { | |
fn set_schedule_label(&mut self, schedule: InternedScheduleLabel) { | |
if let Some(schedule_old) = self.schedule { | |
assert_eq!(schedule_old, schedule); | |
} else { | |
self.schedule = Some(schedule); | |
} | |
} | |
} | |
pub(crate) struct AppBuilder { | |
pub(crate) app: App, | |
auto_deps: HashMap<AutoSystemValueId, AutoSystemValueStatus>, | |
} | |
impl AppBuilder { | |
pub(crate) fn new() -> Self { | |
Self::with_app(App::new()) | |
} | |
pub(crate) fn with_app(app: App) -> Self { | |
AppBuilder { | |
app, | |
auto_deps: HashMap::new(), | |
} | |
} | |
pub(crate) fn add_system_with_deps<In, Out, Marker>( | |
&mut self, | |
schedule: impl ScheduleLabel, | |
system: impl IntoSystem<In, Out, Marker>, | |
) where | |
In: AutoSystemValue, | |
Out: AutoSystemValue, | |
{ | |
let schedule = schedule.intern(); | |
In::init_resource(&mut self.app); | |
if let Some(in_t) = In::make_label() { | |
let status = self.auto_deps.entry(in_t).or_default(); | |
status.set_schedule_label(schedule); | |
assert!(!status.in_filled); | |
status.in_filled = true; | |
} | |
if let Some(out_t) = Out::make_label() { | |
let status = self.auto_deps.entry(out_t).or_default(); | |
status.set_schedule_label(schedule); | |
assert!(!status.out_filled); | |
status.out_filled = true; | |
} | |
let mut system = IntoSystemConfigs::into_configs(read_in_system.pipe(system).pipe(write_out_system)); | |
if let Some(in_t) = In::make_label() { | |
system = system.after(in_t.label); | |
} | |
if let Some(out_t) = Out::make_label() { | |
system = system.before(out_t.label); | |
} | |
self.app.add_systems(schedule, system); | |
} | |
pub(crate) fn build(self) -> App { | |
for (_t, status) in self.auto_deps { | |
assert!(status.in_filled); | |
assert!(status.out_filled); | |
} | |
self.app | |
} | |
pub(crate) fn run(self) { | |
self.build().run(); | |
} | |
} | |
impl Deref for AppBuilder { | |
type Target = App; | |
fn deref(&self) -> &Self::Target { | |
&self.app | |
} | |
} | |
impl DerefMut for AppBuilder { | |
fn deref_mut(&mut self) -> &mut Self::Target { | |
&mut self.app | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use bevy::app::Startup; | |
use bevy::prelude::In; | |
use crate::bevy_util::auto_deps::builder::AppBuilder; | |
use crate::bevy_util::auto_deps::value::AutoSystemValueHolder; | |
#[test] | |
fn test() { | |
fn system1() -> AutoSystemValueHolder<u32> { | |
println!("system1"); | |
AutoSystemValueHolder(1) | |
} | |
fn system2(In(AutoSystemValueHolder(x)): In<AutoSystemValueHolder<u32>>) -> AutoSystemValueHolder<String> { | |
println!("system2"); | |
assert_eq!(1, x); | |
AutoSystemValueHolder("hello".to_owned()) | |
} | |
fn system3( | |
In(AutoSystemValueHolder(x)): In<AutoSystemValueHolder<String>>, | |
) { | |
println!("system3"); | |
assert_eq!("hello", x); | |
} | |
let mut app = AppBuilder::new(); | |
app.add_system_with_deps(Startup, system3); | |
app.add_system_with_deps(Startup, system1); | |
app.add_system_with_deps(Startup, system2); | |
app.run(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::any::TypeId; | |
use std::mem; | |
use bevy::prelude::In; | |
use bevy::prelude::ResMut; | |
use bevy::prelude::Resource; | |
use crate::bevy_util::auto_deps::value::AutoSystemValue; | |
#[derive(Resource)] | |
pub(crate) struct AutoRes<T: AutoSystemValue>(pub(crate) Option<T>); | |
impl<T: AutoSystemValue> Default for AutoRes<T> { | |
fn default() -> Self { | |
AutoRes(None) | |
} | |
} | |
pub(crate) fn write_out_system<V: AutoSystemValue>(In(v): In<V>, res: Option<ResMut<AutoRes<V>>>) { | |
if V::is_unit() { | |
return; | |
} else { | |
let mut res = res.unwrap(); | |
assert!(res.0.is_none()); | |
res.0 = Some(v); | |
} | |
} | |
pub(crate) fn read_in_system<V: AutoSystemValue>(res: Option<ResMut<AutoRes<V>>>) -> V { | |
if TypeId::of::<V>() == TypeId::of::<()>() { | |
// We could avoid it with some metaprogramming, but this is cheaper to write. | |
unsafe { mem::transmute_copy(&()) } | |
} else { | |
mem::take(&mut res.unwrap().0).unwrap() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use bevy::app::App; | |
use bevy::ecs::schedule::InternedSystemSet; | |
use bevy::prelude::SystemSet; | |
use crate::bevy_util::auto_deps::res::AutoRes; | |
use crate::bevy_util::system_set::system_type_set::ForkSystemTypeSet; | |
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | |
pub(crate) struct AutoSystemValueId { | |
pub(crate) label: InternedSystemSet, | |
} | |
pub(crate) trait AutoSystemValue: Send + Sync + 'static { | |
fn is_unit() -> bool; | |
fn make_label() -> Option<AutoSystemValueId>; | |
fn init_resource(app: &mut App); | |
} | |
impl AutoSystemValue for () { | |
fn is_unit() -> bool { | |
true | |
} | |
fn make_label() -> Option<AutoSystemValueId> { | |
None | |
} | |
fn init_resource(_app: &mut App) {} | |
} | |
pub(crate) struct AutoSystemValueHolder<T>(pub(crate) T); | |
impl<T: Send + Sync + 'static> AutoSystemValue for AutoSystemValueHolder<T> { | |
fn is_unit() -> bool { | |
false | |
} | |
fn make_label() -> Option<AutoSystemValueId> { | |
Some(AutoSystemValueId { | |
label: ForkSystemTypeSet::<T>::new().intern(), | |
}) | |
} | |
fn init_resource(app: &mut App) { | |
app.init_resource::<AutoRes<Self>>(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment