Hi all,
As said in the title, I am trying to find ways to organize my ever growing code.
I try to split my code into differents modules, usually into files, but I also try to keep concepts grouped together in those modules. But when I have a module "def", in a file "def.rs" and I have a lot of Types and I need to implement a lot of Traits on them, I end up with a lot of impl block and it makes navigation in the code less nice.
So what are my options to make this codebase easier to navigate ?
-
A) The first obvious way to do this is to split the code into modules. It also permits to control the scope and the privacy. But you will need to bring everything you need in scope (e.g.
use super::*;
)
(also usually the linter won't be happy with super::* ...) -
A1) The module can be inline, within curly brackets. Useful for tests and I guess other scenarios.
It would permit me to collapse the code inside but the annoyance is to put back in scope all what I need. Like this:
#[attribute...]
pub struct Foo {
...
}
mod _impl_Foo {
use super::*;
impl Foo {...}
impl Trait for Foo {...}
...
}
...
-
A2) The module can be in another file, which is obviously a great way to split code. But at a certain resolution, it feels too much. If I have 10 types in my def module, it seems a bit too much to have a 10 submodules which means 10 files + mod.rs for the def itself. + all the
use
statetment repetitions in each module. -
B) The second way is a bit more obscure. I picked up this patern while writting proc macros a learning from serde I think. To use an unnamed constant:
const _: () = {...code...};
In macro it used to assert trait bounds.
This comes with a big caveat anything type defined inside won't be visible outside. But since free constants are always evaluated at compile-time, it seems that writting several impl block inside on a type in scope works and the big advantage is that you stay in the same scope. Like this:
#[attribute...]
pub struct Foo {
...
}
const _: () = {
impl Foo {...}
impl Trait for Foo {...}
...
};
...
Question about the unnamed constant: Is there any drawbacks? Reasons to not do that?
And also, what do you think is the best practice in general and is there another way than A1, A2 and B ?