fmt::Write, io::Write, Formatter, Display?

In annotate-snippets I'm building up a string and most of the time I end up printing it to terminal.

To avoid allocations, I've been working on a refactor to use fmt::Write argument which would be filled with characters.
This way I was able to use write! and print! to print to stdout or to write to a &mut String.
Since the primary mode is to output to stdout that's the performance I care about, and support for writing to a string or file is just a nice addition and I'm ok if it costs a bit more.

I'm playing now with incorporating termcolor and I noticed that it uses io::Write instead. The docs also state that io::Write is preferred over fmt::Write.
Unfortunately, I don't see a way to use a String as a source of io::Write which means that I seem to have a choice - either support stdout+String model or support termcolor (optionally, by default I still write plain strings so fmt::Write would work except for when an optional feature is on).

Is there a way to make an allocation free API that can support both or is that an expression of some fundamental trade-off that I have to make?

Ty.

Vec<u8> is io::Write and converting it into String never allocate - only check if the content is valid UTF-8.

String is not io::Write because it cannot accept arbitrary byte sequence. It can only accepts valid UTF-8 texts.

2 Likes

The Stdout type implements io::Write, so you can actually drop the intermediate String and use write!(stdout, "Some text") directly.

This has the added benefit of not adding any extra allocations over whatever your platform would use to send data to the kernel anyway (none on Linux, I'm not sure if Windows or OSX allocate).

3 Likes

Ah, thank you!

I wish the Vec<u8> was in the docs for io::Write!