Name resolution

mdbook-rustdoc-link resolves items in the context of your crate's "entrypoint", which is usually your lib.rs or main.rs (the specific rules are mentioned below).

tip

If you use Cargo workspaces, or if your source tree has special layout, see Workspace layout for more information.

An item must be in scope in the entrypoint for the proprocessor to generate a link for it.

Let's say you have the following as your lib.rs:

use anyhow::Context;
/// Type that can provide links.
pub trait Resolver {}
mod env {
    /// Options for the preprocessor.
    pub struct Config {}
}

Items in the entrypoint can be linked to with just their names:

[`Resolver`] — Type that can provide links.

This crate also uses the [`Context`] trait from [`anyhow`].

Resolver — Type that can provide links.

This crate also uses the Context trait from anyhow.

This includes items from the prelude (unless you are using #![no_implicit_prelude]):

[`FromIterator`] is in the prelude starting from Rust 2021.

FromIterator is in the prelude starting from Rust 2021.

Though technically not required — to make items from your crate more distinguishable from others in your Markdown source, you can write crate::*:

[Configurations](configuration.md) for the preprocessor is defined in the
[`Config`][crate::env::Config] type.

Configurations for the preprocessor is defined in the Config type.

For everything else, provide its full path, as if you were writing a use declaration:

[`JoinSet`][tokio::task::JoinSet] is analogous to `asyncio.as_completed`.

JoinSet is analogous to asyncio.as_completed.

tip

In short, write links the way you use an item in your lib.rs or main.rs.

The preprocessor will emit a warning if an item cannot be resolved:

warning emitted when an item cannot be resolved

Formatting of diagnostics powered by miette

This is something to remember especially if you are including doc comments as part of your Markdown docs. Only rustdoc has the ability to resolve names from where the comments are written, so links that work in doc comments may not work when using this preprocessor!

Feature-gated items

To link to items that are gated behind features, use the cargo-features option in book.toml.

For example, clap is known for providing guide-level documentation through docs.rs. The tutorial for its Derive API is gated behind the unstable-doc feature. To link to such items, configure the necessary features:

[preprocessor.rustdoc-link]
cargo-features = ["clap/unstable-doc"]

Then, specify the item as normal:

[Tutorial for clap's Derive API][clap::_derive::_tutorial]

Tutorial for clap’s Derive API

Which entrypoint

For this preprocessor, the "entrypoint" is usually src/lib.rs or src/main.rs.

  • If your crate has multiple bin targets, it will use the first one listed in your Cargo.toml.
  • If your crate has both lib and bins, it will prefer lib.
  • If your crate has custom paths in Cargo.toml instead of the default src/lib.rs or src/main.rs, it will honor that.

How it works

note

The following are implementation details. See rustdoc_link/mod.rs.

mdbook-rustdoc-link parses your book and collects every link that looks like a Rust item. Then it synthesizes a Rust function that spells out all the items, which looks roughly like this:

fn __ded48f4d_0c4f_4950_b17d_55fd3b2a0c86__ () {
    Result::<T, E>;
    core::net::Ipv4Addr::LOCALHOST;
    std::vec!();
    serde::Serialize!();
    <Vec<()> as IntoIterator>::into_iter;
    // ...
}

Note that this is barely valid Rust — Result::<T, E>; is a type without a value, and you wouldn't use serde::Serialize as a regular macro.

This is where language servers like rust-analyzer excel — they can provide maximally useful information out of badly-shaped code.

The preprocessor appends this fake function to your lib.rs or main.rs (in memory, it doesn't modify your file) and sends it to rust-analyzer. Then, for each item that needs to be resolved, the preprocessor sends an external documentation request.

{
  "jsonrpc": "2.0",
  "method": "experimental/externalDocs",
  "params": {
    "textDocument": { "uri": "file:///src/lib.rs" },
    "position": { "line": 6, "character": 17 }
  }
}

Hence item names in your book must be resolvable from your crate entrypoint!

This process is as if you had typed a name into your source file and used the "Open Docs" feature — except it's fully automated.

the Open Docs option in VS Code