7

In another question of mine, I asked how to publicly expose only a concrete variant (Foo<u32>) of a private generic type (Foo<T>). The suggested solution is as follows:

mod internal {
    /// Private documentation of `Foo`.
    pub struct Foo<X> {
        /// Private documentation of `x`.
        pub x: X,
    }

    impl Foo<u32> {
        pub fn foo() -> u32 {
            32
        }
    }

    impl Foo<u8> {
        pub fn foo() -> u8 {
            8
        }
    }
}

/// Public documentation of `FooBar`.
pub type FooBar = internal::Foo<u32>;

This works, in the sense that the public API just contains FooBar, but not Foo. However, it is lacking from a documentation point of view. Here's the output of cargo doc for FooBar:


Screenshot of Cargo documentation


As you can see,

  • The private type Foo appears in the documentation, but it's not a link and Foo gets no separate
  • Neither the private documentation of Foo, nor that of Foo.x is shown

As a result, this documentation is not really useful. Obviously I could add more information to the documentation of FooBar, but that still would not make the documentation of FooBar look like that of a regular struct.

With this approach, the documentation of FooBar is clearly inferior to the "equivalent" definition of FooBar like this:

/// Public documentation of `FooBar`.
pub struct FooBar {
    /// Public documentation of `x`.
    x: u32,
}

I've put "equivalent" into quotes because I do assume that from the compiler's point of view (and obviously that of cargo doc), these two definitions of FooBar are quite different. My issue is that readers of my documentation should not have to care about that difference.

Is there a way to achieve the "natural" documentation in this situation?

I'm happy to use a completely different approach for hiding the generic Foo definition if that's necessary.

Florian Brucker
  • 9,621
  • 3
  • 48
  • 81
  • that why I disagree about this trick, Rust pub visibility rules are not perfect, you use a trick to give user a public type but it's a private type, that wrong, your type should be all pub to start with if user are expected to need a doc for it. Tl;DR: semver trick sux and hurt user, just make pub item pub as they should be – Stargateur Dec 04 '21 at 18:02
  • Does this answer your question? [How to generate documentation for private items](https://stackoverflow.com/questions/52136276/how-to-generate-documentation-for-private-items) – Stargateur Dec 04 '21 at 18:04
  • @Stargateur: As I've said, I'm open to completely different approaches. However, note that the types in my real use case are significantly more complex, so reducing boilerplate and code duplication is important to me. – Florian Brucker Dec 04 '21 at 20:29
  • @Stargateur: Also, thanks for the suggested duplicate. I don't think it matches my question, since I'm trying to document a *public* type. – Florian Brucker Dec 04 '21 at 20:30
  • 1
    In the given example, field `x` is private—so why do you want it to appear in the documentation? – eggyal Dec 04 '21 at 20:33
  • @eggyal: That was an error in the code I posted, I've corrected it to make `x` public. That doesn't change the output of `cargo doc`. Thanks for pointing it out! – Florian Brucker Dec 04 '21 at 20:40
  • @FlorianBrucker Rust is a verbose language. – Stargateur Dec 04 '21 at 21:09
  • @FlorianBrucker "since I'm trying to document a public type" no you are not, that as I said, the trick you use is bad, it's neither a public neither a private item, it's a private type leak, as I say I would prefer such code don't compile. I'm not 100% sure but I believe if you use document private item you will see the documentation thus answering your question – Stargateur Dec 04 '21 at 21:11

1 Answers1

0

You can use #[cfg(doc)] to fake the item:

#[cfg(not(doc))]
pub type FooBar = internal::Foo<u32>;
#[cfg(doc)]
/// Public documentation of `FooBar`.
pub struct FooBar {
    /// Public documentation of `x`.
    pub x: u32,
}

But this will hide all impls (unless you'll copy them too) and duplicate code. So, don't do that.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77