Reputation: 44334
I have two types, each with a bunch of supporting functions; the entire content of these two types should be private (in my case, they are mutable pointers to objects in C). These two types are conceptually different, so I put them in different modules…
pub mod client {
pub struct Client {
// private internals
}
// Lots of code.
}
pub mod collection {
pub struct Collection {
// private internals
}
// Lots of code.
}
(In my real-world case, mod client
and mod collection
are separate files, i.e., client.rs
and collection.rs
.)
client.rs
needs to create a Collection
; however, it can't, because the internals are private. Any attempt to write a function suffers the same problem: the function would need to be in collection.rs
(to access the private members of Collection
, but would need to be pub
so that client.rs
can access it… but now it's also pub
to the entire world.
What I'd really like is some sort of crate-level visibility, or a way to "friend" this struct out to another module. (Otherwise, the pub
lically visible stuff in the crate doesn't represent the API, which seems silly.)
Upvotes: 4
Views: 181
Reputation: 65832
Move Collection
to a new private module (e.g. collection_impl
). Add a public function in that module to create a Collection
. Re-export Collection
from collection
(which is public) with pub use
.
You can use collection_impl
from within your crate, but since it is private, other crates cannot use it. However, by re-exporting Collection
in module collection
, other crates can use Collection
through this path.
pub mod client {
use super::collection;
use super::collection_impl;
pub struct Client {
p: i32
}
/* this could also be a method on Client */
pub fn make_collection(client: &Client) -> collection::Collection {
collection_impl::new_collection(42)
}
}
mod collection_impl {
pub struct Collection {
p: i32
}
pub fn new_collection(p: i32) -> Collection {
Collection { p: p }
}
}
pub mod collection {
use super::collection_impl;
pub use collection_impl::Collection;
}
Upvotes: 3
Reputation: 300159
If you compare Rust and C++ you will notice that Rust does not have:
protected
friend
This is a deliberate design, and there is no alternative. In Rust something is either private or public, and therefore you do not have to jump all around the codebase to know whether an invariant holds or not.
Therefore, the solution is to:
pub fn new
function to create a Collection
This is actually good design; if there is one struct
that should be responsible for upholding Collection
's invariants, it certainly is Collection
itself. Delegating this responsibility to another crate seems hazardous.
Upvotes: 2