mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-06-15 13:04:18 -06:00
277 lines
11 KiB
Markdown
277 lines
11 KiB
Markdown
# Publishing a Crate to Crates.io
|
|
We have used packages form [crates.io](http://crates.io) as dependencies of our pojects.
|
|
|
|
You could also share your code with others by publishing your own packages.
|
|
|
|
The crate regsitry at [crates.io](http://crates.io) distributes the source code of your packages, it primarily hosts code that is open source.
|
|
|
|
Rust and Cargo have features that make your published package easier for people to find and use.
|
|
|
|
These features will be covered later and then explaining how to publish a package
|
|
|
|
## Making Useful Documentation Comments
|
|
Accurately documenting your packages will others know how and when to use them.
|
|
|
|
It is worth investing the time to write documentation
|
|
|
|
In ch we said that to comment in Rust you use two slashes, `//`
|
|
|
|
Rust also has a pariticualr kind of comment for documentation.
|
|
|
|
This is known conveniently as a *documentation comments*, that will generate HTML documentation.
|
|
|
|
The HTML diesplays the contents of documentation comments for public API items intended for programmers interested in knowing how to use your crate as opposed to how your crate is *implemented*.
|
|
|
|
The documentation comments uses three slashes `///` instead of two and this supports Markdown notation for formatting the text.
|
|
|
|
The placement of documentation comments just before the item they are documenting.
|
|
|
|
Here is an example of documentation comments for an `add_one` function in a crate named `my_crate`.
|
|
```rust
|
|
/// Adds one to the number given.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// let arg = 5;
|
|
/// let answer = my_crate::add_one(arg);
|
|
///
|
|
/// assert_eq!(6, answer);
|
|
/// ```
|
|
pub fn add_one(x: i32) -> i32 {
|
|
x + 1
|
|
}
|
|
```
|
|
|
|
Here we first give a description of what the `add_one` function does.
|
|
|
|
Then we add a section starting with the heading `Examples`, and then provide code that demonstrates how to use the `add_one` function.
|
|
|
|
We can generate te HTML documentation from this documentation comment by running `cargo doc`.
|
|
|
|
This command runs the `rsutdoc` tool which comes distributed with Rust and pts the generated HTML documentation in the *target/doc* directory.
|
|
|
|
For convenience running `cargo doc --open` will build the HTML for your current crate's documentation as well as the documentation for all of your crate's dependencies then it will open the result in a web browser.
|
|
|
|
Navigating to the `add_one` function you will see how the texxt in the documentation comments is rendered as shown below
|
|
<img src="https://doc.rust-lang.org/book/img/trpl14-01.png" />
|
|
|
|
### Commonly Used Sections
|
|
We previously used the `# Examples` Markdown heading to create a section in the HTML with the titl "Examples".
|
|
|
|
Here are some other secions that crate author commonly use in the documentation
|
|
- **Panics**: The scenarios in which the function being documented could panic.
|
|
Funtion callers who don't want thier programs to panic should make sure they dont call the function in this way/situation
|
|
- **Errors**: If the function returns a `Result`, that describes the kinds of errors that may occur and what conditions might cause those errors to be returned.
|
|
This can be helpful to caller so that they can write code to handle different kinds of errors in different ways.
|
|
- **Safety**: If the function is inheritly `unsafe` to call, there should be a section explaing why the function is unsafe and covering the invariants that the function expects callers to uphold.
|
|
|
|
Most documentation comments don't need all of these sctions but this is a good checklist ot remind you of the aspects of your code users will be interested in knowing.
|
|
|
|
### Documentation Comments as Tests
|
|
Adding example code blocks in your documentation comments can help demonstrate how to use the library.
|
|
|
|
Doing so also has an addtional bonus: running `cargo test` will run the code examples in your documentation as tests
|
|
|
|
This ensures that your examples will be tested to work, because that would be the worst to ship an example that doesn't work.
|
|
|
|
If we run `cargo test` with the documentation for `add_one` function we would get this output
|
|
```
|
|
Doc-tests my_crate
|
|
|
|
running 1 test
|
|
test src/lib.rs - add_one (line 5) ... ok
|
|
|
|
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
|
|
```
|
|
|
|
Now if we change either the function or the example so the `assert_eq!` in the example panics, then we will see that the doc tests catch that the example and the code are out of sync with each other.
|
|
|
|
### Commenting Contained Items
|
|
The style of commnet `//!` adds documentation to the item that contains the comments rather than to the items following the comments.
|
|
|
|
We typically use these doc comments inside the crate root file (src/lib.rs by convention) or inside a module to document the crate or the module as a whole.
|
|
|
|
For example, adding documentation that describes the purpose of the `my_crate` that contains the `add_one` function
|
|
|
|
We add documentation comments qith `//!` to the beginning of the *src/lib.rs* file
|
|
|
|
Here is an example of this
|
|
```rust
|
|
//! # My Crate
|
|
//!
|
|
//! `my_crate` is a collection of utilities to make performing certain
|
|
//! calculations more convenient.
|
|
|
|
/// Adds one to the number given.
|
|
// --snip--
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// let arg = 5;
|
|
/// let answer = my_crate::add_one(arg);
|
|
///
|
|
/// assert_eq!(6, answer);
|
|
/// ```
|
|
pub fn add_one(x: i32) -> i32 {
|
|
x + 1
|
|
}
|
|
```
|
|
|
|
Notice that there isn't any code after the last line that begins with `//!`
|
|
|
|
Because we started the comments with `//!` instead of `///` , this inidcates we are documenting the item that contains this comment rather than an item that follows his comment.
|
|
|
|
In this case, that item is the *src/lib.rs* file which is the crate root.
|
|
|
|
These comments describe the entire crate
|
|
|
|
When we run `cargo doc --open`, these comments will display on the front page of the documentation for `my_crate` above the list of public items in the crate
|
|
|
|
Here is what the docs would look like
|
|
<img src="https://doc.rust-lang.org/book/img/trpl14-02.png" />
|
|
|
|
Documentation comments within items are useful for describing crates and modules especially.
|
|
|
|
Use them to explain the overall purpose of the container to help your users understand the crate's organization
|
|
|
|
## Exporting a Convenient Public API with `pub use`
|
|
The structure of your public API is a major consideration when publishing a crate.
|
|
|
|
People who use your crate are less familiar with the structure than you.
|
|
|
|
They might have difficulty finding the pieces they want to use if your crate has a large moudle hierarchy
|
|
|
|
Before we covered how to make items public using the `pub` keyword and bring items into a scope iwth the `use` keyword.
|
|
|
|
The structure that makes sense to you while you are developing the crate might not be very useful or convenient for your users.
|
|
|
|
You might want to organize your structs in a heirary containing multiple levels.
|
|
|
|
The people who want to use a type you have defined deep in the hierary might have trouble finding out that tpye exists.
|
|
|
|
They might also be annoyed having to enter `use` `my_crate::some_module::another_module::UsefulType;` rather than `use` `my_crate::UsefulType;`.
|
|
|
|
The good news is that if the struct isn't convenient for others to use from another library, you dont have to rearrange your interal organization.
|
|
|
|
You can instead re-export items to make a public structure that is different form your private structure by using `pub use`.
|
|
|
|
Re-exporting takes a public item in one location and makes it public in another location as if it we defined in the other location instead
|
|
|
|
For example lets say we made a libarary named `art`
|
|
|
|
Within this library there are two modules:
|
|
- a `kinds` module containing two enums named `PrimaryColor` and `SecondaryColor`
|
|
- a `utils` module containinga function named `mix`
|
|
|
|
Here is what it would look like in *src/lib.rs*
|
|
```rust
|
|
//! # Art
|
|
//!
|
|
//! A library for modeling artistic concepts.
|
|
|
|
pub mod kinds {
|
|
/// The primary colors according to the RYB color model.
|
|
pub enum PrimaryColor {
|
|
Red,
|
|
Yellow,
|
|
Blue,
|
|
}
|
|
|
|
/// The secondary colors according to the RYB color model.
|
|
pub enum SecondaryColor {
|
|
Orange,
|
|
Green,
|
|
Purple,
|
|
}
|
|
}
|
|
|
|
pub mod utils {
|
|
use crate::kinds::*;
|
|
|
|
/// Combines two primary colors in equal amounts to create
|
|
/// a secondary color.
|
|
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
|
|
// --snip--
|
|
}
|
|
}
|
|
```
|
|
Here is what the frontpage docs generated by `cargo doc` would look like
|
|
<img src="https://doc.rust-lang.org/book/img/trpl14-03.png" />
|
|
|
|
Notice that the `PirmaryColor` and `SecondaryColor` types are't listed on the front page nor is the `mix` function.
|
|
|
|
We have to navigate to `kinds` and `utils` to see them.
|
|
|
|
Another crate that depends on this library would need `use` statements that bring items from `art` into scope. Specifying the module structure that is currently defined
|
|
|
|
Here is an example of a crate that uses the `PrimaryColor` and `mix` items form the `art` crate
|
|
```rust
|
|
use art::kinds::PrimaryColor;
|
|
use art::utils::mix;
|
|
|
|
fn main() {
|
|
let red = PrimaryColor::Red;
|
|
let yellow = PrimaryColor::Yellow;
|
|
mix(red, yellow);
|
|
}
|
|
```
|
|
The author of the code in above which uses the `art` crate had to figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the `utils` module.
|
|
|
|
The module struct of the `art` crate is more relevant to developers working on the `art` rate than to those using it.
|
|
|
|
The internal structure doesn't contain any useful info for someone trying to understand how to use the `art` crate, but rather causes confusion becasue devs who use it have to figure out where to look and must specify the module names in the `use` statements.
|
|
|
|
To remove the interal organization from the public API, we can modify the `art` crate to add `pub use` statements to re-export the items at the top level
|
|
```rust
|
|
//! # Art
|
|
//!
|
|
//! A library for modeling artistic concepts.
|
|
|
|
pub use self::kinds::PrimaryColor;
|
|
pub use self::kinds::SecondaryColor;
|
|
pub use self::utils::mix;
|
|
|
|
pub mod kinds {
|
|
// --snip--
|
|
}
|
|
|
|
pub mod utils {
|
|
// --snip--
|
|
}
|
|
```
|
|
The API docs that `cargo doc` generates for this crate will now list and link re-exprots on the front page.
|
|
|
|
This makes the `PrimaryColor` and `SecondaryColor` types and makes finding the `mix` function easier
|
|
|
|
<img src="https://doc.rust-lang.org/book/img/trpl14-04.png" />
|
|
|
|
The `art` crate users can still see the internal structure as demonstrated in the picture above.
|
|
|
|
They could also use the more convenient structure like in the example below
|
|
```rust
|
|
use art::mix;
|
|
use art::PrimaryColor;
|
|
|
|
fn main() {
|
|
// --snip--
|
|
}
|
|
```
|
|
|
|
In cases where there are many nested modules, re-exporting the types at the top level with `pub use`.
|
|
|
|
This can make a very significant difference in the experience of people who use the crate.
|
|
|
|
Another common use of `pub use` is to re-export definitions of a dependency in the current crate to make that crate's definitions part of your crate's public API.
|
|
|
|
Creating a useful public API structure is more of an art than a science.
|
|
|
|
You can iterate to find the API that works best for your users.
|
|
|
|
Choosing `pub use` gives you flexibility in how you structure your crate internally and decouples that interanl struct from what you present to your users.
|
|
|
|
Look at some of the code of crates you have used previously to see if their internal struct differs from their public API.
|
|
|
|
## Setting Up a Crates.io Account
|
|
Before being able to create |