Recently, I saw several good publicity regarding Rust, for example :
- Why Discord is switching from Go to Rust (TLDR : Golang's automatic garbage collection is causing problems)
- Rust will go into Linux 6.1 (TLDR : To reduce the number of potential bugs and security vulnerabilities)
- It's time to stop using C and C++ for new projects, says Microsoft Azure CTO : (TLDR : "Speaking of languages, it's time to halt starting any new projects in C/C++ and use Rust for those scenarios where a non-GC language is required. For the sake of security and reliability. the industry should declare those languages as deprecated.")
A good publicity so intense that i'm quite inclined to join this bandwagon.
Runtime Error? #
Several years ago, I made a Python-based simple timer app to track my own work-hour. Nowadays, I still use this app daily to measure my productivity rate. But, lately, this app has been crashing sporadically for some unknown reason.
Maybe it's a good time to finally rewrite this app for good, in Rust!
Prepare the dependencies #
First, cargo new appname
. It will generate two important file : Cargo.toml and main.rs. Open Cargo.toml, add several dependencies.
[dependencies]
console = "0.15.2"
chrono = "0.4"
cli-clipboard = "0.3.0"
- console : I need to clear-screen the terminal
- chrono : I need to access system time
- cli-clipboard : Well. It's obvious
Run cargo build
to install the dependencies. Then open main.rs, and let's go.
Program structure #
There are two main sections : module inclusion and main function.
use std::thread;
use std::time::{Duration};
use std::io;
use chrono;
use std::sync::mpsc::{self, TryRecvError};
use cli_clipboard::{ClipboardContext, ClipboardProvider};
fn main() {
// main program
}
Main program : how it works #
Split the app into two thread : backend-timer and frontend. Backend-timer will continue counting the elapsed time in the background. Frontend will wait for quit signal from user. If the frontend received the quit signal, frontend will send a quit message to backend. Backend will reply with the elapsed time data before killing itself.
1 // Get start timestamp
2 let date = chrono::Local::now().format("%-d %B %Y").to_string();
3 let start_time = chrono::Local::now().format("%-H:%M").to_string();
4 println!("reitnorF timer 2.0");
5 println!("{}, {}", date,start_time);
6 println!("");
7
8 //Initialize communication channel
9 let (tx, rx) = mpsc::channel();
10 let (txa, rxa) = mpsc::channel();
11
12 //Initialize time counter
13 let mut i = 1;
14 let mut m = 0;
15 let mut h = 0;
16
17 //Spawn backend thread
18 thread::spawn(move || {
19 loop {
20 //Update current elapsed time
21 let term = console::Term::stdout();
22 term.clear_last_lines(1).expect("");
23 let stamp = format!("{} hour, {} minute, {} second ",h,m,i);
24 term.write_line(&stamp).expect("");
25
26 //Second to hour-minute-second conversion
27 thread::sleep(Duration::from_millis(1000));
28 i = i + 1;
29 if i == 60 {i = 0;m = m +1;}
30 if m == 60{m = 0;h = h +1;}
31
32 //Wait for quit signal from main thread
33 match rx.try_recv() {
34 Ok(_) | Err(TryRecvError::Disconnected) => {
35 println!("Timer terminated.");
36 let ticker_dur = format!("({} hour {} minute {} second)",h,m,i);
37 // Send back the time data to main thread
38 txa.send(ticker_dur).unwrap();
39 break;
40 }
41 Err(TryRecvError::Empty) => {}
42 }
43 }
44 });
45
46 //Wait for quit signal from user
47 io::stdin().read_line(&mut String::new()).unwrap();
48
49 //Send quit signal to timer thread
50 let _ = tx.send(());
51
52 //Receive elapsed time data
53 let received = rxa.recv().unwrap();
54
55 //Get end time
56 let end_time = chrono::Local::now().format("%-H:%M").to_string();
57
58 //Generate report
59 let ticker = format!("[{}] {} - {} {}", date,start_time, end_time,received);
60
61 //Show report
62 println!("{}",ticker);
63
64 //Copy report to clipboard
65 let mut ctx = ClipboardContext::new().unwrap();
66 ctx.set_contents(ticker.to_owned()).unwrap();
The Result #
- Press enter to quit the timer.
- After the app is terminated, check your clipboard. The report is there.
- Check the source code on Github : https://github.com/altilunium/reitnorF-timer-2.0
Benchmarking against my old Python code #
Smaller executable file, generally lower CPU and RAM usage. Cool. I'm very satisfied.
Epilogue #
In my opinon, "rewrite in rust" challenge is quite a good movement to witness it by yourself, whether Rust will actually improve your codebase or not. Go pick your old, dusty, forsaken side project that you haven't touched it since ages. Rewrite it in Rust. Do the benchmark.
Cool propaganda-styled poster that I found on Twitter. Credit : © 2022 Fission