How do you document a Rust struct/enum in one documentation block before the struct? - struct

How do you document a Rust struct or enum in one documentation block before the type, so as to avoid polluting the contents with confusing mess?
This is what I do at the moment, which is really terrible.
/// Enumerates the possible jobblers in thingy paradigm.
enum MyEnum
{
/// Something is a blue exchange doodad thingy thing.
EnumValue1,
/// Something is meld mould mild mote.
EnumValueTheSecond,
/// Vivamus arcu mauris, interdum nec ultricies vitae, sagittis sit.
EnumValueGamma,
}
What I want is the style I would write it in Doxygen, which is clean and easy to read:
/** \enum MyEnum
* Enumerates the possible jobblers in thingy paradigm.
* \var MyEnum::EnumValue1
* Something is a blue exchange doodad thingy thing.
* \var MyEnum::EnumValueTheSecond
* Something is meld mould mild mote.
* \var MyEnum::EnumValueGamma
* Vivamus arcu mauris, interdum nec ultricies vitae, sagittis sit.
*/
enum MyEnum
{
EnumValue1,
EnumValueTheSecond,
EnumValueGamma,
};

This is what I do at the moment, which is really terrible.
I guess the beauty is in the eye of the beholder? It looks fine to me, the reader of the code gets to see the documentation for the corresponding item in the same place, which makes sense.
What I want is the style I would write it in Doxygen, which is clean and easy to read:
Again I guess beauty is in the eye of the beholder as I think this looks like garbage on fire, but AFAIK rustdoc does not support this (a doc-comment is just commonmark with limited extension), so you could:
ignore rustdoc's support for sub-items entirely, just document everything however you want at the toplevel item
use function-like macros and #[doc] to define your stuff in macros above the structure, then #[doc] attributes to link those, I don't think you can just #[doc = A_CONST]
How to embed a Rust macro variable into documentation? and How to concatenate a literal string with a const string? could also be useful for that purpose

How about documenting the enum values after the enum values like:
/// Enumerates the possible jobblers in thingy paradigm.
enum MyEnum
{
EnumValue1, ///< Something is a blue exchange doodad thingy thing.
EnumValueTheSecond, ///< Something is meld mould mild mote.
EnumValueGamma, ///< Vivamus arcu mauris, interdum nec ultricies vitae, sagittis sit.
}
Result with doxygen 1.9.2:
Note from the discussion in the comment: the given example works in doxygen but not in cargo doc. Doxygen does not support Rust so the code first has to be translated into something that doxygen does understand (e.g. by means of a doxygen filter). The given example in the question looks quite similar to C / C++ code.

Related

Make a one to one mapping from string to enum variant without using a match statement

I'm writing code to parse HTTP requests. I'd rather keep some things like request methods and response codes as enums because of their exhaustibility.
But it also means that for each of those enums I would have to make a From<String> implementation. The obvious way to do it is to match against a plethora of constant strings. That seems like a lot of almost identical code which I would want to factor out.
Someone suggested I use a macro to do it, but my knowledge of rust macros is limited so it made me question some things:
How can I ensure the argument is of type &str or String? Macros can take expressions, but I don't want to use type_name and panic if it doesn't match as it seems to be a very dirty fix.
How can I convert a string to a token stream? So far I've seen that the proc_macro crate offers that functionality, but is it possible to do with simple declarative macro?
Is it possible to achieve one to one mapping by any other means? I hoped I could pre-initialize enum variants with some known values like in Java.
You really want to use a library for this. You can write the macro yourself, but someone else has already made a battle-tested version of what you're trying to do.
Use strum's EnumString derive:
In Cargo.toml:
[dependencies]
strum = "0.24"
strum_macros = "0.24"
In your source code: (eg main.rs)
use std::str::FromStr;
use strum_macros::EnumString;
#[derive(Debug, EnumString)]
enum MyEnum {
Foo,
Bar,
Baz,
}
fn main() {
dbg!(MyEnum::from_str("Foo").unwrap());
}
Gives you
[src/main.rs:12] MyEnum::from_str("Foo").unwrap() = Foo
For more details see The documentation for the FromString derive and strum's readme.

How to write a doc that's incomplete / failed intentionally?

I know one of the main Rust feature is built-in documentation testing. You can write any comment like this and it will be available on generated documentation. But how do you create a comment that incomplete / cannot run ?
/// ## Foo Function
/// Lorem ipsum dolor sit amet, consectetur adipiscing elit.
/// Duis eleifend at dolor auctor maximus. Vestibulum
/// ### How to use
/// ```
/// use my_app::Item; // how to skip testing this part ?
/// Item::map_from_doc(&foo) <---- this error on test since I do not declare `foo`
/// ```
pub fn foo_func(doc: &str) -> Result<Self, ItemError> {...}
I do not want to write the entire code for foo variable. I just want to give user a simple explanation about the function usage. I think that there should be a way to skip document testing on this part.
So far I can only found about hiding parts of the code, which means that I need to write the complete example code and hide some of it. https://doc.rust-lang.org/rustdoc/documentation-tests.html
How to write a doc that's incomplete / failed intentionally ?
Down the page you linked is the Attributes section, which documents various directives you can use to configure non-standard / "abnormal" behaviour:
/// ```ignore
/// fn foo() {
/// ```
The ignore directive tells Rust to ignore your code. This is almost never what you want, as it's the most generic. Instead, consider annotating it with text if it's not code, or using #s to get a working example that only shows the part you care about.
I'm not going to copy the whole section, you can go read it, but the other useful values listed there are:
should_panic tells rustdoc that the code should compile correctly, but not actually pass as a test.
The no_run attribute will compile your code, but not run it. This is important for examples such as "Here's how to retrieve a web page," which you would want to ensure compiles, but might be run in a test environment that has no network access.
compile_fail tells rustdoc that the compilation should fail. If it compiles, then the test will fail.
edition2018 tells rustdoc that the code sample should be compiled using the 2018 edition of Rust. Similarly, you can specify edition2015 to compile the code with the 2015 edition.
In your case, ignore is probably the best attribute. Technically you could use compile_fail but you're not actually trying to demonstrate or assert a compilation failure so it feels like an over-specification to me.

Is there a way to "do macro stuff" in an attribute without a procedural macro?

Specifically, I'm trying to put macro output into a doc comment. I was excited that this does exactly what I want:
/// foo
///
#[doc="bar\n\nbaz"]
///
/// quux
struct Dummy;
The next step would be to replace that string with my content. According to this, I can't write #[doc=my_content!()], and attribute macros are procedural, so I need another crate for that, plus (I think) my content could be generated without the need for any procedural macro features.
Is there a way to do this with "conventional macros" in some way, or am I out of luck?
Edit: starting with 1.54.0, Attributes can invoke function-like macros, enabling the code proposed in the question. Original answer below :
The answer seems to be no.
Looking at the grammar for attributes, apart from parentheses, commas and equals signs, attributes can ultimately only contain literals. So on this level, there is no way Rust allows more here.
However, inverting the structure enables something like this, and the doc-comment crate does this for doc comments. Instead of calling a macro from inside an attribute, use a macro to create an attribute; that macro is then not constrained to only taking literals*. The downside is, the item that the attribute should apply to must be part of the macro call. So this
#[doc=my_content!()]
struct Foo;
becomes this:
doc_comment!(
my_content!(),
struct Foo;
);
The definition of the macro is straight-forward:
#[macro_export]
macro_rules! doc_comment {
($x:expr, $($tt:tt)*) => {
#[doc = $x]
$($tt)*
};
}
(omitted a branch of the original macro that is not part of the core pattern)
(thanks to jonas-schlevink for pointing me to this)
*except for that last part (getting macro content into the attribute), the linked question's answer already does exactly that.

Is it possible to group sections of an API with rustdoc?

Is it possible to group sections of an API? related functions, types or constants for example.
Doxygen for example supports grouping like this:
/** \name Some API Grouping
* \{ */
// code //
/* \} */
Is rustdoc capable of something similar?
No.
Would be nice, but sadly no.
Edit: As noted by Matthieu M., you can add doc comments to individual impl blocks, but that doesn't solve the general case.

Visual C++ 12 (VS2013 Preview) variadic template with function parameter workaround

I just filed this bug on Microsoft Connect regarding the inability to compile the following toy snippet of code:
template <typename... P> struct S {
template <void(*F)(P...)> static void T() { }
};
void A(int, float) { }
int main() { S<int, float>::T<&A>(); }
The error is:
test.cpp(2): error C3520: 'P' : parameter pack must be expanded in this context
Essentially, I cannot unpack a variadic type inside of a function signature when used as a template parameter. This code is (I think) legal; at least, GCC 4.7, Clang 3.0, and ICC 13 all support it.
I've seen this SO question but no workarounds are requested or given, which is what I'm looking for.
While not super critical (obviously I've been getting by without variadic templates for many years now) this pattern is of particular importance to some of the work I'd like to do and some articles I'd like to do on C++11 reflection techniques for serialization, script binding, etc. which is something I'd like to be useful to Visual Studio users (as it is by far the dominant compiler toolset in my industry). I'd like to hope that Microsoft's engineers will be able to fix this by 2013 RTM, but I'm not holding my breath.
A toy (from memory this time) sample of how this is being used is something like (minus the macros that make it slightly easier to use):
Reflect<MyType>("MyType")
.bind("GetMatrix", mat44, &MyType::GetMatrix>()
.bind("Display", void, &MyType::Display>();
Of course this can all be done without variadic templates. It just takes large masses of code and accepting limitations to the maximum arity of bound member functions, of course. And yes, passing the functions as a template parameter is of import, due to the nature of how member function pointers work in Visual Studio (variable size) and a desire to achieve efficiency on par with Impossibly Fast C++ Delegates (in my niche of the C++ community, this level of optimization can sometimes actually matter) which negates the option of using std::function or similar designs.
Is there a work-around for this VS bug? Or any other way to use variadic templates to use a (compile-time) function pointer parameter in VC++12?
Not sure why but simplifying with a typedef seems to work:
template <typename... P>
struct S
{
typedef void (*MyFunc)(P...);
template <MyFunc myFunc>
static void foo() {}
};
void foo2(int, float) {}
int main()
{
S<int, float>::foo<&foo2>();
}
At least on the Visual Studio 2013 Ultimate Preview.

Resources