With "default" constructors, it can be useful to document what the… defaults are. If this is textually defined in the doc and separately defined as a literal or a static / const, the two can get out of sync:
impl Foo {
/// Creates a [Foo] with a `bar` of 3.
fn new() -> Foo { Foo::new_with_bar(5) }
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo { Foo { bar } }
}
It's possible to extract the literal to a const or static and link to that, but then the reader has to go through the indirection to know what the value is, and the const / static has to be pub
or cargo doc
complains and refuses to link to it.
Is there any way to substitute the const value in the docstring instead of linking to it? Or some other method which would avoid the indirection? aka
const DEFAULT_BAR: usize = 5
impl Foo {
/// Creates a [Foo] with a `bar` of ???DEFAULT_BAR???.
fn new() -> Foo { Foo::new_with_bar(DEFAULT_BAR) }
}
should be rendered as:
pub fn new() -> Foo
Creates a Foo with a
bar
of 5.
Although similar, How to embed a Rust macro variable into documentation? doesn't seem to apply here. [doc]
complains about an unexpected token when given a name as a parameter (even a const str) and I don't know if a wrapping macro can force the substitution of a const.
On stable there isn't really an easy solution to doing this, without requiring a specialized macro for each type/method. So the easiest is to fallback to using a const DEFAULT_BAR
and referencing it in the docs (which you wanted to avoid.)
However, there's a rather new nightly feature extended_key_value_attributes
(see issue #78835 and PR 78837.)
Besides requiring one of the latest nightly builds. It will also be slightly cumbersome to use for your use case (in its current state). This is because it either requires the use of literals, which excludes using const DEFAULT_BAR
. Alternatively, you can use a macro which expands to 5
, which is the cumbersome solution.
#![feature(extended_key_value_attributes)]
struct Foo {
bar: usize,
}
macro_rules! default_bar {
() => {
5
};
}
impl Foo {
/// Creates a [Foo] with a `bar` of
#[doc = concat!(default_bar!(), ".")]
fn new() -> Foo {
Foo::new_with_bar(default_bar!())
}
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo {
Foo { bar }
}
}
The above works on rustc 1.50.0-nightly (bb1fbbf84 2020-12-22)
Note that you have to use concat!
, as otherwise default_bar
needs to expand into a string. So if you don't need e.g. "."
, then just use an empty string, e.g. concat!("", default_bar!())
.
This works in Rust 1.47:
struct Foo { bar: usize }
macro_rules! impl_foo {
($bar_def:expr) => { impl_foo!(@ $bar_def, stringify!($bar_def)); };
(@ $bar_def:expr, $bar_def_str:expr) => {
impl Foo {
/// Creates a [Foo] with a `bar` of
#[doc = $bar_def_str]
///.
fn new() -> Foo { Foo::new_with_bar($bar_def) }
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo { Foo { bar } }
}
}
}
impl_foo!(3);
You can use the paste to avoid the redirection:
use paste::paste;
struct Foo { bar: usize }
macro_rules! impl_foo {
($bar_def:expr) => {
paste! {
impl Foo {
#[doc = "Creates a [Foo] with a `bar` of " $bar_def "."]
fn new() -> Foo { Foo::new_with_bar($bar_def) }
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo { Foo { bar } }
}
}
}
}
impl_foo!(3);
In the future, you'll be able to skip the re-direction in the macro (or the usage of paste!
) by using #![feature(extended_key_value_attributes)]
, as described in vallentin's answer.
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With