How to organize code among modules?

I have a multiple-precision floating point number arithmetic library written by myself in C and C++ and I recently want to translate it into rust. But I simply have no idea of how to organize my code.

I plan to let it be a crate. My C files do low level mantissa operations, and my C++ files implement a class of realizing multiple-precision arithmetic operations. The C files are quite independent of one another.

According to "the book", the functions in the root module, even private, can be called by all the functions in the crate. Thus it seems I should put the lowest level routines in the root module. But we all know if the crate is a bin, then the main function is in the root module and main is the highest level function. So I get confused. Is there any guidelines on code organization for rust?

1 Like

If you are creating a library then the crate won't be a bin. I'd probably organise the crate to have a raw module containing all the low level operations, then a second module which contains the wrapper structs that use these low level operations.

Generally you want to keep to keep your root lib.rs pretty clean, for convenience only re-exporting types and functions people are going to be using all the time. MDBook is by no means a perfect example, but this is how we structured things and it's worked out fairly well so far.

What I generally do is start off lumping everything into lib.rs, then as the crate starts to get bigger and harder to navigate (around 100-200 lines) I'll start breaking bits out into their own modules. This lets you naturally find a module structure which suits the domain and means you don't waste loads of time trying to plan out every little detail before you've written any code, only to find your original plan doesn't work out in practice.

2 Likes

No, putting things in a root module because they're "private" is a bad idea. There's absolutely no need to do so, because you have control over privacy of all your functions — pub(crate) anywhere gives you the same level of access. And you can use ("#include") modules in other modules in your crate, so you're free to structure the code the way it makes sense to you.

The usual approach is to group code in modules by functionality. Implement one thing/group of things as a module, and give it a public interface for the rest of the crate (you can think of modules as mini crates themselves). Note that the module itself doesn't have to be public outside the crate, so pub items in private modules are just for the rest of your code.

In lib.rs I often have no code at all (apart from extern crate/mod and pub use). In lib.rs I pub use items from internal modules to create a simplified public interface for my library.

Starting with one module per one C file may work.

1 Like

In a single C file I usually only write one function. This is also the style used by the Microsoft C runtime library. But this style is no longer suitable for rust, because if I have a MtsAdd.rs file that contains only the MtsAdd function, then it must have a file name/module name (which is also MtsAdd), and it must be referred to as (if my crate name is Multiprecision) Multiprecison::MtsAdd::MtsAdd . Two appearances of MtsAdd now.

1 Like

That does sound excessive. If you put all your modules in a private module and then pub use functions in the root, you can have API of the crate different from your internal structure of modules, but I haven't seen anyone use one module per function in Rust.

2 Likes