I have a trait that needs to be public so that it can be used as a constraint for a public function. The implementation of the trait is not meant to be public. This seems to be related to sealed traits ?
Here is an example of what I am trying to accomplish:
use std::convert::From;
//
// PrivateStruct
// This structure is private and not part of the API
struct PrivateStruct { }
//
// PublicTrait
// This trait is public because it is a constraint in check_le_max
pub trait PublicTrait {
#[doc(hidden)]
fn max(_ : Self, _ : PrivateStruct) -> Self;
}
impl PublicTrait for u8 {
// This function is not part of the API
#[doc(hidden)]
fn max(_ : Self , _ : PrivateStruct) -> Self
{ return Self::MAX }
}
//
// check_le_max
// This function is public because it is part of the API
pub fn check_le_max<T>(u : usize, _ : T) -> bool
where
T : From<u8> + PublicTrait ,
usize : From<T> ,
{ let z_t : T = From::from(0u8);
let z_ps : PrivateStruct = PrivateStruct{ };
let max = PublicTrait::max(z_t, z_ps );
u <= From::from(max)
}
//
fn main() {
println!( "( {} <= u8 max) = {}", 255, check_le_max(255, 0u8) );
println!( "( {} <= u8 max) = {}", 256, check_le_max(256, 0u8) );
}
Here is the error message I am getting:
--> src/main.rs:11:5
|
11 | fn max(_ : Self, _ : PrivateStruct) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `PublicTrait::max` is reachable at visibility `pub`
|
note: but type `PrivateStruct` is only usable at visibility `pub(crate)`
--> src/main.rs:5:1
|
5 | struct PrivateStruct { }
| ^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(private_interfaces)]` on by default
use std::convert::From;
mod private {
pub struct PrivateStruct {}
pub trait PrivateTrait {
fn max(_: Self, _: PrivateStruct) -> Self;
}
}
use private::{PrivateStruct, PrivateTrait};
pub trait PublicTrait: PrivateTrait {}
impl PrivateTrait for u8 {
// This function is not part of the API
#[doc(hidden)]
fn max(_: Self, _: PrivateStruct) -> Self {
return Self::MAX;
}
}
impl<T: PrivateTrait> PublicTrait for T {}
//
// check_le_max
// This function is public because it is part of the API
pub fn check_le_max<T>(u: usize, _: T) -> bool
where
T: From<u8> + PublicTrait,
usize: From<T>,
{
let z_t: T = From::from(0u8);
let z_ps: PrivateStruct = PrivateStruct {};
let max = PrivateTrait::max(z_t, z_ps);
u <= From::from(max)
}
//
fn main() {
println!("( {} <= u8 max) = {}", 255, check_le_max(255, 0u8));
println!("( {} <= u8 max) = {}", 256, check_le_max(256, 0u8));
}
More in-depth trait sealing, including alternatives to the snippet above, can be found in this classic blog post:
Edit: you already have PrivateStruct in the method signature, so sealing via this would be more straight-forward and you can get rid of the private trait I introduced above:
use std::convert::From;
mod private {
pub struct PrivateStruct {}
}
use private::PrivateStruct;
pub trait PublicTrait {
fn max(_: Self, _: PrivateStruct) -> Self;
}
impl PublicTrait for u8 {
fn max(_: Self, _: PrivateStruct) -> Self {
return Self::MAX;
}
}
//
// check_le_max
// This function is public because it is part of the API
pub fn check_le_max<T>(u: usize, _: T) -> bool
where
T: From<u8> + PublicTrait,
usize: From<T>,
{
let z_t: T = From::from(0u8);
let z_ps: PrivateStruct = PrivateStruct {};
let max = PublicTrait::max(z_t, z_ps);
u <= From::from(max)
}
//
fn main() {
println!("( {} <= u8 max) = {}", 255, check_le_max(255, 0u8));
println!("( {} <= u8 max) = {}", 256, check_le_max(256, 0u8));
}
The former is a private type. The latter is an inaccessible (not exported) public type. The difference in visibility of PrivateStruct is important in this case. We can't leak a private type in a public interface, but we can use a public type in a public interface, even if we seal it behind a private module.