Summary
Currently the way of achieving the equivalent of “protected” API functionality is to make a struct, enum, trait, or method be “public”, and then chose not to re-export it using “pub use”.
This works well for everything I mentioned above. Where it is much less useful is for struct fields.
Syntactic extensions to “pub use” could make this dramatically simpler"
Motivation
As far as I can tell, the recommendation for allowing private field access within sibling sub-modules of a large module/crate, but not export those fields externally, is to:
- make the field private, not pub
- make a public sub-module that provides a public api to access that private field
- don’t export the sub-module outside of your crate or primary module
This works. I’m doing it right now. But it is really ugly and cumbersome when you need to do it a lot.
Unfortunately, there are cases where this pattern needs to be used extensively. In particular, FFI usage where you have one -sys crate, either hand written or bindgen-genderated, that should be completely wrapped by a safe crate.
When the -sys crate’s API is large and complex, it is, in practice, necessary to break your wrappers into different files, and hence different modules. So any cross-module “protected” (in the java sense) access requires implementation of the pattern above.
In the work I’ve been doing, my crate that wraps the -sys crate has 30+ files, and 50+ structs who need to follow this pattern. This is taking hours and hours of refactoring work, and the result is substantially more verbose and harder to read than it was when I just accepted exposing what should be hidden implementation details of those structs.
##Design I am not at all attached to this particular syntax nor approach. but the following seems fairly simple, concise, and backwards compatible.
- Make all of your struct fields that need to be accessed by sibling modules as public
- Don’t create an additional sub-module with access methods
- Instead, in the “pub use” section, add syntax to allow you to optionally export public fields instead of requiring the export of private fields.
Possible syntax:
pub use mymod::MyStruct; //same as today. will export all public fields
pub use mymod::MyStruct{}; //hides all fields while exporting this struct
pub use mymod::MyStruct{fieldA, fieldC, fieldD} //does not expose any public fields of MyStruct other than A, C, and D
##Alternatives
- Status quo, which is notably cumbersome for wrapping complex unsafe/ffi crates.
- Alternate syntax. Open to any ideas.
- RFC 1422