Some findings and notes about using rust on some real-world stuff

Handling JSON

A small example how to dump your struct to a file and read it again.


serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use std::io::BufWriter;
use std::io::BufReader;
use std::fs::File;

#[derive(Serialize, Deserialize, Debug)]
enum CarClass {

#[derive(Serialize, Deserialize, Debug)]
struct Car {
    maxspeed: f64,
    weight: f64,
    class: CarClass

fn main() {
    let new_car = Car {
        maxspeed: 120.0,
        weight: 4000.0,
        class: CarClass::Offroad
    // write out the file
    let writer = BufWriter::new(File::create("car.json").unwrap());
    serde_json::to_writer_pretty(writer, &new_car).unwrap();

    // read it back again
    let reader = BufReader::new(File::open("car.json").unwrap());
    let loaded_car: Car = serde_json::from_reader(reader).unwrap();
    println!("{:?}", loaded_car);

Iterate folder:

use std::io;
use std::fs::{self, DirEntry};
use std::path::Path;

fn iterate_path(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            if path.is_dir() {
                visit_dirs(&path, cb)?;
            } else {

or walkdir:

walkdir = "2"
extern crate walkdir
use walkdir::WalkDir;

for entry in WalkDir::new("foo") {

Argument parsing with clap

clap = "2"
extern crate clap;
use clap::{Arg, App, SubCommand};

fn main() {
    let matches = App::new("myapp")
                               .help("Sets a starting directory")
    let dir  = matches.value_of("dir").unwrap();
    println!("Value for root: {}", dir);

cargo run -- somedir


use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use treexml::Document;

match File::open("yo.xml") {
    Ok(f) => {
        let mut buf_reader = BufReader::new(f);
        let doc = Document::parse(buf_reader).unwrap();
    Err(_e) => ()

Run system command

use std::process::Command;

let output = 
        .args(&["-l", "-R"])
        .expect("failed to execute process");
let res = output.stdout;
println!("{:?}", res);

Gracefully handling Options and Results in iterators

fn main() {
    let animals = vec![Some("Bear"), Some("Dog"), None, Some("Cat")];
    let valid_animals = animals.iter().flat_map(|x| x).collect::<Vec<_>>()

Parse string to type

let i = String::from("42").parse::<i32>().unwrap();
// or let the compiler figure that out from annotating the variable
let i: i32 = String::from("42").parse().unwrap();

Defaults for structs

Derive from Default is the easiest:

struct Animal {
    hitpoints: i32,
    speed: f64,
    weight: f64
fn main() {
    // use all defaults
    let snake = Animal::default();
    //just specify one, use Default for everything else
    let birdy = Animal {
        hitpoints: 500,

If you want to have hand-crafted defaults, you need to impl your own Default:

struct Animal {
    hitpoints: i32,
    speed: f64,
    weight: f64

impl Default for Animal {
    fn default () -> Animal {
        Animal{hitpoints: 500, speed: 3.141, weight: 55.5}

fn main() {
    let snake = Animal::default();

Building gotchas and Cargo stuff

OSX @rpath

you can use install_name_tool to add a relative library search path to your executable like that:
install_name_tool -add_rpath @executable_path/. your_binary
in case you are using a gui library like libui you can then bundle the libui.A.dylib with your app bundle.
cargo bundle is recommended for packaging the actual app.

create multiple binaries

Let's say you want a GUI app and one for the command line that has minimal size and dependencies. All you need to do is the following in your Cargo.toml:

name = "cli"
path = "src/"

name = "cli"
path = "src/"

cargo build will then build both. Run the binary of your choice with cargo run --bin cli.

Windows programs without a console window

#![windows_subsystem = "windows"]

If you use this in your crate root, no console window will be shown if you run the resulting executable.

Git dependencies

rand = { git = "" }

But what if your repo is private? Relative url without a base?
First: if you are cloning with ssh, use the appropriate protocol and use an absolute-style url - github will accept replacing : with a /:

rand = { git = "ssh://" }

In order for this to work, .cargo/config needs to specify

git-fetch-with-cli = true

This file can be in your ~ home dir or in the project itself which makes sense if other people want to build your project.