Last active
July 27, 2024 16:08
-
-
Save killercup/3f79222eaafc289088e730cff4cb658a to your computer and use it in GitHub Desktop.
Rebuilding Bevy system functions
This file contains hidden or 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
#![allow(dead_code)] | |
// ------------------ | |
// The game code | |
// ------------------ | |
fn main() { | |
App::new() | |
.add_system(example_system) | |
.add_system(another_example_system) | |
.add_system(complex_example_system) | |
.run(); | |
} | |
fn example_system() { | |
println!("foo"); | |
} | |
fn another_example_system(_q: Query<&Position>) { | |
println!("bar"); | |
} | |
fn complex_example_system(_q: Query<&Position>, _r: ()) { | |
println!("baz"); | |
} | |
// ------------------ | |
// App boilerplate | |
// ------------------ | |
struct App { | |
systems: Vec<Box<dyn System>>, | |
} | |
impl App { | |
fn new() -> App { | |
App { | |
systems: Vec::new(), | |
} | |
} | |
fn add_system<F: IntoSystem<Params>, Params: SystemParam>(mut self, function: F) -> Self { | |
self.systems.push(Box::new(function.into_system())); | |
self | |
} | |
fn run(&mut self) { | |
for system in &mut self.systems { | |
system.run(); | |
} | |
} | |
} | |
// Use this to fetch entities | |
struct Query<T> { | |
output: T, | |
} | |
// The position of an entity in 2D space | |
struct Position { | |
x: f32, | |
y: f32, | |
} | |
// ------------------ | |
// Systems magic | |
// ------------------ | |
use core::marker::PhantomData; | |
/// This is what we store | |
trait System: 'static { | |
fn run(&mut self); | |
} | |
/// Convert thing to system (to create a trait object) | |
trait IntoSystem<Params> { | |
type System: System; | |
fn into_system(self) -> Self::System; | |
} | |
/// Convert any function with only system params into a system | |
impl<F, Params: SystemParam> IntoSystem<Params> for F | |
where | |
F: SystemParamFunction<Params>, | |
{ | |
type System = FunctionSystem<F, Params>; | |
fn into_system(self) -> Self::System { | |
FunctionSystem { | |
system: self, | |
params: PhantomData, | |
} | |
} | |
} | |
/// Represent a system with its params | |
// | |
// TODO: do stuff with params | |
struct FunctionSystem<F: 'static, Params: SystemParam> { | |
system: F, | |
params: PhantomData<Params>, | |
} | |
/// Make our wrapper be a System | |
impl<F, Params: SystemParam> System for FunctionSystem<F, Params> | |
where | |
F: SystemParamFunction<Params>, | |
{ | |
fn run(&mut self) { | |
SystemParamFunction::run(&mut self.system); | |
} | |
} | |
/// Function with only system params | |
trait SystemParamFunction<Params: SystemParam>: 'static { | |
fn run(&mut self); | |
} | |
/// unit function | |
impl<F> SystemParamFunction<()> for F | |
where | |
F: Fn() -> () + 'static, | |
{ | |
fn run(&mut self) { | |
eprintln!("calling a function with no params"); | |
self(); | |
} | |
} | |
/// one param function | |
impl<F, P1: SystemParam> SystemParamFunction<(P1,)> for F | |
where | |
F: Fn(P1) -> () + 'static, | |
{ | |
fn run(&mut self) { | |
eprintln!("calling a function"); | |
eprintln!("params:"); | |
<P1 as SystemParam>::debug(); | |
println!("TODO: fetching params"); | |
} | |
} | |
/// two param function | |
impl<F, P1: SystemParam, P2: SystemParam> SystemParamFunction<(P1, P2)> for F | |
where | |
F: Fn(P1, P2) -> () + 'static, | |
{ | |
fn run(&mut self) { | |
eprintln!("calling a function"); | |
eprintln!("params:"); | |
<P1 as SystemParam>::debug(); | |
<P2 as SystemParam>::debug(); | |
println!("TODO: fetching params"); | |
} | |
} | |
// exercise for reader: macro to make this for other functions | |
/// Marker trait for parameters of a System function | |
trait SystemParam: 'static { | |
fn debug(); | |
} | |
/// Query is a good param | |
impl<T: 'static> SystemParam for Query<T> { | |
fn debug() { | |
eprintln!("Query") | |
} | |
} | |
impl SystemParam for () { | |
fn debug() { | |
eprintln!("unit") | |
} | |
} | |
impl<T1> SystemParam for (T1,) | |
where | |
T1: SystemParam, | |
{ | |
fn debug() { | |
eprintln!("Tuple("); | |
<T1 as SystemParam>::debug(); | |
eprintln!(")"); | |
} | |
} | |
impl<T1, T2> SystemParam for (T1, T2) | |
where | |
T1: SystemParam, | |
T2: SystemParam, | |
{ | |
fn debug() { | |
eprintln!("Tuple("); | |
<T1 as SystemParam>::debug(); | |
eprintln!(", "); | |
<T2 as SystemParam>::debug(); | |
eprintln!(")"); | |
} | |
} | |
// exercise for reader: macro to make this for other tuples | |
// exercise for highly-ambitious reader: 1 macro for both the other macros |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment