The hardest thing in programming - picking a project
So for this project, I wanted to build a simple system with Windows APIs. So I spent 30 minutes perusing windows-rs
and WinRT to see what kind of Windows features looked interesting to use. Some of the features that stood out to me included:
- HID LampArray Device Lighting - I was considering making a lighting effect but since I don’t have any devices that support this protocol, this idea was tabled.
- Windows Media Capture - I am interested in doing some video processing but I’ll likely save that for a later project since this will be a bit complicated as I might want to implement a DAG pipeline for processing the video in different ways.
- Windows Media Face Analysis - I’ve used face/body tracking on a React Native project before so I considered remaking this in Rust, but asset/content generation would take time and was not something I was interested in doing.
Here’s a demo of win-say. Also, you may think I’m joking but this game actually exists, it’s called Emberward.
Enter win-say, a way for you to rest your vocal cords
In the end, Windows Media Speech Synthesis (a much cooler name than tts) won out and I decided to implement a bare bones version of the say
command from MacOS. This was one of my favorite *nix commands when I first started programming.
# If you've never tried `say` before...
# Grab your MacBook, open Terminal, and type the following in, then hit enter:
say "Sitong sent me here"
# Actually, they might butcher my name so play around with the phonetics for me please.
If you’d like to see the code for win-say, check out the repository here.
Thoughts from this project
- Error handling in Rust is a first class citizen. The language really forces you to consider error bubbling/propagation more than any language I’ve used before. This actually led to a lot of boilerplate code for me (
match
). Then boilerplate frustration actually led me to enable Github Copilot for some autocompletion snippets and forced me into a longer deep dive intoResult<T, E>
,unwrap
, unwrap variants, and finally?
bubbling which finally let me avoid fighting the compiler as much. - Cargo features are a nice pattern to reduce unnecessary compilation of unneeded code. I can see why this would exist in the Rust world, where compilation times can get wild fast. However, as a Rust newbie, I definitely wasted a number of cycles wondering why my crate imports were causing compilation errors or wondering what was the name of the feature I needed to add to
Cargo.toml
. This still feels like a very manual process to me - if anyone has any tips here, please reach out to me. - I basically never think about multithreading due to working on the single threaded event loop Web. So it’s been great to reengage with threads and shared memory. There are a lot more patterns I’d like to see/implement here. This project was my first battle with Rust closures, variable lifetimes across threads, moving or borrowing, and it all has been enlightening in-between the periods of confusion/frustration.
- Copilot is really great for snippets and saving me doc lookup time. For instance, I typed
println!(”thread id
and I was able to tab complete toprintln!("Thread id: {:?}", thread::current().id());
without needing to know the Rust standard library functions. - Working with Windows docs means 1000 tabs open - this I already knew though.
My other favorite *nix commands include: cowsay, lolcat, cmatrix, and sl
$ echo "this is a mood" | cowsay
________________
< this is a mood >
----------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||