I feel like allowing lib.rs and main.rs to be in the same directory has caused a lot of confusion because users may mod something they actually mean to use from the library. If it wasn't so convenient for bin-only packages, I'd be considering deprecating src/main.rs.
I think we should deprecate src/main.rs when there's also a src/lib.rs to avoid the pitfall of using modules by having mod foo; in both of them instead of using stuff through the library's public api.
What would your proposed replacement be for bin+lib packages? How would they work instead? I often make use of them, as you can't add integration tests on a pure bin crate, you need a bin+lib for that, with the bin crate being just a thin wrapper around the lib.
Just use src/bin/my_package.rs (or maybe src/bin/main.rs or src/bin/default.rs in a new edition), since that's clearly in its own folder, people won't be tempted to just use mod foo; where foo is actually part of the library crate.
I like the idea of removing the option of having both in one directory, because it is a common way for newcomers to end up compiling the same files in two crates and become very confused by the resulting errors (or dead code warnings).
Just use src/bins/my_package.rs
In case anyone gets confused by trying this and having it not work: the directory name is actuallysrc/bin/, not src/bins/.
BTW: It's not immediately obvious that src/bin/main.rs is meant to stay, and this post could be interpreted as deprecation of bin+lib packages in general, not just the specific file path combination.
Ideally, use of redundant mod for the same file in both lib and bin should just be a warning that directly says what's going on. Unfortunately, it falls in between responsibilities of rustc vs cargo, so neither one is in a good position to properly detect this problem.
Currently src/main.rs is the default for cargo new, and I think it should stay like that to keep the initial file easy to find, especially for people just starting with Rust.
But if src/main.rs stays, then Cargo should make it easy, maybe even automatic, to switch to the src/bin layout when src/lib.rs is added, because this isn't going to be a one-off migration, but a natural step in development for many projects when they grow and reorganize.
I kinda think it might make more sense to beginners if we keep src/main.rs as long as there's only one binary crate, and instead move src/lib.rs to src/lib/mod.rs or some such.
That would be a valid filesystem layout for mod lib in the binary, which is another version of the same problem.
It's also an apparent inconsistency that bin/main.rs works, but lib/main.rs doesn't (if you assume main.rs is the default file for crates, like mod.rs is for modules).
I wonder how crazy it would be to deprecate src altogether and have bin/main.rs, where bin is in the same directory as Cargo.toml, be the default crate root for binary crates. And, in fact, lib/main.rs for library crates. You could still have multiple binary crates with bin/ls.rs, bin/cat.rs, etc. in the same way you do now.
That would be even more confusing than src/bin already is. In other projects, bin is typically the directory for compiled files with machine code, not for source files (i.e. what target is in Cargo projects). The name bin suggests it contains files in binary, i.e. machine code rather than ASCII text.
What about main as a top level folder name? So instead of binary, it's "the file (or group of files for multiple binary targets) that define fn main". If we're uneasy calling it binary, then that seems like the main (chuckles) distinction from src/lib.rs.
This still leaves the open question of the default binary source file (main/main.rs?), and I'm also not sure how much symmetry there should be with src/lib.rs
That's just one convention. Another one, which is at least as old as Unix V74.1cBSD (1982), is to have bin in a source tree hold source code that will be compiled into programs to be installed into /(usr/)bin, and similarly for lib.
I can't find any src/bin or src/lib directories in that Unix directory tree. Can you point to the specific directories you're talking about? Perhaps you're talking about shell scripts in /bin? But those are not in a source tree and don't get compiled.
It would be consistent if the lib target was also in a lib directory. Having bin for binaries and src for libraries is inconsistent in its own way.
I'm not sure if it's even possible to make the two seem consistent, because there can be multiple binaries, but only one library. Presumably any naming scheme that keeps binaries clearly separate would add unnecessary directory structure for the singular library.
Sorry, I didn't check thoroughly enough. The oldest source tree I can find on TUHS that actually does use src/bin as a directory containing .c sources to be compiled, is 4.1cBSD. That means the convention "only" dates to 1982, not 1979.
The V7/System V phylum seems to have used src/cmd for the same purpose that the BSD phylum used src/bin, but nowadays I think the src/bin convention will be more familiar -- it is, for example, used to this day by FreeBSD.
What if rustc warned on any use of mod inside src/main.rs if there's also a src/lib.rs?
I think it would be simpler from implementation perspective — Cargo knows when both files exist, and is already in charge of [lints], so it could conditionally enable the warning by adding something like -W modules_in_bin to the rustflags. Then rustc would know to warn about any mod it sees, and could explain the footgun. This way rustc doesn't need to parse two targets, and there's no need to cross-reference paths or module names.
Users who still want mod in both will have an option of renaming main.rs or simply silence the warning like any other lint.