How to get written bytes count for formatted string?

Here a simple code snippet:

fn main() {
    use std::io::Write as _;
    let mut s = [0_u8; 64];
    s.as_mut().write_fmt(format_args!("{}", 12345)).unwrap();
    let n = 3; // need to actually calculate written bytes count
    let s = std::str::from_utf8(&s[..n]).unwrap();
    println!("{}", s);
}

So I'd like to preallocate buffer, then write there some bytes and get amount of bytes written. In this exact case I could just scan trailing zero bytes and detect when they end but It's just so ugly. The write function returns exactly what I need but it doesn't accept any kind of formatting but &[u8] instead.

What do I do is call Display but to preallocated stack buffer not string like in ToString.
What are my options to do this in the cleanest way?

No, not really. \0 is valid UTF-8; Rust strings can contain embedded zeros without problem, so finding the first zero won't give you the correct result.

Apart from this problem, I don't think what you want is fully possible. Even if you compute the number of bytes, you won't be able to allocate a dynamically-sized buffer on the stack.

Anyway, there's an easy way to perform the calculation: just ask the fmt::Write how many bytes it was told to write! For that, you can do something like

struct WriteCounter(usize);

impl fmt::Write for WriteCounter {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.0 += s.len();
        Ok(())
    }
}
3 Likes

The std::io::Cursor type allows the above without needing a custom struct, since you can just query its position after the write.

That doesn't quite work though: it requires a big enough buffer to be already allocated.

You can use arrayvec crate. It's de-facto standard solution for fixed-capacity buf dynamic-length buffers and even no_std compatible.

fn main() {
    use std::fmt::Write  as _;
    use arrayvec::ArrayString;

    let mut s = ArrayString::<64>::new();
    write!(s, "{}", 12345).unwrap();
    println!("{}", s);
}
1 Like

Okay then, I thought it's something I can do without relying on extra crates.

Thanks

But that doesn't work for dynamically sizing the buffer either, does it?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.