The Rust programming language has been gaining more supporters in the developer community thanks to its focus on performance, safety, concurrency, and a rich ecosystem of libraries.
In this blog post, we offer a concise overview of some noteworthy Rust libraries, selected based on their functionality and popularity among developers.
What is a Rust library?
In Rust, a library, commonly termed as a “crate,” provides precompiled routines (functions), scripts, and modules, allowing programmers to avoid redundant implementations. There are two primary types of crates: Binary and Library. The default prefix for a library is “lib.” You can change it by writing specific attributes or compiler options.
For a Binary crate, Cargo automatically generates a Cargo.toml file when creating a new project. The main entry point for this Binary crate is located at src/main.rs. In the case of a Library crate, the root is found in src/lib.rs within its corresponding package.
How to use a Rust library?
Using a Rust library involves the following steps:
- Choosing a library
First, identify the library that you want to use. You can search for Rust libraries on crates.io, which is the official crate registry for Rust.
- Add dependency to
Cargo.toml
Once you’ve identified the crate, add it to your project by including it in the [dependencies]
section of your Cargo.toml
file, for instance:
[dependencies]
serde = “1.0”
You can use semver notation to specify a version range. See Cargo documentation for more information.
- Fetch and compile dependency
When you run cargo build
or cargo run
, Cargo, Rust’s package manager, will fetch the crate and its dependencies from crates.io and compile them as part of your project.
- Use the library in your code
After adding the dependency, you can use the library in your Rust code by bringing it into scope with the use
keyword. For instance:
use serde::{Serialize, Deserialize};
- Consult the documentation
Each crate typically has its own documentation that provides information about how to use its functionality. You can often find this documentation linked from the crate’s page on crates.io or by searching for the crate’s name followed by “Rust docs” in a search engine.
- Update the library
Over time, libraries may receive updates that offer new features, bug fixes, or security patches. You can update a library by changing its version in Cargo.toml
and running cargo update
. Cargo will then resolve the latest compatible version and update your Cargo.lock
file accordingly.
Are Rust libraries cross-platform?
Rust libraries often aim to be cross-platform, with the language emphasizing cross-platform compatibility. However, a library’s cross-platform nature depends on its purpose, dependencies, any platform-specific features it might have, and how regularly it’s tested across platforms. While Rust’s standard library supports a consistent API across systems, it also contains platform-specific modules. In practice, many Rust libraries are cross-platform, but it’s essential to consult a library’s documentation and repository for specific platform support details.
Is Rust memory-safe?
Rust is designed for memory safety. Yet, it also includes an ‘unsafe’ programming feature, highlighted by the unsafe
keyword. When you see unsafe
, it indicates that developers and reviewers need to manually check that the code follows certain contracts. Not doing so can result in memory vulnerabilities and crashes in those specific sections.
Now that we’re done with the basics, let’s explore some of the most popular Rust libraries that can help you in your work.
5 most popular Rust libraries
In this section, we introduce libraries with the highest number of downloads and the most helpful features, in our opinion. Further sections also contain popular crates, but we have included some that may be less popular but are worth paying attention to due to their functionality.
Serde
Serde is the crate for data serialization and deserialization, and the name is actually composed of the initial letters of these two words. It’s very popular, with more than 216 million downloads and more than 270 versions, so you’re likely to find assistance with almost any issue. Data formats supported by Serde include JSON, YAML, TOML, Pickle, BSON, and much more. Additionally, Serde offers a derive macro that allows you to automatically generate serialization methods for structs within your application. It can produce implementations for a majority of structs and enums, even those with complex generic types or trait limitations.
Lazy_static
Lazy_static is the crate for lazy static data initialization. Static variables in Rust are normally initialized at compile time, but there are cases where you might want to initialize them at runtime (e.g. if you want to do runtime computations during initialization). They also ensure that the initialization only happens once. The lazy_static macro provides a way to handle this.
Lazy_static offers several advantages when working with static variables in Rust. Firstly, it employs “Lazy Initialization.” This means that the static variable is only initialized when accessed for the first time. Such an approach can boost performance and sidestep potential issues related to initialization order. Secondly, it guarantees “Thread Safety.” If multiple threads attempt to access the variable simultaneously during the initialization phase, lazy_static ensures that the variable is initialized just once, preventing any race conditions or redundant operations.
Thiserror
Thiserror is a utility crate in Rust designed to streamline the creation of custom error types. It complements the std::error::Error
trait from Rust’s standard library by eliminating the need for repetitive boilerplate code. With thiserror
, developers can effortlessly derive the Error
trait for their custom error types. For instance, consider the a enum representing various error types. Using the #[error(...)]
attribute, you can define how each error variant is displayed, and thiserror
will derive std::fmt::Display
and std::error::Error
trait implementations automatically. It is also possible to use the #[from]
attribute to automatically derive std::convert::From
implementation. For example:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum DataStoreError {
#[error("data store disconnected")]
Disconnect(#[from] io::Error),
#[error("the data for key `{0}` is not available")]
Redaction(String),
#[error("invalid header (expected {expected:?}, found {found:?})")]
InvalidHeader {
expected: String,
found: String,
},
#[error("unknown data store error")]
Unknown,
}
In essence, thiserror
enhances error handling and reporting, making it more concise and user-friendly in Rust applications.
Itertools
Itertools is a Rust crate that provides additional iterator traits, functions, and adaptors extending the capabilities of Rust’s standard iterators. It offers utility functions that allow for more complex and specialized iterator operations that aren’t available in the standard library, for example, interleave
, unique
, batching
, and group_by
. Beyond these, itertools
also offers special iterator adaptors such as multi_peel
, tuple_combinations
, and kmerge
. In a sense, itertools is to Rust what itertools (the module with the same name) is to Python, in that both provide a set of utilities that make it easier to work with iterators in their respective languages.
Anyhow
The Anyhow crate in Rust streamlines error handling. The best way to describe what anyhow
does is by comparing it with dyn Error
. dyn Error
is a vanilla “unified error type,” but it has to be boxed as a dyn
type. This can make it somewhat cumbersome to work with, and it’s represented using a “fat pointer,” which occupies twice the memory size of a regular pointer. Anyhow
errors don’t need to be boxed and sidestep the “fat pointer” issue. Additionally, anyhow
has utilities for enriching errors with context information. So whenever you want to use dyn Error
, Anyhow
is a better alternative.
Scientific Rust libraries
From geospatial calculations to bioinformatics solutions, these Rust libraries can help researchers in a variety of tasks.
Geo
With more than 120k downloads per month, the geo crate offers geospatial types like Point, LineString, and Polygon, and includes various operations: area calculation, distance measurement, and affine transformations. Additional functionalities encompass coordinate transformations, serialization to GeoJSON and WKT, geocoding, and GPS data handling. Contributions to the library can be licensed under either the Apache License, Version 2.0 or the MIT license.
Rust-bio
The Rust-bio library offers algorithmic and data structural solutions for bioinformatics. All features undergo thorough testing via continuous integration. For those contributing, it’s recommended to use the pre-commit tool to ensure code quality. There are two ways to submit pull requests: one-time contributors can fork and submit changes, while frequent contributors can join the rust-bio team by introducing themselves on Discord and then push changes directly. You are required to provide documentation for every public function/module, specifying content and format. The library currently supports Rust version 1.64.0 and is licensed under the MIT license.
Audio and sound
The libraries in this section will streamline audio and sound software development.
Hound
Hound is a Rust-based library for encoding and decoding in the WAV audio format, commonly used for raw, uncompressed audio. It was developed primarily to test Claxon, another Rust library for FLAC decoding. Hound operates under the Apache 2.0 license and can be used in both open-source and closed-source projects, whether commercial or not. For integration into GPLv2-licensed software, you can add an exception to their copyright notice.
CPAL
CPAL (Cross-Platform Audio Library) is a low-level audio input and output library written in pure Rust. Key features include enumerating audio hosts, identifying available audio devices, determining default input/output devices, and managing PCM streams. Supported hosts currently encompass Linux (through ALSA or JACK), Windows (primarily WASAPI), macOS and iOS (both via CoreAudio), Android (via Oboe), and Emscripten. Linux users need the ALSA development files from libasound2-dev or alsa-lib-devel packages.
Symphonia
Symphonia is a Rust-based multimedia library specializing in demuxing, tag reading, and audio decoding. It supports decoding popular audio codecs with gapless playback, demuxing prevalent media containers, reading most tagging formats, and has an efficient system for manipulating audio data. Symphonia prioritizes 100% Rust safety and speed without sacrificing performance, and has minimal dependencies. Future enhancements include creating C and WASM APIs for diverse integrations. Symphonia uses separate crates for different audio codecs and media formats. By default, it supports only royalty-free open standard codecs, but others can be enabled using feature flags. To describe the reliability and completeness of the library it is categorized as “Good,” “Great,” or “Excellent”. A “Great” status denotes that the feature is largely developed, while “Excellent” confirms it meets or exceeds reference standards.
Cryptography
The following crates provide functionalities related to cryptographic operations and concepts in the Rust programming language. These operations are fundamental for various security-related tasks, such as hashing, digital signatures, key generation and management, etc.
Rustls
Rustls is a TLS library developed in Rust. It’s used in various production environments, and although its API is mostly stable, it’s subject to change. Designed for optimal cryptographic security, Rustls requires no configuration and omits unsafe or outdated cryptographic practices by default.
Its key features include:
- Support for TLS1.2 and TLS1.3 protocols.
- Various server authentication methods, including ECDSA, Ed25519, and RSA.
- Forward secrecy facilitated by curve25519, nistp256, and nistp384.
- Encryption techniques, such as AES128-GCM, AES256-GCM, and ChaCha20-Poly1305.
- ALPN, SNI, session resumption, 0-RTT data, client authentication, extended master secret, exporters, and OCSP stapling.
Ring
Ring is a cryptographic library in Rust, C, and assembly language, designed to facilitate user-friendly and secure operations. It easily integrates with applications, with a special focus on optimization for small IoT devices. Derived from BoringSSL, Ring regularly receives updates and actively contributes to the development of that library. Given its platform-specific nature, it is recommended to run benchmarks on your target devices from the repository’s benches folder. The library is compatible with recent Rust releases. Comprehensive documentation is available here, and for building, you can refer to BUILDING.md.
Digest
Digest is a base library for implementing specific cryptographic hash functions on top of. Since it doesn’t provide any implementations, you need crates providing specific hash implementations, such assha1
, sha2
, sha3
, hmac
, pbkdf2
, blake2
, blake3
. It requires a minimum Rust version of 1.57. While this may change in the future, you can always tell when this change has occurred by looking at the library’s version number, specifically the minor version component. According to its Semantic Versioning policy, the library includes default features but does not impose version requirements on the minimum Rust version. You can license under either the Apache License, Version 2.0 or the MIT license. Contributions are assumed to be dual-licensed under these terms unless stated otherwise by the contributor.
Signature
Signature depends on Digest and contains traits that provide generic, object-safe interfaces for both creating and authenticating digital signatures. Libraries using this crate provide specific signature implementations, which include ed25519
, ecdsa
, rsa
, pgp
and others. This crate was developed over years to offer a user-friendly approach to digital signatures. It emphasizes ease-of-use and flexibility but has made some tradeoffs, like limiting signature representations. While there are suggestions to improve it for those implementing the traits, these changes could complicate things for users. Future updates might consider balancing both user and developer needs, but current challenges include technical complexities and design limitations.
Openssl
The openssl crate provides Rust bindings that encompass a wide range of OpenSSL versions, spanning from 1.0.1 to 3.x.x, as well as compatibility with LibreSSL versions from 2.5 to 3.7.x. Currently, the recommended release versions are 0.10 for openssl and 0.9 for openssl-sys. Major updates are typically released annually, and the previous version continues to receive bug fixes for a period of three months following the new release. For building, users can choose the “vendored” feature for a static link to OpenSSL or use the “automatic” method which detects existing OpenSSL installations. Contributions to the crate are typically dual-licensed under the Apache and MIT licenses unless stated otherwise by the contributor.
Date and time
Time and date Rust crates are used for handling, manipulating, and formatting dates, times, and timestamps in Rust programs.
Chrono
Chrono, a date and time library for Rust, provides a solution for managing dates and times within the proleptic Gregorian calendar. It offers strftime-inspired flexible parsing and formatting. Its features include alloc
, std
, clock
, and wasmbind
, with optional extensions such as serde
and rkyv
. To keep the core library lightweight, timezone data isn’t included by default. However, you can easily incorporate Chrono-TZ or tzfile for this pupose. Comprehensive documentation is accessible on docs.rs.
Among its few limitations are exclusive support for the proleptic Gregorian calendar, date range constraints of +/- 262,000 years from the standard epoch, and nanosecond precision for time. It does handle lead seconds either. The Minimum Supported Rust Version (MSRV) is Rust 1.57.0.
Time
Time is a date and time library for Rust. It is written to be easy, safe, space and time efficient. It supports integration with serde
, has a rich support for const
(i.e. compile-time) computations, no-std
support and includes numeric traits to simplify specifying durations (e.g. 2.seconds()
).
Miscellaneous
Below, we present libraries for managing temporary files, handling URLs, making HTTP requests, and using regular expressions.
Tempfile
The “tempfile” library aids in managing temporary files and directories. To create temporary files, it is recommended to use the tempfile()
function, and for temporary directories, you should opt for the tempdir()
function. The library provides multiple methods for creating temporary entities. The tempfile()
function delegates the task of removing the temporary file to the operating system when it’s no longer needed. On the other hand, the TempDir
and NamedTempFile
methods rely on Rust’s destructors to handle cleanup.
In most scenarios, using tempfile()
suffices unless there is a specific requirement to access the file’s path or retain it for extended periods. It’s important to note a security consideration: in environments with aggressive temporary file cleaners, relying solely on file paths can be risky. This is because such cleaners might unintentionally remove a temporary file, potentially creating an opportunity for attackers to exploit and replace the file. In contrast, tempfile()
doesn’t depend on file paths, making it a safer option in this context. However,NamedTempFile
does rely on file paths for certain operations.
Url
The url crate for Rust is a library that provides tools for parsing and manipulating URLs, aligning with the WHATWG URL Living Standard. It offers a comprehensive URL type, Url
, that makes it easy to read, write, and manipulate components of URLs, such as the scheme, domain, path, and query string. The crate ensures URL validity, performs automatic percent-encoding of specific URL components, and supports relative URL resolution and normalization.
Reqwest
Reqwest is a widely-used Rust crate that offers a high-level HTTP client, simplifying interactions with web services. Built atop the hyper
library, it provides a user-friendly API for dispatching and receiving HTTP requests. Notably, it supports Rust’s async/await
for non-blocking tasks, seamlessly integrates JSON serialization with the serde
crate, ensures secure connections via rustls
or native-tls
, and manages cookies efficiently. Its comprehensive features and ease of use, make reqwest a preferred choice for Rust developers interfacing with web APIs.
Regex
The regex crate provides tools for working with regular expressions, allowing for efficient text processing. To use it, you need to include it in your Cargo.toml file. With the regex crate, you can match strings against patterns, search within strings, split them based on patterns, or replace portions of them. For instance, you can create patterns to match date formats or extract parts of a string using capturing groups. Moreover, it’s possible to iterate over all matches in a string or replace matched patterns with specified text. This library offers an extensive API, making it an essential tool for text manipulation tasks in Rust.
Conclusion
You can leverage Rust’s performance benefits for tasks in various fields, from fintech and biomedicine to machine learning and business intelligence. Rust is widely used in fault-tolerant software, especially for production-ready systems and performance-critical components. Check out this crash course to become a Rust programmer:
We also invite you to discover Serokell’s expert Rust development solutions.