[Rust](https://www.rust-lang.org/) is a statically-typed programming language known for its emphasis on performance, safety, and concurrency. Originally developed by [Mozilla](../../../internet/websites/clearnet/Mozilla.md), Rust has gained popularity for its ability to provide low-level control over system resources without sacrificing memory safety. Rust uses [Cargo](../../../applications/development/cargo.md) as its package manager and build tool.
Your application starts within the main function, so the simplest application is this:
```rust
fn main() {
}
```
### Variables
You can declare variables. Variables are immutable by default, if you need to change them you have to use the `mut` keyword. Every variable is strongly typed, but you can either ommit type information and let the compiler infer the type or explicitly state it. Constants which never change can be made as well.
```rust
let var = "Hello";
let mut mutable = "World";
let explicit_num: isize = 0;
const NINE_K: isize = 9000;
```
### Data Types & Ownership
Every variable in Rust is strongly typed. You can define your own types and use the compiler together with an algebraic type system to your advantage.
In Rust, primitive types are classified into two categories: scalar types and compound types:
One can use functions with optional arguments and return types. If you `return` on the last line, you can ommit the `return` keyword and `;` to return the value.
Rust has support for comments. There are regular comments, multiline comments and documentation comments. Documentation comments get used when generating documation via `cargo doc` and inside the IDE.
/// Documentation comments can be styled with markdown as well.
///
/// # Example
///
/// If you place a rust code block here, you can provide examples on how to use this function and `cargo test` will automatically run this code block when testing.
You can split your code up into multiple modules for better organization.
```rust
// will search for `mymod.rs` or `mymod/mod.rs` beside the source file and include it as `mymod`;
mod mymod;
// inline module
mod processor {
struct AMD {
name: String
}
}
fn main() {
// full syntax
let proc = processor::AMD{ name: "Ryzen".to_string() };
// you can put often used symbols in scope
use processor::AMD;
let proc = AMD{ name: "Ryzen".to_string() };
}
```
### Generics
Generics let you write code for multiple data types without repeating yourself. Instead of an explicit data type, you write your code around a generic type.
```rust
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// you can declare methods which only work for specific data types.
-`Add`, `Sub`, `Mul`, and `Div`: Traits for arithmetic operations.
```rust
pub trait Add<RHS=Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
// Similar traits for Sub, Mul, and Div
```
### Closures
Closures are anonymous functions. They can be assigned to variables, passed as parameters or returned from a function.
```rust
fn add_one_v1 (x: u32) -> u32 { x + 1 }
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| { x + 1 };
let add_one_v4 = |x| x + 1 ;
// this function takes ownership over variables it uses as noted by `move`
thread::spawn(
move || println!("From thread: {:?}", list)
).join().unwrap();
// To use closures as parameters, specify the type. It is one of the Fn traits
impl<T> Option<T> {
pub fn unwrap_or_else<F>(self, f: F) -> T
where
F: FnOnce() -> T
{
match self {
Some(x) => x,
None => f(),
}
}
}
```
### Iterators
The [iterator pattern](../patterns/behavioral/Iterator%20Pattern.md) allows you to perform some task on a sequence of items in turn. An iterator is responsible for the logic of iterating over each item and determining when the sequence has finished. When you use iterators, you don’t have to reimplement that logic yourself.
```rust
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
```
With this you can do functional programming with the iterators.
Some functions on them include:
-`chain(other)`: An iterator that links two iterators together, in a chain.
-`cloned()`: An iterator that clones the elements of an underlying iterator.
-`copied()`: An iterator that copies the elements of an underlying iterator.
-`cycle()`: An iterator that repeats endlessly.
-`empty()`: An iterator that yields nothing.
-`enumerate()`: An iterator that yields the current count and the element during iteration.
-`filter(predicate)`: An iterator that filters the elements of `iter` with `predicate`.
-`filterMap(f)`: An iterator that uses `f` to both filter and map elements from `iter`.
-`flat_map(f)`: An iterator that maps each element to an iterator, and yields the elements of the produced iterators.
-`flatten()`: An iterator that flattens one level of nesting in an iterator of things that can be turned into iterators.
-`from_fn(f)`: An iterator where each iteration calls the provided closure `F: FnMut() -> Option<T>`.
-`fuse()`: An iterator that yields `None` forever after the underlying iterator yields `None` once.
-`inspect(f)`: An iterator that calls a function with a reference to each element before yielding it.
-`map(f)`: An iterator that maps the values of `iter` with `f`.
-`map_while(f)`: An iterator that only accepts elements while `predicate` returns `Some(_)`.
-`once(value)`: An iterator that yields an element exactly once.
-`peekable()`: An iterator with a `peek()` that returns an optional reference to the next element.
-`repeat(value)`: An iterator that repeats an element endlessly.
-`rev()`: A double-ended iterator with the direction inverted.
-`skip(n)`: An iterator that skips over `n` elements of `iter`.
-`skip_while(f)`: An iterator that rejects elements while `predicate` returns `true`.
-`step_by(n)`: An iterator for stepping iterators by a custom amount.
-`successors(first, f)`: A new iterator where each successive item is computed based on the preceding one.
-`take(n)`: An iterator that only iterates over the first `n` iterations of `iter`.
-`take_while(f)`: An iterator that only accepts elements while `predicate` returns `true`.
-`zip(a, b)`: An iterator that iterates two other iterators simultaneously.
Rust, a systems programming language known for its focus on safety and performance, comes with a rich standard library that provides a wide range of modules to handle common tasks.
1.**`std::collections`**: Data structures like `Vec`, `HashMap`, etc.
2.**`std::fs`**: File system manipulation and I/O operations.
3.**`std::thread`**: Facilities for concurrent programming with threads.
4.**`std::time`**: Time-related types and functionality.
5.**`std::io`**: Input and output facilities.
6.**`std::path`**: Path manipulation utilities.
7.**`std::env`**: Interface to the environment, command-line arguments, etc.
20.**`std::marker`**: Marker traits for influencing Rust's type system.
## Macros
We’ve used macros like `println!` before, but we haven’t fully explored what a macro is and how it works. The term _macro_ refers to a family of features in Rust: _declarative_ macros with `macro_rules!` and three kinds of _procedural_ macros:
- Custom `#[derive]` macros that specify code added with the `derive` attribute used on structs and enums
- Attribute-like macros that define custom attributes usable on any item
- Function-like macros that look like function calls but operate on the tokens specified as their argument
Fundamentally, macros are a way of writing code that writes other code, which is known as _metaprogramming_. All of these macros _expand_ to produce more code than the code you’ve written manually.
Declarative macros work almost like a `match` statement.
```rust
macro_rules! mymacro {
($expression:expr) => {
println!("{}", $expression)
};
($expression:expr, $other:expr) => {
println!("{} {}", $expression, $other)
};
}
mymacro!("Hello World");
mymacro!("Hello", "World");
```
This macro gets expanded to the code inside the `macro_rules!` section with the provided arguments. For more information on macros, see the [docs](https://doc.rust-lang.org/reference/macros-by-example.html).
Macros work kind of like a match statement. In the matcher, `$ name : fragment-specifier` matches a Rust syntax fragment of the kind specified and binds it to the metavariable `$name`. Valid fragment specifiers are:
-`item`: an Item
-`block`: a BlockExpression
-`stmt`: a Statement without the trailing semicolon (except for item statements that require semicolons)
-`pat_param`: a PatternNoTopAlt
-`pat`: at least any PatternNoTopAlt, and possibly more depending on edition
-`expr`: an Expression
-`ty`: a Type
-`ident`: an IDENTIFIER_OR_KEYWORD or RAW_IDENTIFIER
-`path`: a TypePath style path
-`tt`: a TokenTree (a single token or tokens in matching delimiters (), [], or {})
-`meta`: an Attr, the contents of an attribute
-`lifetime`: a LIFETIME_TOKEN
-`vis`: a possibly empty Visibility qualifier
-`literal`: matches -?LiteralExpression
Common Rust Macros:
-`assert!(bool)`: Asserts that a boolean expression is true at runtime.
-`assert_eq!(a, b)`: Asserts that two expressions are equal to each other (using `PartialEq`).
-`assert_ne!(a, b)`: Asserts that two expressions are not equal to each other (using `PartialEq`).
-`debug_assert!(bool)` Asserts that a boolean expression is true at runtime.
-`debug_assert_eq!(a, b)`: Asserts that two expressions are equal to each other.
-`debug_assert_ne!(a, b)`: Asserts that two expressions are not equal to each other.
-`module_path!()`: Expands to a string that represents the current module path.
-`file!()`: Expands to the file name in which it was invoked.
-`line!()`: Expands to the line number on which it was invoked.
-`column!()`: Expands to the column number at which it was invoked.
-`concat!()`: Concatenates literals into a static string slice.
-`cfg!()`: Evaluates boolean combinations of configuration flags at compile-time.
-`compile_error!(msg)`: Causes compilation to fail with the given error message when encountered.
-`panic!()`: Panics the current thread.
-`dbg!()`: Prints and returns the value of a given expression for quick and dirty debugging.
-`env!(var)`: Inspects an environment variable at compile time.
-`option_env!(var)`: Optionally inspects an environment variable at compile time.
-`print!()`: Prints to the standard output.
-`println!()`: Prints to the standard output, with a newline.
-`eprint!()`: Prints to the standard error.
-`eprintln!()`: Prints to the standard error, with a newline.
-`format!()`: Creates a String using interpolation of runtime expressions.
-`write!()`: Writes formatted data into a buffer.
-`writeln!()`: Write formatted data into a buffer, with a newline appended.
-`include!()`: Parses a file as an expression or an item according to the context.
-`include_bytes!()`: Includes a file as a reference to a byte array.
-`include_str!()`: Includes a UTF-8 encoded file as a string.
-`matches!()`: Returns whether the given expression matches the provided pattern.
-`todo!()`: Indicates unfinished code.
-`unimplemented!()`: Indicates unimplemented code by panicking with a message of “not implemented”.
-`unreachable!()`: Indicates unreachable code.
-`vec![]`: Creates a Vec containing the arguments.
Procedural macros allow creating syntax extensions as execution of a function. Procedural macros come in one of three flavors:
- Function-like macros - `custom!(...)`
- Derive macros - `#[derive(CustomDerive)]`
- Attribute macros - `#[CustomAttribute]`
Procedural macros allow you to run code at compile time that operates over Rust syntax, both consuming and producing Rust syntax. You can sort of think of procedural macros as functions from an AST to another AST.
As functions, they must either return syntax, panic, or loop endlessly. Returned syntax either replaces or adds the syntax depending on the kind of procedural macro. Panics are caught by the compiler and are turned into a compiler error. Endless loops are not caught by the compiler which hangs the compiler.
Procedural macros have two ways of reporting errors. The first is to panic. The second is to emit a `compile_error!` macro invocation.
Procedural macros must be in their own crate. Use this `Cargo.toml` as a start:
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
```
We’ve introduced three new crates: `proc_macro`, `syn`, and `quote`. The `proc_macro` crate comes with Rust, so we didn’t need to add that to the dependencies in `Cargo.toml`. The `proc_macro` crate is the compiler’s API that allows us to read and manipulate Rust code from our code. The `syn` crate parses Rust code from a string into a data structure that we can perform operations on. The `quote` crate turns `syn` data structures back into Rust code. These crates make it much simpler to parse any sort of Rust code we might want to handle.
The `hello_macro_derive` function will be called when a user of our library specifies `#[derive(HelloMacro)]` on a type. This is possible because we’ve annotated the `hello_macro_derive` function here with `proc_macro_derive` and specified the name `HelloMacro`, which matches our trait name; this is the convention most procedural macros follow.
The `quote!` macro lets us define the Rust code that we want to return. The compiler expects something different to the direct result of the `quote!` macro’s execution, so we need to convert it to a `TokenStream`. We do this by calling the `.into()` method, which consumes this intermediate representation and returns a value of the required `TokenStream` type.
The `quote!` macro also provides some very cool templating mechanics: we can enter `#name`, and `quote!` will replace it with the value in the variable name. You can even do some repetition similar to the way regular macros work. Check out the [quote crate’s docs](https://docs.rs/quote/latest/quote/) for a thorough introduction.
#### Attribute-like macros
Attribute-like macros are similar to custom derive macros, but instead of generating code for the derive attribute, they allow you to create new attributes. They’re also more flexible: derive only works for structs and enums; attributes can be applied to other items as well, such as functions. Here’s an example of using an attribute-like macro: say you have an attribute named route that annotates functions when using a web application framework:
```rust
#[route(GET, "/")]
fn index() {}
```
This `#[route]` attribute would be defined by the framework as a procedural macro. The signature of the macro definition function would look like this:
Here, we have two parameters of type `TokenStream`. The first is for the contents of the attribute: the `GET, "/"` part. The second is the body of the item the attribute is attached to: in this case, `fn index() {}` and the rest of the function’s body.
Other than that, attribute-like macros work the same way as custom derive macros: you create a crate with the `proc-macro` crate type and implement a function that generates the code you want!
#### Function-like macros
Function-like macros define macros that look like function calls. Similarly to `macro_rules!` macros, they’re more flexible than functions; for example, they can take an unknown number of arguments. However, `macro_rules!` macros can be defined only using the match-like syntax. Function-like macros take a `TokenStream` parameter and their definition manipulates that `TokenStream` using Rust code as the other two types of procedural macros do. An example of a function-like macro is an `sql!` macro that might be called like so:
```rust
let sql = sql!(SELECT * FROM posts WHERE id=1);
```
This macro would parse the SQL statement inside it and check that it’s syntactically correct, which is much more complex processing than a `macro_rules!` macro can do. The `sql!` macro would be defined like this:
```rust
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {}
```
This definition is similar to the custom derive macro’s signature: we receive the tokens that are inside the parentheses and return the code we wanted to generate.
## Conditional Compilation
Conditionally compiled source code is source code that may or may not be considered a part of the source code depending on certain conditions. Source code can be conditionally compiled using the attributes `cfg` and `cfg_attr` and the built-in `cfg` macro. These conditions are based on the target architecture of the compiled crate, arbitrary values passed to the compiler, and a few other miscellaneous things further described below in detail.
Each form of conditional compilation takes a configuration predicate that evaluates to true or false. The predicate is one of the following:
- A configuration option. It is true if the option is set and false if it is unset.
-`all()` with a comma separated list of configuration predicates. It is false if at least one predicate is false. If there are no predicates, it is true.
-`any()` with a comma separated list of configuration predicates. It is true if at least one predicate is true. If there are no predicates, it is false.
-`not()` with a configuration predicate. It is true if its predicate is false and false if its predicate is true.
Configuration options are names and key-value pairs that are either set or unset. Names are written as a single identifier such as, for example, unix. Key-value pairs are written as an identifier, `=`, and then a string. For example, `target_arch = "x86_64"` is a configuration option.
> **Note**: For `rustc`, arbitrary-set configuration options are set using the `--cfg` flag.
The cfg attribute conditionally includes the thing it is attached to based on a configuration predicate.
If the predicate is true, the thing is rewritten to not have the cfg attribute on it. If the predicate is false, the thing is removed from the source code.
Some examples on functions:
```rust
// The function is only included in the build when compiling for macOS
#[cfg(target_os = "macos")]
fn macos_only() {
// ...
}
// This function is only included when either foo or bar is defined
#[cfg(any(foo, bar))]
fn needs_foo_or_bar() {
// ...
}
// This function is only included when compiling for a unixish OS with a 32-bit
// architecture
#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {
// ...
}
// This function is only included when foo is not defined
#[cfg(not(foo))]
fn needs_not_foo() {
// ...
}
// This function is only included when the panic strategy is set to unwind
#[cfg(panic = "unwind")]
fn when_unwinding() {
// ...
}
```
The `cfg_attr` attribute conditionally includes attributes based on a configuration predicate.
When the configuration predicate is true, this attribute expands out to the attributes listed after the predicate. For example, the following module will either be found at `linux.rs` or `windows.rs` based on the target.
// When the `magic` feature flag is enabled, the above will expand to:
#[sparkles]
#[crackles]
fn bewitched() {}
```
> **Note**: The `cfg_attr` can expand to another `cfg_attr`. For example, `#[cfg_attr(target_os = "linux", cfg_attr(feature = "multithreaded", some_other_attribute))]` is valid. This example would be equivalent to `#[cfg_attr(all(target_os = "linux", feature ="multithreaded"), some_other_attribute)]`.
The built-in `cfg` macro takes in a single configuration predicate and evaluates to the true literal when the predicate is true and the false literal when it is false.
For example:
```rust
let machine_kind = if cfg!(unix) {
"unix"
} else if cfg!(windows) {
"windows"
} else {
"unknown"
};
println!("I'm running on a {} machine!", machine_kind);
Rust is focused strongly on safety, but sometimes doing something dangerous is necessary. In this case you can use the `unsafe` keyword. `unsafe` should be used only when needed as it may cause undefinied behaviour, but when debugging you can solely focus on your `unsafe` blocks as all potential dangerous operations are neatly packaged in them.
There are two types of using `unsafe`:
-`unsafe` blocks lets you call dangerous code. With this you can wrap unsafe code in a safe function with checks to call.
```rust
fn write_to_serial(data: &[u8]) {
assert!(data.is_valid());
unsafe {
// doing potentially unsafe things
write_to_serial_unchecked(data);
}
}
```
-`unsafe` functions can only be called from `unsafe` blocks.
Support for inline assembly is provided via the `asm!` and `global_asm!` macros. It can be used to embed handwritten assembly in the assembly output generated by the compiler.
```rust
use std::arch::asm;
// Multiply x by 6 using shifts and adds
let mut x: u64 = 4;
unsafe {
asm!(
"mov {tmp}, {x}",
"shl {tmp}, 1",
"shl {x}, 2",
"add {x}, {tmp}",
x = inout(reg) x,
tmp = out(reg) _,
);
}
assert_eq!(x, 4 * 6);
```
The assembler template uses the same syntax as format strings (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by RFC #2795) are not supported.
An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.
As with format strings, positional arguments must appear before named arguments and explicit register operands.
Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.
The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
Currently, all supported targets follow the assembly code syntax used by LLVM's internal assembler which usually corresponds to that of the GNU assembler (GAS). On x86, the .intel_syntax noprefix mode of GAS is used by default. On ARM, the .syntax unified mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior. Further constraints on the directives used by inline assembly are indicated by Directives Support.
- [image](https://lib.rs/crates/image): Imaging library. Provides basic image processing and encoders/decoders for common image formats.
### CLI
- [rustyline](https://lib.rs/crates/rustyline): Rustyline, a readline implementation based on Antirez's Linenoise
- [clap](https://lib.rs/crates/clap): A simple to use, efficient, and full-featured Command Line Argument Parser
- [crossterm](https://lib.rs/crates/crossterm): A crossplatform terminal library for manipulating terminals
- [indicatif](https://lib.rs/crates/indicatif): A progress bar and cli reporting library for Rust
- [argh](https://lib.rs/crates/argh): Derive-based argument parser optimized for code size
- [owo-colors](https://lib.rs/crates/owo-colors): Zero-allocation terminal colors that'll make people go owo
- [yansi](https://lib.rs/crates/yansi): A dead simple ANSI terminal color painting library
### Compression
- [flate2](https://lib.rs/crates/flate2): DEFLATE compression and decompression exposed as Read/BufRead/Write streams. Supports miniz_oxide and multiple zlib implementations. Supports zlib, gzip, and raw deflate streams.
- [unrar](https://lib.rs/crates/unrar): list and extract RAR archives
### Databases
- [rusqlite](https://lib.rs/crates/rusqlite): Ergonomic wrapper for [SQLite](../SQLite.md)
- [sqlx](https://lib.rs/crates/sqlx): The Rust [SQL](SQL.md) Toolkit. An async, pure Rust [SQL](SQL.md) crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and [SQLite](../SQLite.md).
- [regex](https://lib.rs/crates/regex): An implementation of [regular expressions](../../../tools/Regex.md) for Rust. This implementation uses finite automata and guarantees linear time matching on all inputs.
- [tokio](https://lib.rs/crates/tokio): An event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications
- [futures](https://lib.rs/crates/futures): An implementation of futures and streams featuring zero allocations, composability, and iterator-like interfaces