I don't even use pub(crate). I try to develop every module, even crate-private ones, so that they have a well-defined interface, outside of which nothing is exposed. It's easier for me to keep abstraction boundaries sound (and my code bug-free) in my mind when dependencies form a strict hierarchy rather than an arbitrary graph.
A great side effect of this approach is that making a module public after the fact usually doesn't require additional thought, coding, verification, tests, etc. It is sufficient to add pub and voilà, a new, correctly-functioning public module is born. (In order for this to work, I also like to document private items with the same scrutiny as public ones.)
I try to put every Struct/Enum in it's own separate *.rs file.
Sometimes, the impls of these Structs/Enums have functions that other modules (in the same crate) need (but should never be called outside the crate), and thus my usage of pub(crate).
I see; that does seem like a legitimate use case. I just don't think it is important to put every user-defined type in its own file.
As far as I can tell, that practice is mainly prevalent in object-oriented languages, but Rust's types are much more self-contained, more modular, and simpler, so I usually find it advantageous to keep closely-related types together in the same file, so that I don't have to context (and file) switch too often while writing or modifying their implementation.
Having many files and/or very deep hierarchies – and thus the need of jumping around across several different files when changing them – tends to annoy me and makes me lose track of what I'm about to do.
(Also, if two types need to be able to rip each others' guts apart, they probably do belong in the same household. )
I do the same. I use pub(crate) sparingly. But I otherwise have never used any other visibility modifier. I don't think I've ever needed that kind of fine grained visibility. Otherwise, it just seems like extra complexity for little gain unless you're in a case where it's critical to have. (I can't immediately think of any such case though.)
I personally like using pub(self) as a way to explicit that something is private / not public, especially for functions that are usually pub. For instance, in this post, I show a code pattern whereby the "classic" new constructor must not be visible, so I annotate it with pub(self) // private !
to make it resiliant to future changes.