Prevent access to dependencies in examples in Rust project?

Viewed 58

I am making a library in rust, and I learned that I could put example usages of the library in an examples directory in the root directory and then run them with cargo run --example hello. However, I noticed that the dependencies I specify in Cargo.toml are also available in the example code. This is a bit odd to me. These dependencies belong to the library and the user shouldn't be aware of them and certainly not use them himself (unless he happens to depend on them too, I guess).

For example, I have nalgebra = "0.31.0" in Cargo.toml and use it as a backend for vectors and matrices and other mathematical operations.

I created my own wrappers for vectors and matrices, so the user shouldn't access nalgebra types directly. I find it weird that when writing examples for the library, I can write use nalgebra as na; and use it without any issues. I guess it's helpful for debugging purposes, but when writing a complete example, this code shouldn't compile.

Is there a way to generate compiler errors when trying to use dependencies in example code, or is it simply my responsibility to write examples that reflect actual usage of the library?

1 Answers

is it simply my responsibility to write examples that reflect actual usage of the library?

Yes.

This comes up in other situations too: as long as you're writing code inside a single Cargo package, all that code shares a common set of dependencies (with the exception that [dev-dependencies] are not available to lib and bin targets, only test, example, and bench targets).

If you want a different set of dependencies, the only option is to split the example(s) into a separate package (which can be in a workspace with the library package). In my experience, it's somewhat common for Rust projects to have a separate package for examples, particularly when those examples have shared code; for example, a graphics library whose examples need window-management code might have structure like

Cargo.toml          # workspace declaration
the-library/
    Cargo.toml
    src/
        lib.rs
examples/
    Cargo.toml      # has a `{ path = "../the-library" }` dependency
    src/
        lib.rs      # contains setup code the examples use
    examples/
        ex1.rs
        ex2.rs

There is a disadvantage to doing this: your examples won't be included in the package uploaded to the registry, and the new rustdoc feature that shows snippets of examples in the docs of functions that they use, won't find these examples.


However, if your only concern is “the examples shouldn't refer to this library”, then probably the best option is to take care writing the examples.

You can also use clippy to check for unwanted mentions of functions or types, with the disallowed_methods and disallowed_types lints. However, the lists of disallowed items are package-wide configuration, so you'd have to specifically disable the lint inside your library so that clippy doesn't warn on those uses of the dependency.

Related