Hello World

Some basic example:

fn main() {
    println!("Hello World!");
    eprintln!("Message in stderr :-(");
}

Some more complex example:

fn main() {
    let hello = "Hello, world";
    println!("{}", hello);
}

On last more, a little more hard-core:

fn main() {
    println!("{}",
             "Hello, world"
                .chars()
                .collect::<Vec<char>>()
                .into_iter()
                .collect::<String>()
    );
}   

Numbers

Starting to format numbers.

fn main() {
    let n_immutable = 1;
    let mut n = 42;

    println!("{}", n);

    println!("{:.2}", 0.123456789);
    println!("{:04}", 42);
    println!("{val}", val=42);
    println!("{:?}", (1, 2, 3, 4));
    println!("{:#?}", (1, 2, 3, 4));

    println!("{n}", 
        n=[1, 2, 3, 4, 5].iter().sum::<u32>()
    );

    println!("{n}",
        n=(1..=10).sum::<u32>()
    );

    println!("{n:04.4}",
        n="42".parse::<f64>().unwrap()
    );
}

Wow, and what about a fibo?

fn fibo(n : u32) -> u32 {
    if n == 0 {
        0
    } else {
        fibo(n - 1) + n
    }
}

fn main() {
    println!("{val}",
        val = (1..=10).map(|x| fibo(x)).sum::<u32>()
    );
}

And limits?

fn main() {
    println!("{} -> {}",
        u32::MIN,
        u32::MAX
    );
}

Colors in text

Today I'm testing text_colorizer

In cargo.toml:

[dependencies]
text-colorizer="*"

and the source code:

extern crate text_colorizer;
use text_colorizer::*;

fn main() {
    let blue_world = "Hello, world!".blue().bold().italic();

    println!("{}", blue_world);
    println!("{:#?}", blue_world);
}

gets us:

Hello, world! <- This part is blue, shiny and italic.
ColoredString {
    input: "Hello, world!",
    fgcolor: Some(
        Blue,
    ),
    bgcolor: None,
    style: Style(
        9,
    ),
}

Another one: ansi_term: ansi_term

In cargo.toml:

[dependencies]
ansi_term="*"
use ansi_term::Colour::*;

fn main() {
    let red_world = Red.bold().italic().paint("Hello world!");

    println!("{}", red_world);
    println!("{:#?}", red_world);
}

Sorting /etc/passwd

use std::fs;
use anyhow::Result;

#[derive(Debug)]
struct Entry {
    username: String,
    uid: u16,
    gid: u16
}

fn main() -> Result<()> {
    let password_file = "/etc/passwd";

    let content = fs::read_to_string(password_file)?;
    let mut entries = content
        .split('\n')
        .filter(|entry| entry.split(':').count() >= 4)
        .map(|entry| {
            let values = entry.split(':').collect::<Vec<&str>>();
            Entry {
                username: values[0].to_string(),
                uid: values[2].parse::<u16>().unwrap(),
                gid: values[3].parse::<u16>().unwrap(),
            }
        })
        .collect::<Vec<Entry>>();

    entries.sort_by(|a, b| a.uid.cmp(&b.uid));

    for entry in entries {
        println!("{username} ({uid},{gid})",
            username=entry.username,
            uid=entry.uid,
            gid=entry.gid,
        )
    }

    Ok(())
}

More on this:

File & Pipe

use std::fs;
use std::process;
use std::io::{self, Read};

use base64::{decode,encode};

fn write() {
    let src = "/etc/passwd";

    let content = match fs::read_to_string(&src) {
        Ok(content) => content,
        Err(x) => {
            eprintln!("{}", x);
            process::exit(1);
        }
    };

    let mut lines = content
        .split('\n')
        .filter(|x| !x.is_empty())
        .collect::<Vec<&str>>();

    lines.sort_unstable();

    println!("{encoded}", encoded=encode(lines.join("\n")));
}

fn read() {
    let dst = "/tmp/passwd";

    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer).expect("We want some input.");
    let buffer = buffer.trim();

    let decoded : String = match decode(&buffer) {
        Ok(res) => {
            String::from_utf8(res).expect("Valid utf8 string")
        },
        Err(err) => {
            eprintln!("Invalid buffer: {:?}", err);
            process::exit(1);
        }
    };

    match fs::write(&dst, decoded) {
        Ok(_res) => {
            println!("Wrote file {dst}.", dst=dst);
        },
        Err(x) => {
            eprintln!("{}", x);
        }
    }
}

