Skip to content

Instantly share code, notes, and snippets.

@killercup
Last active July 27, 2024 16:08
Show Gist options
  • Save killercup/3f79222eaafc289088e730cff4cb658a to your computer and use it in GitHub Desktop.
Save killercup/3f79222eaafc289088e730cff4cb658a to your computer and use it in GitHub Desktop.
Rebuilding Bevy system functions
#![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