Before arriving at this page, you’ve likely visited crates.io multiple times to explore your favorite crates. Have you ever pondered how crate documentations are constructed? Do developers manually craft all the HTML tags and designs? Let’s delve into these questions.
First things first, what is the difference between a binary crate and a library crate?
At a surface level, a binary crate typically includes an entry point, main.rs
, and when compiled, it produces an executable file that can be run. On the other hand, a library crate contains lib.rs
, which is used to create code that can be utilized by others. However, does this mean a crate can't be both a binary and a library at the same time? Well, no. A crate can indeed contain both lib.rs
and main.rs
simultaneously.
In the blog, we will develop a library (crate) designed to split a string based on a specified splitting factor.
execute the following command in your preferred code editor’s terminal:
crago new --lib strsplit
This command will create a new Rust library project named “StrSplit” using Cargo, the Rust package manager.
this is how your file structure would look like, with some function and test already written by cargo
Now run this command
cargo run
Have you encountered an error stating “a bin target must be available for cargo run
"? This error indicates that the Cargo tool requires a binary target to execute your code using cargo run
. If you're unable to run your code, how can you verify if it's functioning correctly? You can test your code using cargo test
.
now if you run
cargo test
And as expected you will see some output regarding your test, so far so good.
Currently, our goal is to develop a library that allows users to split a provided string based on a specified splitting factor. We understand the objective, but where should we commence? Our initial step should involve writing test cases.
#[cfg(test)]
mod test{
use super::*;
#[test]
fn test(){
// crate a new instance of StrSplit
let mut str_split = StrSplit::new("a b c d e f"," ");
// split the instance by the given factor
let str_split = str_split.split();
assert_eq!(vec!["a", "b", "c", "d", "e", "f"],str_split)
}
}
Now we have written the test case and we know what should be output of the functions.
Now lets create the struct to Hold the data .
//! This is Simple Yet effective crate for splitting screen
/// strSplit is the struct to create new instances of str split
/// it takes two arguments , original string and string split param
/// # Examples
///
/// let str_split = StrSplit::new("a b c d e f"," "); /// ```
pub struct StrSplit<'a>{ reminder: &'a str, split: &'a str, }
impl<'a> StrSplit<'a> {
pub fn new(reminder: &'a str,split: &'a str,)->Self{ todo!() }
pub fn split(&mut self)->Vec<&str>{ self.reminder.split(self.split).collect() } }
Upon adding documentation comments using three forward slashes (///), along with an example demonstrating how to create a new instance of the object, running `cargo doc - open` will direct you to a web page containing detailed documentation for your crate.notice -There are two doc comments: `///` and `//!`. `///` documents the item following it whereas `//!` documents the **parent** item. Example
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1736330240869/e5d20661-4cd6-4054-bad5-f1c3b5874ab8.webp align="center")
We will enhance our documentation by adding comments at the function implementation level as well. These comments will describe the functions in detail, ensuring that the generated documentation comprehensively covers both the `StrSplit` struct and its associated implementations.
```rust
/// strSplit is the struct to create new instances of str split
/// it takes two arguments , original string and string split param
/// # Examples
///
/// let str_split = StrSplit::new("a b c d e f"," "); /// ```
pub struct StrSplit<'a>{ reminder: &'a str, split: &'a str, }
impl<'a> StrSplit<'a> {
/// create a new instance.
/// # Arguments
///
/// reminder
- original string reference.
/// split
- splitting factor.
///
/// # Returns
///
/// A new instance of StrSplit
///
/// # Examples
///
/// /// let str_split = StrSplit::new("a b c d e f"," ");
///
///
pub fn new(reminder: &'a str,split: &'a str,)->Self{
todo!()
}
/// split the string based on splitting factor
///
/// # Returns
///
/// /// Vec<&'a str>
///
///
/// # Examples
///
/// /// let str_split = StrSplit::new("a b c d e f"," ").split();
/// assert_eq!(vec!["a", "b", "c", "d", "e", "f"],str_split)
///
///
pub fn split(&mut self)->Vec<&str>{
todo!() } }
In the documentation above the `StrSplit::new` function, three additional sections have been added: `# Arguments`, which describes the function's arguments; `# Returns`, which explains the return type of the function; and `# Examples`, featuring a small code example demonstrating the usage of the function.
After adding these additional sections to the documentation above the `StrSplit::new` function, running `cargo doc - open` again will generate a refreshed document that includes detailed descriptions of the functions, arguments, return types, and examples, providing comprehensive documentation for your crate.
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1736330303675/5b67218c-a718-4852-9250-b16ba60e3257.webp align="center")
Some extra takeaways
It’s possible that you want a code example to be compiled but not run ,You can tell **rustdoc** by adding **no\_run** to your block:
```rust
/// Example
///
/// ```no_run
/// use std::fs::File;
///
/// let mut f = File::open("some_file.txt").expect("failed");
///
To ensure that you haven’t missed documenting any public items in your crate, you can utilize the lints provided by rustdoc, specifically `missing_docs` and `missing_doc_code_examples`. By default, these lints are allowed, meaning they won't be triggered unless explicitly activated
```rust
#![warn(missing_docs)]
#![warn(missing_doc_code_examples)]Absolutely, there are indeed many more features and options available in rustdoc to enhance the documentation of your Rust code further. These include sections for describing the purpose, usage, and examples of your crate, as well as providing information on types, traits, functions, and more. Additionally, rustdoc supports markdown formatting, allowing you to create rich and well-formatted documentation.
Exploring these additional features and options can greatly improve the readability and usability of your crate's documentation, making it easier for users to understand and utilize your code effectively. It's a good idea to delve deeper into rustdoc's capabilities as you continue to work on your Rust projects.
Absolutely, there are indeed many more features and options available in rustdoc to enhance the documentation of your Rust code further. These include sections for describing the purpose, usage, and examples of your crate, as well as providing information on types, traits, functions, and more. Additionally, rustdoc supports markdown formatting, allowing you to create rich and well-formatted documentation.
Exploring these additional features and options can greatly improve the readability and usability of your crate’s documentation, making it easier for users to understand and utilize your code effectively. It’s a good idea to delve deeper into rustdoc’s capabilities as you continue to work on your Rust projects.
If you’re looking for more information and references on Rust documentation with rustdoc, here are some helpful resources: