Skip to main content

Rust all-in

A language empowering everyone to build reliable and efficient software.

https://www.rust-lang.org/

The most important links when working with Rust (alphabetically):

Other awesome links (alphabetically):

Interesting Stack Overflow questions

Difference between iter, iter_mut, and into_iter

  • the iterator returned by into_iter may yield any of T, &T or &mut T, depending on the context
  • the iterator returned by iter will yield &T, by convention
  • the iterator returned by iter_mut will yield &mut T, by convention

If you just need to "look at" the data, use iter, if you need to edit/mutate it, use iter_mut, and if you need to give it a new owner, use into_iter.

Sources:

Difference between Copy and Clone

Copies happen implicitly, for example as part of an assignment y = x. The behavior of Copy is not overloadable; it is always a simple bit-wise copy.

Cloning is an explicit action, x.clone(). The implementation of Clone can provide any type-specific behavior necessary to duplicate values safely. For example, the implementation of Clone for String needs to copy the pointed-to string buffer in the heap. A simple bitwise copy of String values would merely copy the pointer, leading to a double free down the line. For this reason, String is Clone but not Copy.

Clone is a supertrait of Copy, so everything which is Copy must also implement Clone. If a type is Copy then its Clone implementation only needs to return *self:

struct MyStruct;

impl Copy for MyStruct { }

impl Clone for MyStruct {
fn clone(&self) -> MyStruct {
*self
}
}

Source: https://github.com/rust-lang/rust/blob/2e6eaceedeeda764056eb0e2134735793533770d/src/libcore/marker.rs#L272

Different wording:

  • Copy is implicit, inexpensive, and cannot be re-implemented (memcpy)
  • Clone is explicit, may be expensive, and may be re-implement arbitrarily

Read this interesting question: https://stackoverflow.com/q/31012923/3135248

Visibility and privacy in Rust

Visibility and privacy o modules in Rust is well explained here: https://doc.rust-lang.org/reference/visibility-and-privacy.html

In short: (almost) everything is private by default and you can make it public via pub keyword. There are several additional restrictions of the pub keyword:

  • pub(in path) makes an item visible within the provided path. path must be an ancestor module of the item whose visibility is being declared.
  • pub(crate) makes an item visible within the current crate.
  • pub(super) makes an item visible to the parent module. This is equivalent to pub(in super).
  • pub(self) makes an item visible to the current module. This is equivalent to pub(in self) or not using pub at all.

Example:

pub mod outer_mod {
pub mod inner_mod {
// This function is visible within `outer_mod`
pub(in crate::outer_mod) fn outer_mod_visible_fn() {}

// This function is visible to the entire crate
pub(crate) fn crate_visible_fn() {}

// This function is visible within `outer_mod`
pub(super) fn super_mod_visible_fn() {
// This function is visible since we're in the same `mod`
inner_mod_visible_fn();
}

// This function is visible only within `inner_mod`,
// which is the same as leaving it private.
pub(self) fn inner_mod_visible_fn() {}
}
pub fn foo() {
inner_mod::outer_mod_visible_fn();
inner_mod::crate_visible_fn();
inner_mod::super_mod_visible_fn();

// This function is no longer visible since we're outside of `inner_mod`
// Error! `inner_mod_visible_fn` is private
//inner_mod::inner_mod_visible_fn();
}
}

fn bar() {
// This function is still visible since we're in the same crate
outer_mod::inner_mod::crate_visible_fn();

// This function is no longer visible since we're outside of `outer_mod`
// Error! `super_mod_visible_fn` is private
//outer_mod::inner_mod::super_mod_visible_fn();

// This function is no longer visible since we're outside of `outer_mod`
// Error! `outer_mod_visible_fn` is private
//outer_mod::inner_mod::outer_mod_visible_fn();

outer_mod::foo();
}

fn main() { bar() }

How to create parameterized tests in Rust?

https://stackoverflow.com/q/34662713/3135248

macro_rules! fib_tests {
($($name:ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $value;
assert_eq!(expected, fib(input));
}
)*
}
}

fib_tests! {
fib_0: (0, 0),
fib_1: (1, 1),
fib_2: (2, 1),
fib_3: (3, 2),
fib_4: (4, 3),
fib_5: (5, 5),
fib_6: (6, 8),
}

An interesting alternative approach is to use proptest:

proptest! {
#[test]
fn parses_all_valid_dates(s in "[0-9]{4}-[0-9]{2}-[0-9]{2}") {
parse_date(&s).unwrap();
}
}

Or with extra config:

proptest! {
#![proptest_config(ProptestConfig {
cases: 1000, .. ProptestConfig::default()
})]
#[test]
fn parse_authorization_header_proptest(token in "[a-zA-Z0-9-._~+/]+") {
println!("Bearer {}", token); // visible only with `cargo test -- --nocapture`
let result = parse_authorization_header(format!("Bearer {}", token).as_str()).unwrap();
prop_assert_eq!(result, token)
}
}

Reading and writing files

https://stackoverflow.com/a/31193386/3135248

Read a file to a String:

use std::fs;

fn main() {
let data = fs::read_to_string("/etc/hosts").expect("Unable to read file");
println!("{}", data);
}

Read a file as a Vec<u8>:

use std::fs;

fn main() {
let data = fs::read("/etc/hosts").expect("Unable to read file");
println!("{}", data.len());
}

Write a file:

use std::fs;

fn main() {
let data = "Some data!";
fs::write("/tmp/foo", data).expect("Unable to write file");
}

Macro repetitions

Below is a macro which formats each element as a string. It matches zero or more comma-separated expressions and expands to an expression that constructs a vector.

macro_rules! vec_strs {
(
// Start a repetition:
$(
// Each repeat must contain an expression...
$element:expr
)
// ...separated by commas...
,
// ...zero or more times.
*
) => {
// Enclose the expansion in a block so that we can use
// multiple statements.
{
let mut v = Vec::new();

// Start a repetition:
$(
// Each repeat will contain the following statement, with
// $element replaced with the corresponding expression.
v.push(format!("{}", $element));
)*

v
}
};
}

fn main() {
let s = vec_strs![1, "a", true, 3.14159f32];
assert_eq!(s, &["1", "a", "true", "3.14159"]);
}

Source: https://veykril.github.io/tlborm/macros/macro_rules.html#repetitions

Ultimate Clippy pedantic check

cargo clippy -- -W clippy::pedantic