fn main() {
    if atty::is(atty::Stream::Stdin) {
        write();
    } else {
        read();
    }
}

Run by doing:

$ cargo r|cargo r && wc -l /tmp/passwd 
Wrote file /tmp/passwd.
53 /tmp/passwd

Regex

use std::env;
use std::fs;
use std::process;

use anyhow::Result;
use regex::Regex;

fn main() -> Result<()> {
    let args : Vec<String> = env::args().collect();
    let filename = match args.get(1) {
        None => {
            eprintln!("Invalid argument");
            process::exit(1);
        },
        Some(n) => {
            n
        }
    };
    let pattern = args[2].clone();
    let repl = args[3].clone();

    let in_contents = fs::read_to_string(filename)?;
    let re = Regex::new(&pattern)?;

    let out_contents = re.replace_all(&in_contents, &repl).to_string();

    println!("{}", out_contents);

    let pattern = "^([^:]*):";
    let re = Regex::new(pattern)?;

    for line in out_contents.split('\n') {
        let res = match re.captures(line) {
            None => continue,
            Some(v) => v,
        };

        println!("{}", &res[1]);
    }

    Ok(())
}

To test:

cargo r --bin test000 /etc/passwd mycroft testaroo

HashMap

use std::collections::HashMap;

fn main() {
    let mut h : HashMap<u32, u32> = HashMap::new();

    println!("is empty: {}", h.is_empty());

    h.insert(42, 42);

    println!("is empty: {}, h: {:?}", h.is_empty(), h);

    println!("has 42: {:?}", h.contains_key(&42));
    println!("has 1442: {:?}", h.contains_key(&1442));

    let v = match h.get(&42) {
        None => {
            eprintln!("Don't have value");
            0
        },
        Some(x) => {
            eprintln!("Have value: {}", x);
            *x
        }
    };

    println!("Value: {:?}", v);

    let v = match h.get(&1442) {
        None => {
            eprintln!("Don't have value");
            0
        },
        Some(x) => {
            eprintln!("Have value: {}", x);
            *x
        }
    };

    println!("Value: {:?}", v);

    h.remove(&42);
    println!("is empty: {}", h.is_empty());

    for i in 1..=7 {
        h.insert(i, i);
    }

    println!("Len: {}", h.len());

    for (k, v) in &h {
        println!("{} = {}", k, v);
    }


    // With entry API

    let z = h.entry(4242).or_insert(4242);
    println!("with Entry API: {:?}", z);

    fn get_value() -> u32 {
        return 4242;
    }

    let z = h.entry(42).or_insert_with(get_value);
    println!("with Entry API w/ function: {:?}", z);
}

Threads

1

use std::thread;
use std::time::Duration;

fn main() {
    let v = vec![1, 2, 3];

    let th = thread::spawn(move || {
        for _index in 1..10 {
            println!("in spawned thread: {v:?}", v=v);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for _index in 1..5 {
        println!("in main thread");
        thread::sleep(Duration::from_millis(1));
    }

    th.join().unwrap();
}

2

use std::thread;
use std::time::Duration;
use std::sync::mpsc;

fn main() {
    let v = vec![1, 2, 3];
    let (tx, rx) = mpsc::channel();

    let th = thread::spawn(move || {
        for received in rx {
            println!("in spawned thread: {v:?}; {recv}", v=v, recv=received);

            if received == 9 {
                break;
            }

            thread::sleep(Duration::from_millis(1));
        }
    });

    for index in 1..10 {
        println!("in main thread");
        tx.send(index).unwrap();
        thread::sleep(Duration::from_millis(1));
    }

    th.join().unwrap();
}

Threads, Arc & RNG

use std::thread;
use std::sync::{Arc,Mutex};
use std::time::Duration;

use rand::Rng;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut threads = vec![];

    for i in 1..10 {
        let cloned_counter = Arc::clone(&counter);
        let th = thread::spawn(move || {
            let mut num = cloned_counter.lock().unwrap();
            let mut rng = rand::thread_rng();

            thread::sleep(Duration::from_millis(rng.gen::<u64>() % 100));

            *num += i;

            println!("=> {}: {}", i, *num);
        });

        threads.push(th);
    }

    for th in threads {
        th.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

Links & Books

Books