How to use function pointers or closures efficiently with the help of generics

Hi. I finish my tetris game in rust but I want to exercise with generics and I want to abstract underlying framework(piston) with generic abstract layer which allow me to use any framework without change the game code. Of Course my approach is to use generics. Normally in c++ my code would look like that

#include <iostream>
struct RenderContext {
};

struct Game {
    void handleEvent(RenderContext&) {
        std::cout<<"Some rendering"<<std::endl;
    }
};

template<typename S>
struct AbstractionLayer {
    S& subsciber;

    AbstractionLayer(S& s) : subsciber(s) {}
    void emitEvent() {
        RenderContext ctx;
        subsciber.handleEvent(ctx);
    }
};



int main() {
    Game theGame;
    AbstractionLayer layer(theGame);
    layer.emitEvent();

    return 0;
}

The point here is to not have additional memory allocation and have single indirection(call) and I should be able to achieve this because I know everything in compile time. No runtime decisions
Can I achieve something similar or better in rust

First, I suggest not doing that. Rust's difficulty raises exponentially with layers of abstraction.

C++ templates are sort of in between two Rust features: macros and generics.

You can create a macro that, like a C++ template, syntactically generates all the types and functions, and even they will work as long as everything in the generated code matches in a duck-typed way.

Second option is create a trait (or a family of traits and associated types) that handles all the operations you need.

However, Rust's generics are equivalent of C++ Concepts. They're type-safe in a strict way (no duck typing!). They won't allow use of anything, no matter how boring and basic, if it's not declared by trait bounds ahead of time. I can't stress enough how picky generics are about this. In generic code you can't even add two numbers if you don't declare their types support addition and the result is also a number. This level of pedantism is fine for containers and iterators, but if you try to stretch it to the whole game engine, it's likely to be super painful. And it'll describe your particular engine in such a detail, that in practice it won't be possible to implement these traits for any other engine. I recommend YAGNI here.

Instead of layers of abstraction (where you make a code monolith and use abstraction to substitute its parts), it's more common in Rust to make reusable components. This way you make fixed non-abstract program out of building blocks. But you can use the same building blocks to make other, similar programs.

So instead of writing a single engine-abstract game, try extracting parts of the game as tiny libraries that can be used in games written in different engines.

2 Likes

I really do not need to implement that abstraction layer but while I still need to exercise generics it look like good opportunity for that. Also I believe that abstracting the framework that allow me to render and handle input wouldn't be so hard. I only need to abstract how 3 functions of my code are called from outside and implement resource handle that abstract the real type of those. About macros it's too early for me to learn them. I prefer to learn more basic skills first