I'm wondering if there's a better or preferred way to do the following. I want to use a library which accepts a std::fmt::Write, but in the context I have, I only have a type which implements std::io::Write.
I've just decided to buffer everything to a string first then write it to the file I want it written to. Is there a better way to interoperate between the std::io::Write and std::fmt::Write traits?
Would it have made more sense for the library to accept std::io::Write in the first place?
My personal opinion on this matter is that std::fmt::Write should very rarely be used explicitly; its primary job is to be implemented by things that want to be written to using formatting traits (std::fmt::Display and such).
The standard library provided way to interoperate between fmt and io here is std::io::Write::write_fmt(), which lets you write anything formattable to an io::Write stream. So, you should create a Displayable adapter type and you get the trait adaptation for free:
use std::fmt;
use std::io::Write as _;
fn function_that_demands_fmt_write(out: &mut dyn fmt::Write) -> fmt::Result {
out.write_str("hello")
}
struct Adapter {}
impl fmt::Display for Adapter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// fmt::Formatter implements fmt::Write
function_that_demands_fmt_write(f)
}
}
fn main() {
let a = Adapter {};
// write! calls .write_fmt()
write!(std::io::stdout(), "{a}").unwrap();
}
Would it have made more sense for the library to accept std::io::Write in the first place?
Not necessarily, because io::Write has the significant disadvantage of not being usable in no_std environments. and also isn't implemented by String (because io::Write allows writing arbitrary non-UTF-8 bytes which String cannot accept). In my opinion, the library should instead be returningimpl fmt::Display.
The exception is if the library function is intended to be called by the implementations of formatting traits like impl fmt::Display for ....