Note: This is a tutorial style introduction to cargo-play. If you prefer to explore things yourself, please take a look at cargo-play's README.md.

Have you ever wanted to try a new crate in Rust Playground, then you realized sadly that crate hasn’t made to the top 100 most downloaded crates on crates.io? Now you have to go through the process of creating a new Cargo project (cargo new playground) and editing Cargo.toml (vim Cargo.toml) to add that crate and write the code (vim src/main.rs) and opening your terminal to run the code with cargo run. So many commands to run to just try a new crate. Wouldn’t the world be nicer if you can just open your favorite editor to write some code and a command will take care of all these hassles for you? Like a local Rust Playground?

Meet cargo-play, a brand new Cargo custom subcommand that brings Rust Playground to your computer and give you full control on what crates you can play with.

To get to this magic playground to your laptop, simply run cargo install cargo-play.

Now open your favorite editor and write some code. For example, you may want to write things like:

fn main() {
  println!("Hello cargo-play!");
}

Nah this is too boring. Try something fancier like:

//# regex = "1.2.1"

use regex::Regex;

const TO_SEARCH: &'static str = "
On 2010-03-14, foo happened. On 2014-10-14, bar happened.
";

fn main() {
    let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap();

    for caps in re.captures_iter(TO_SEARCH) {
        // Note that all of the unwraps are actually OK for this regex
        // because the only way for the regex to match is if all of the
        // capture groups match. This is not true in general though!
        println!("year: {}, month: {}, day: {}",
                 caps.get(1).unwrap().as_str(),
                 caps.get(2).unwrap().as_str(),
                 caps.get(3).unwrap().as_str());
    }
}

(This example is taken from regex’s README file.)

Save this file to somewhere like your home directory (a messy person like me): ~/regex.rs. Then, simply run cargo play ~/regex.rs in your terminal (or :!cargo play % if you are a Vim user like me) and you will witness the magic:

$ cargo play regex.rs
    Updating crates.io index
   Compiling memchr v2.2.1
   Compiling lazy_static v1.3.0
   Compiling regex-syntax v0.6.11
   Compiling thread_local v0.3.6
   Compiling aho-corasick v0.7.6
   Compiling regex v1.2.1
   Compiling t9zjqgnpj2xi2gmy6kdibu4id7u v0.1.0 (/var/folders/nq/608n9lcx02n_mzx33_3z5wyw0000gn/T/cargo-play.t9zjqgnpj2XI2GMY6KdiBu4Id7U)
    Finished dev [unoptimized + debuginfo] target(s) in 8.73s
     Running `/var/folders/nq/608n9lcx02n_mzx33_3z5wyw0000gn/T/cargo-play.t9zjqgnpj2XI2GMY6KdiBu4Id7U/target/debug/t9zjqgnpj2xi2gmy6kdibu4id7u`
year: 2010, month: 03, day: 14
year: 2014, month: 10, day: 14

Now you may already notice the strangely familiar comment lines at the beginning of the example, it looks quite similar to what you write in a Cargo.toml. Indeed, this is how cargo-play does its trick. It simply take these lines and stuff these lines into a generated Cargo project and invoke cargo run for you.

The magic would be too boring if it just stops here. A lazy person like me wouldn’t want to write these comment lines at the beginning of the file. I want someone else write it for me! Behold, put the following code to a file (~/serde.rs):

use serde_json::{Result, Value};

fn main() {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    // Parse the string of data into serde_json::Value.
    let v: Value = serde_json::from_str(data)?;

    // Access parts of the data by indexing with square brackets.
    println!("Please call {} at the number {}", v["name"], v["phones"][0]);

    Ok(())
}

(This example is taken from serde_json’s README file.)

Notice how it does not have the dependency specified at the beggining of the file like regex.rs? Now, run cargo play --infer ~/serde.rs:

$ cargo play serde.rs
    Updating crates.io index
   Compiling ryu v1.0.0
   Compiling serde v1.0.99
   Compiling itoa v0.4.4
   Compiling serde_json v1.0.40
   Compiling y4c9qgejnve0fmq3n7mt3dzsj8g v0.1.0 (/var/folders/nq/608n9lcx02n_mzx33_3z5wyw0000gn/T/cargo-play.y4c9qGEJNVe0FmQ3n7mt3dZSJ8g)
    Finished dev [unoptimized + debuginfo] target(s) in 10.57s
     Running `/var/folders/nq/608n9lcx02n_mzx33_3z5wyw0000gn/T/cargo-play.y4c9qGEJNVe0FmQ3n7mt3dZSJ8g/target/debug/y4c9qgejnve0fmq3n7mt3dzsj8g`
Please call "John Doe" at the number "+44 1234567"

With the --infer flag, cargo-play is able to infer the dependencies your code use and automaitally add these dependencies to the generated Cargo.toml so you don’t need to write these lines yourself.

There are some other features cargo-play provides, take a look at the --help message you may find what you want. If you don’t find what you want, feel free to file an issue so I can see if I can add these to cargo-play.

The simply command line interface makes it a lot easier to integrate cargo-play with your favorite editor. If you are a Vim user like me, you can add the following to your .vimrc:

command CargoPlay !cargo play %

Next time when you want to try something new with Rust, just open vim write some code and run :CargoPlay you will be able to see the result of your program.