DEV Community

Cover image for 10 Awesome Rust Crates and Resources to Learn
Tom Holloway πŸ•
Tom Holloway πŸ•

Posted on

10 Awesome Rust Crates and Resources to Learn

If you're just getting started in Rust, you might wonder what kind of packages you should be exploring and how to get started in the community. Depending on your initial use case, here are a few resources I have found to be immensely helpful in learning rust. Enjoy!

The Definitive Book

Affectionately nicknamed β€œthe book,” The Rust Programming Language will give you an overview of the language from first principles. You’ll build a few projects along the way, and by the end, you’ll have a solid grasp of the language.

https://doc.rust-lang.org/book/

All rustaceans need to make sure they read through this before they go anywhere else. It's the best guide there is on learning the language and it's practically everyone's starting point.

1. Crate: nom

nom

nom is a parser combinators library written in Rust. Its goal is to provide tools to build safe parsers without compromising the speed or memory consumption. To that end, it uses extensively Rust's strong typing and memory safety to produce fast and correct parsers, and provides functions, macros and traits to abstract most of the error prone plumbing.

I was once trying to implement a simple netflow parser and I came across nom. The ergonomics for implementing protocols is straightforward and it includes a number of helpful examples. Here's an example of a color parser!

extern crate nom;
use nom::{
  IResult,
  bytes::complete::{tag, take_while_m_n},
  combinator::map_res,
  sequence::tuple
};

#[derive(Debug,PartialEq)]
pub struct Color {
  pub red:   u8,
  pub green: u8,
  pub blue:  u8,
}

fn from_hex(input: &str) -> Result<u8, std::num::ParseIntError> {
  u8::from_str_radix(input, 16)
}

fn is_hex_digit(c: char) -> bool {
  c.is_digit(16)
}

fn hex_primary(input: &str) -> IResult<&str, u8> {
  map_res(
    take_while_m_n(2, 2, is_hex_digit),
    from_hex
  )(input)
}

fn hex_color(input: &str) -> IResult<&str, Color> {
  let (input, _) = tag("#")(input)?;
  let (input, (red, green, blue)) = tuple((hex_primary, hex_primary, hex_primary))(input)?;

  Ok((input, Color { red, green, blue }))
}

fn main() {}

#[test]
fn parse_color() {
  assert_eq!(hex_color("#2F14DF"), Ok(("", Color {
    red: 47,
    green: 20,
    blue: 223,
  })));
}

In the repository you will find parsers for just about anything from programming languages, network protocols, misc formats like gameboy roms, and text formatting. Definitely worth looking at or keeping as a bookmark.

2. Crate: Bevy Game Engine

Bevy

Bevy is an amazing game engine crate! It provides a number of fantastic out of the box tooling and features such as:

  • Cross Platform: Windows, MacOS, and Linux (with planned support for mobile and web)
  • 3D: Lights, meshes, textures, MSAA, and GLTF loading
  • Sprites: Render individual images as sprites, render from sprite sheets, and dynamically generate new sprite sheets
  • Assets: An extensible, event driven asset system that loads assets asynchronously in background threads
  • Scenes: Save ECS Worlds to human-readable scene files and load scene files into ECS Worlds
  • Plugins: All engine and app features are implemented as modular plugins
  • Sound: Load audio files as assets and play them from within systems
  • Multiple Render Backends: Vulkan, DirectX 12, and Metal (with more on the way thanks to wgpu)
  • Data Driven Shaders: Easily bind ECS components directly to shader uniforms
  • Hot Asset Reloading: Automatically reload changes to assets at runtime without recompiles or restarts
  • Events: Efficiently consume and produce Events from within ECS systems
  • Properties: Dynamically get and set component fields using a string version of their names
  • Hierarchical Transforms: Create parent-child relationships between entities that propagate Transforms down the hierarchy

The design goals are to keep things very simple for newcomers while providing a lot of flexibility for seasoned developers. The ergonomics and compilation performance is really something to marvel at!

3. Crate: rocket.rs web framework

If you need to write a web site without sacrificing type safety, flexibility, and usability - then take a look at rocket.rs. I've tried using a number of different web frameworks from including actix-web, tide, and warp. There is much debate over the ecosystem here, but I think in the end I would have to put rocket.rs in this list.

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use] extern crate rocket;

#[get("/hello/<name>/<age>")]
fn hello(name: String, age: u8) -> String {
    format!("Hello, {} year old named {}!", age, name)
}

fn main() {
    rocket::ignite().mount("/", routes![hello]).launch();
}

If you want a better overview and comparison between the different web frameworks and ergonomics check out this post by Luca Palmieri on Choosing a Rust Web Framework 2020 Edition.

4. Crate/Ecosystem: Tokio.rs

Tokio is an async runtime for the Rust programming language. There is some debate at the long term differences between the async-std but in any case, tokio is quite a powerhouse and you can't go very far without running into tokio dependencies in many rust crates.

