101 Chunks of Rust
I’m learning writing more & more rust. But I really lack writing idiomatic code. So, I’ve decided to gather small useful Rust snippets on this page. No particular order, the more I want to write, the more it will be written on it.
Goal: One snippet, one crate/doc page/poc/whatever.
This page was last updated on 2022-01-03 and it is still WIP!
Have fun!
The Snippets
Navigating into the command line args
use std::env;
fn main() {
    println!("There is {} env.", env::args().len());
    for arg in env::args() {
        println!("- {}", arg);
    }
}
Also, you can check the clap crate.
Filtering numbers
use std::env;
use std::str::FromStr;
fn main() {
    let numbers = env::args()
        .skip(1)
        .map(|arg| u64::from_str(&arg))
        .filter(|arg| arg.is_ok())
        .map(|arg| arg.unwrap())
        .collect::<Vec<u64>>();
    println!("{:?}", numbers);
}
The std::str::FromStr trait documentation.
Pretty logging
pretty_env_logger is a simple logger built on top of log and that is allowing to write logs using colors.
extern crate pretty_env_logger;
#[macro_use] extern crate log;
fn main() {
    pretty_env_logger::init_timed();
    info!("such information");
    warn!("o_O");
    error!("much error");
}
Don’t forget to use log & pretty_env_logger crates to enable this.
Returning values from a loop
fn main() {
    let mut count = 0;
    let result = loop {
        if count == 10 {
            break count * 10;
        }
        count += 1;
    };
    println!("result: {:?}", result);
}
Simple password generator
// Don't forget to add the rand crate in Cargo.toml file:
//
// [dependencies]
// rand = "0.8.4"
//
use rand::prelude::*;
fn generate(size: usize) -> String {
    let mut rng = rand::thread_rng();
    let printable_chars = (0x20u8..=0x7e).map(|c| c as char).collect::<Vec<char>>();
    (0..size)
        .map(|_| rng.gen::<usize>() % printable_chars.len())
        .map(|idx| printable_chars[idx])
        .collect()
}
fn main() {
    for _ in 0..32 {
        println!("{}", generate(16));
    }
}
It makes use of the rand crate.
Swapping variables
The following snippet will swap 2 variables (which type has Copy trait), and will print their address.
fn swap<T: Copy>(a: &mut T, b: &mut T) {
    let z = *a;
    *a = *b;
    *b = z;
}
fn main() {
    let mut a = 1;
    let mut b = 2;
    println!("ptr: {:p}: val: {} // ptr: {:p}; val: {}", &a, a, &b, b);
    swap(&mut a, &mut b);
    println!("ptr: {:p}: val: {} // ptr: {:p}; val: {}", &a, a, &b, b);
}
The Itertools crate
use itertools::Itertools;
use itertools::{merge,partition,zip};
fn main() {
    // Get all permutations
    println!("{:?}", (0..5).permutations(5).collect_vec());
    // Get all uniques
    println!("{:?}", vec![1, 2, 3, 2, 1].iter().unique().collect_vec());
    // combine elements from first array with second's 
    println!("{:?}", vec![0, 1, 2].iter().zip(vec![4, 5, 6]).collect_vec());
    println!("{:?}", zip(vec![0, 1, 2], vec![0, 1, 2]).collect_vec());
    // partition elements of array into 2.
    let mut l = vec![1, 2, 3, 4, 5, 6];
    partition(&mut l, |z| { z % 2 == 0 });
    println!("{:?}", l); // [6, 2, 4, 3, 5, 1]
    // merge two array into an iterator
    println!("{:?}", merge(&[0, 1, 2], &[4, 5, 6]).collect_vec()); // [0, 1, 2, 4, 5, 6]
    println!("{:?}", merge(&[0, 1, 2], &[0, 1, 2]).collect_vec()); // [0, 0, 1, 1, 2, 2]
}
Check the itertools functions & itertools trait.
Implementing Display & FromStr traits
use std::str::FromStr;
use std::num::ParseIntError;
use std::fmt;
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "P <{},{}>", self.x, self.y)
    }
}
impl FromStr for Point {
    type Err = ParseIntError;
    fn  from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split(",")
            .collect::<Vec<&str>>()
            .iter().map(|&x| x.parse::<i32>().unwrap())
            .collect::<Vec<i32>>();
        Ok(Self {
            x: parts[0],
            y: parts[1],
        })
    }
}
fn main() {
    let p: Point = Point::from_str("-1,-1").unwrap();
    println!("{}", p);
}
As seen as on Rust By Example (Display of official doc); FromStr.
Testing out Iterator traits
use rand::Rng;
#[derive(Clone, Copy, Debug)]
struct Random {
}
impl Iterator for Random {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let n = rand::thread_rng().gen::<u32>();
        if n % 100 == 0 {
            None
        } else {
            Some(n)
        }
    }
}
fn main() {
    let random_numbers = Random{};
    for v in random_numbers {
        println!("- {}", v);
    }
    println!("There is {} elements in this run.", random_numbers.count());
}
The Iterator trait documentation. Rust By Example’s.
Generic structures & enums
struct Testaroo<T> {
    val0: T,
}
enum MyOption<T> {
    None,
    Some(Testaroo<T>)
}
fn main() {
    // All the following code is valid and can be used as it!
    let _ = Testaroo{ val0: "a" };
    let _ : Testaroo<u64> = Testaroo{ val0: 42 };
    let _ = Testaroo{ val0: 0.0 };
    let _ : MyOption<bool> = MyOption::None;
    let _ = MyOption::Some(Testaroo{ val0: true });
}
Arrays, vec & slices
fn main() {
    let array : [u32; 4] = [1, 2, 3, 4];
    let array_vec = array.to_vec();
    let slice0 = &array[2..=3];
    let slice1 = &array_vec[1..=2];
    // Outputs: array:[1, 2, 3, 4] vec:[1, 2, 3, 4] slice:[3, 4] slice:[2, 3]
    println!("array:{:?} vec:{:?} slice:{:?} slice:{:?}",
        array, array_vec, slice0, slice1);
    // auto-filled array declaration:
    let vbool = [false; 100];
    let vec: Vec<u32> = Vec::with_capacity(256);
    println!("len:{} capacity:{}", vec.len(), vec.capacity());
    let s0: &[bool] = &vbool;
    println!("len:{}", s0.len());
    let print = |n: &[bool]| {
        for el in n {
            println!("{:?}", el);
        }
    };
    print(s0); // This will write a lot of "false".
    print(&s0[..42]); // First 42 elements
    print(&s0[99..]); // last element
}
More about arrays, slices & Vec.
String to bytes array to &str
fn main() {
    let s: &str = "新年快乐";
    println!("{}", s);
    let s: String = s.to_string(); // this copies the string
    println!("len: {} chars: {}", s.len(), s.chars().count());
    let s: &[u8] = &s.as_bytes(); // convert to bytes
    println!("{}", String::from_utf8(s.to_vec()).unwrap()); // output: 新年快乐
    let elements = ["a", "b", "c", "d"];
    println!("{}", elements.concat()); // output: abcd
    println!("{}", elements.join(", ")); // output: a, b, c, d
    println!("{}", elements.concat().to_uppercase()); // output: ABCD
    println!("{}", elements.join(", ").replace(",", ";")); // output: "A; B; C; D"
    println!("{}", String::from("\n  A  \n").trim()); // output: "A"
}
The Uuid crate
// Don't forget to add in Cargo.toml:
// uuid = { version = "0.8.2", features = ["v4", "v5"] }
use uuid::Uuid;
fn main() {
    let uuid = Uuid::new_v4();
    println!("{:?}", uuid.to_urn());
    // Doing some conversion
    println!("{:?}", uuid.as_bytes());
    let uuid = Uuid::from_bytes(*uuid.as_bytes());
    println!("{:?}", uuid.to_urn());
    let uuid = Uuid::new_v5(
        &Uuid::NAMESPACE_URL,
        "example.org".as_bytes(),
    );
    println!("{:?}", uuid.to_urn());
}
Anyhow
Sometimes, handling errors in rust can be boring due to the type the error can be. There is a set of different crates to make this easier, and anyhow is one of them:
use anyhow::Result;
fn main() -> Result<()> {
    let contents = std::fs::read_to_string("test")?;
    println!("{:?}", contents);
    Ok(())
}
All the crates
- anyhow: Flexible error type;
- clap: Command line argument parser;
- itertools: Extra iterator adaptors, functions and macros;é
- pretty_env_logger: Simple logger built on top of env_logger, configurable via environment variables & writing nice colored messages depending their log levels;
- rand: Random number generation, with quite some useful features.
- uuid: Generate and parse UUIDs.