Getting started with Rust and the petgraph crate, I made a little program to write a graph in “dot” file format. Below is the rust and some command-line code to turn it into a png.

visual graph representation with circles and arrows

use petgraph::Graph;
use petgraph::dot::{Dot, Config};
use std::fs::File;
use std::io::Write;

fn main() {
    println!("hello graph!");
    let mut graph = Graph::<_, i32>::new();
    graph.add_node("A");
    graph.add_node("B");
    graph.add_node("C");
    graph.add_node("D");
    graph.extend_with_edges(&[
        (0, 1), (0, 2), (0, 3),
        (1, 2), (1, 3),
        (2, 3),
    ]);

    println!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel]));
    let mut f = File::create("example.dot").unwrap();
    let output = format!("{}", Dot::with_config(&graph, &[Config::EdgeNoLabel]));
    f.write_all(&output.as_bytes()).expect("could not write file");
}

output of cargo run:

hello graph!
digraph {
    0 [label="\"A\""]
    1 [label="\"B\""]
    2 [label="\"C\""]
    3 [label="\"D\""]
    0 -> 1
    0 -> 2
    0 -> 3
    1 -> 2
    1 -> 3
    2 -> 3
}

Generate PNG from DOT file

The dot command is part of graphviz, which I installed with brew install graphviz.

The following command creates a PNG file from the .dot file generated by Rust code above

dot -T png -O example.dot

The resulting PNG is displayed at the top-right of this post (next to the Rust code).


Special thanks to:
* mcarton’s help on stackoverflow for enlightening me on a bit of Rust nuance as I experimented with petgraph.
* rudifa’s post graphviz-on-the-mac

I’m debugging an issue where my app uses a library that requires me to dynamically link with an openssl library. What’s more I’m debugging it on an old linux version. Sigh.

gdb to the rescue!

After figuring out how to build openssl from source, I stumbled upon a gdb trick… suppose you are using a fairly standard open source library (like openssl) and you want to debug something that uses it (some other library that doesn’t work over ssl), gdb will let you know if there’s an easy way to download the symbols! Just type gdb + library name.

Here’s an example

gdb openssl
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/bin/openssl...(no debugging symbols found)...done.
Missing separate debuginfos, use: debuginfo-install openssl-1.0.1e-57.el6.x86_64
(gdb) quit

Now I can use this command to install the debug symbols for the specific version of openssl that is installed on this system:

debuginfo-install openssl-1.0.1e-57.el6.x86_64

then I can debug my app looking at how it calls openssl. In the gdb session below, I first set a breakpoint in main, and run to that point…

(gdb) b main
(gdb) run
Starting program: /home/builder/src/app 
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
[Thread debugging using libthread_db enabled]

Breakpoint 1, main (argc=4, argv=0x7fffffffe698) at sample.cpp:226
226         LOG("Here I am in main!")

now the openssl library is loaded and I can set a breakpoint in it:

(gdb) b SSL_CTX_set_verify
Breakpoint 2 at 0x7ffff7734bb0: file ssl_lib.c, line 2040.
(gdb) c
Continuing.
Creating connection object
[New Thread 0x7ffff4bd6700 (LWP 53)]
Connecting to server/app URL: rtmps://live-api-s.facebook.com/rtmp/

Breakpoint 2, SSL_CTX_set_verify (ctx=0x62efe0, mode=1, cb=0x7ffff7acb6c0 <SecuredConnectionIO::VerifyCallback(int, x509_store_ctx_st*)>)
    at ssl_lib.c:2040
2040        ctx->verify_mode=mode;

I can look at variables or all of the function arguments:

(gdb) p mode
$1 = 1
(gdb) info args
ctx = 0x62efe0
mode = 1
cb = 0x7ffff7acb6c0 <SecuredConnectionIO::VerifyCallback(int, x509_store_ctx_st*)>

How cool is that?

Rust has a “community of developers empowered by their tools and each other” (via Katharina Fey in “An async story“). The Rust community helps each other through effective narrative documentation and attention to error messages, and the robust tooling around Rust drives momentum, overcoming some of the natural hurdles when diving into a new language.

Here’s my list of essential rust tools (so far):

The basics

rustup

The default tool when you install rust.

Rust has very good offline documentation (perfect for learning on long plane trips!). See rustup doc help for full list. Here are some highlights:

rustup doc --book              # Rust Programming Language book
rustup doc --rust-by-example   # collection of runnable examples
rustup doc --std               # Standard library API documentation

cargo

Cargo packages Rust code into crates. You can find published libraries at crates.io. After getting familiar with cargo.toml file which streamlines development and enables reproducible builds, I found command line management easier with cargo-edit:

cargo install cargo-edit
cargo add <crate>         # also provides rm, upgrade

Rust and Web Assembly

The Rust Wasm tooling has improved dramatically over the past year — wasm-pack is the “one-stop shop for building, testing, and publishing Rust-generated WebAssembly.” The rustwasm book is very good.

cargo install wasm-pack

rust-parcel

I’ve grown to dread building modern web apps with their complex JavaScript build tooling. In learning Rust, I discovered Parcel which lets you import .rs files from JavaScript. Under the hood, it compiles Rust to Web Assembly and hooks it all up into a tidy js src reference for my index.html. Simply breathtaking.

Parcel tool chain is idiomatic for NodeJS folk. npm run start will run a local server and watch your files.

npm init rust-parcel hello-rust-parcel
cd hello-rust-parcel

When you build your web app, it automatically prints out the kinds of things you should want to know. For many uses of Rust, compiled code size doesn’t matter, but for Web apps, it is important to keep an eye on download size:

npm run build

> create-rust-parcel@0.0.2 build /Users/sallen/src/rust/hello-rust-parcel
> parcel build index.html

✨  Built in 3.20s.

dist/rust_parcel_bg.d1b79d09.wasm    67.63 KB     13ms
dist/js.caa35af8.js.map              14.65 KB     11ms
dist/js.caa35af8.js                   7.49 KB    2.58s
dist/Cargo.8d29e058.toml              1.17 KB    1.16s
dist/index.html                         228 B    999ms

wasm on the edge?

Interesting to note that Web Assembly isn’t just for client-side browser code. WebAssembly on Cloudflare Workers creates potential for new edge capabilities.

TBD

I’m just scratching the surface as I learn Rust. My practical applications range from native client and server code, command-line tools along with my early Web app experiments. I don’t expect Rust to be my goto language for everything, but it’s fun to dive in and explore as I climb the steep learning curve of getting my code to reliably compile!

For people ahead of me on your Rust adventures, what essential tools am I missing?