Here is the starter for the mini redis tutorial:

use mini_redis::{client, Result};

#[tokio::main]
pub async fn main() -> Result<()> {
    // Open a connection to the mini-redis address.
    let mut client = client::connect("127.0.0.1:6379").await?;

    // Set the key "hello" with value "world"
    client.set("hello", "world".into()).await?;

    // Get key "hello"
    let result = client.get("hello").await?;

    println!("got value from the server; result={:?}", result);

    Ok(())
}

Check it out!

5. Crate serde serialization

Serde is a framework for serializing and deserializing Rust data structures into a variety of formats (complimented by things like serde-json

use serde::{Deserialize, Serialize};
use serde_json::Result;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

fn typed_example() -> Result<()> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    // Parse the string of data into a Person object. This is exactly the
    // same function as the one that produced serde_json::Value above, but
    // now we are asking it for a Person as output.
    let p: Person = serde_json::from_str(data)?;

    // Do things just like with any other Rust data structure.
    println!("Please call {} at the number {}", p.name, p.phones[0]);

    Ok(())
}

Here are a number of great examples on their documentation website!

6. Crate: hyper HTTP

hyper is a fast HTTP implementation for Rust

  • A client for talking to web services
  • A server for building those web services
  • Blazing fast thanks to Rust
  • High concurrency with non-blocking sockets
  • HTTP/1 and HTTP/2 support
use std::{convert::Infallible, net::SocketAddr};
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};

async fn handle(_: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new("Hello, World!".into()))
}

#[tokio::main]
async fn main() {
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(handle))
    });

    let server = Server::bind(&addr).serve(make_svc);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e);
    }
}

This helps if you want to get a bit more lower level than a "web framework" like warp which builds on top of hyper.

7. Crate: textwrap

If you need a small quick library that knows how to wrap text for command line utilities, take a look at this crate.

[dependencies]
textwrap = "0.12"
fn main() {
    let text = "textwrap: a small library for wrapping text.";
    println!("{}", textwrap::fill(text, 18));
}
textwrap: a small
library for
wrapping text.

8. Crate: reqwest HTTP Client

If you need a more "batteries-included" HTTP request client then take a look at reqwest. Some of the includes features:

  • Plain bodies, JSON, urlencoded, multipart
  • Customizable redirect policy
  • HTTP Proxies
  • HTTPS via system-native TLS (or optionally, rustls)
  • Cookie Store
  • WASM

Here's an example below that uses tokio.rs and the async runtime to do a simple GET request.

use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resp = reqwest::get("https://httpbin.org/ip")
        .await?
        .json::<HashMap<String, String>>()
        .await?;
    println!("{:#?}", resp);
    Ok(())
}

9. Crate: cargo edit: cargo utility

There are a number of helpful utilities you can add to the built-in cargo command. The one I like to have is cargo-edit which lets you do things like:

cargo add

$ # Add a specific version
$ cargo add regex@0.1.41 --dev
$ # Query the latest version from crates.io and adds it as build dependency
$ cargo add gcc --build
$ # Add a non-crates.io crate
$ cargo add local_experiment --path=lib/trial-and-error/
$ # Add a non-crates.io crate; the crate name will be found automatically
$ cargo add lib/trial-and-error/
$ # Add a crates.io crate with a local development path
$ cargo add my_helper --vers=1.3.1 --path=lib/my-helper/
$ # Add a renamed dependency
$ cargo add thiserror --rename error

cargo rm

$ # Remove a dependency
$ cargo rm regex
$ # Remove a development dependency
$ cargo rm regex --dev
$ # Remove a build dependency
$ cargo rm regex --build

cargo upgrade

# Upgrade all dependencies for the current crate
$ cargo upgrade
# Upgrade docopt (to ~0.9) and serde (to >=0.9,<2.0)
$ cargo upgrade docopt@~0.9 serde@>=0.9,<2.0
# Upgrade regex (to the latest version) across all crates in the workspace
$ cargo upgrade regex --workspace

Super helpful when you don't want to edit Cargo.toml

10. Crate: cargo audit: cargo utility

Cargo-audit will audit Cargo.lock files for crates with security vulnerabilities reported to the RustSec Advisory Database. Very helpful!

Cargo Audit

Conclusion

These are only a small fraction of the vast Rust community out there. If you're looking to explore more, check out these helpful Awesome Rust repositories for more!

Cheers! 🍻

--

If you liked this article, please feel free to give me a follow and a like. Also check out my twitter for more updates!

Thanks again!

Top comments (1)

Collapse
 
gklijs profile image
Gerard Klijs

Awesome, giving a rust intro next week. Of course I'll point out they should read the book fist. And the whole tokio/hyper/warp/reqwest is pretty awesome. Might mention nom a d bevy, those are new to me.