Separation of Concerns

I'm working on a port of a game called AssaultCube. Originally, it was created in C++ and I was going to refactor the code and add new features. After looking at the code I changed my mind and decided on a complete rewrite in Rust.

The first goal is creating a logging library. It's going to be simple just like the one in AssaultCube. I also want to easily switch any component like the logging library for another if I decide it will fulfill the job better.

What is the best way to do this in Rust?

Have a look at the log crate.

Thank you, but my main concern is the ability to switch out components if needed.

That is the objective of the log crate - it allows you to switch out the actual logging logic to whatever you want.

If the concern is more general than any one dependency crate, you'll have to do that yourself with feature gates and using the correct dependencies in just the right ways.

The log crate is pretty nice. I'm not sure if this is what you mean by switching out components, but log is actually just a standardized interface to deal with logging. the actual logging output and formatting can be provided by any struct that implements log::Log. You can then register the instance with set_logger or set_boxed_logger. All the logging macros from log just look at the global logger instance and call into that. This is really nice since lots of crates in the existing ecosystem just have logging for whatever backend you choose built in because they depend on log.

It's perfectly fine to implement your own logger if the existing implementations don't work for this case, but there definitely are some flexible logging backend crates that you might look at as an example. env_logger tends to be the go-to simple logging system, and I have had success with fern when I need more flexibility.

1 Like

What I need is the ability to switch any component in the game easily not just the logger. This could include a networking library for library capabilities. I need a front end and a back end and I would like to know how to do this best in Rust.

In short, traits are used to define an abstraction, so that’s your frontend. Implementations of them are then the backend. You’ll need to decide whether you want to use generics or trait objects, or a combination of both.

You may also want to consider using an ECS library, such as specs. Or just look at it for design inspiration.

1 Like