Ezio

I made a small crate for easy-to-use IO in Rust. It is called ezio, and 0.1 is released today. It is a simple crate and it is ready to use now. I expect it will evolve somewhat on the way to a 1.0 release, but there is nothing which should stop you using it today.

Ezio is designed for education, experimentation, and prototyping. It's primary goal is to be as easy as possible to use. Newcomers to Rust should be able to add simple IO tasks to their programs without worrying about the details. That means ezio is not robust or performant, and is mostly unsuitable for producion use. But, I think ezio is a useful, even necessary, crate. So if you're learning or teaching Rust, or want to quickly experiment with IO in your program, give it a go.

IO in Rust

I think IO in Rust is pretty great - it is very fast, robust, and fairly easy to use. It is, however, designed to be industrial-strength and production-ready. That's usually a good thing, but it does come with a price: IO can be a bit daunting to people learning Rust, and a bit boilerplatey when you just want to quickly dump something into a file in your latest prototype.

In particular, Rust IO wants you to handle the errors properly. So most functions return Results, and in code where you don't care about error handling, that means a lot of unwraps.

Rust IO strives to be performant, and that means it is low-level, matching OS IO primitives as closely as possible. It means that the user allocates buffers for reading, there are often many options for how to read or write data, things like buffering are opt-in, there is minimal processing by default (e.g., the user is usually responsible for converting bytes into strings), and often multiple calls to IO functions are required.

All this adds up to a lot of cognitive load. Which is fine in a big program, but a bit of a pain if you're trying to teach Rust and just want to read a line from stdin.

Ezio

My solution to the above problems is ezio. It is designed for Rust learners and others who do not need industrial-strength IO. It doesn't give you many options, it is happy to allocate, panics rather than giving you the opportunity to handle errors, and deals primarily with strings rather than bytes. It is totally unsuitable for most real applications, but reading from stdin is as easy as let line = stdio::read_line();.

Secondarily, ezio is designed to roughly follow Rust's IO design and to be interoperable with it, so when users do progress from ezio to the standard library there are no big surprises.

Ezio offers reading and writing to files, stdio (i.e., the terminal), and strings (for mocking and other uses in tests). Ezio offers simple free functions, and reader/writer objects for more flexibility. There are Read and Write traits which inherit from and simplify those in the standard library, and which allow for generic programming.

Ezio is currently at version 0.1. I believe there is a lot of potential for improvement and that likely includes breaking changes. However, ezio is a pretty simple library and I think it is unlikely to have subtle problems. Therefore, I recommend you can use it now and shouldn't wait for a 1.0 release. As should be clear from the motivation, ezio is absolutely unsuitable for production use.

A short user's guide

You'll probably want to read the docs.

Add ezio = "0.1.0" to your Cargo.toml and use ezio::prelude::*; to any module where you want to use ezio.

Use the file module for file IO and the stdio module for terminal IO. Within each there are simple functions for reading and writing and there are reader/writer objects. For writing, we generally just write a string. For reading, you can choose to read_all to read everything from a source, or read_line to read a single line. You can also iterate lines. E.g.,

use ezio::prelude::*;

// Read a line from stdin
let _ = stdio::read_line();

// Iterate over lines in a file
for line in file::reader("path/to/file.txt") {
    // ...
}

// Read a while file
let _ = file::read("path/to/file.txt");

// Write to a file
file::write("path/to/file.txt", "Some text");

// Write multiple things to a file
let mut w = file::writer("path/to/file.txt");
w.write("Some text\n");
w.write("Some more text");