ikh
ikh

Reputation: 10417

How can I write a formatted string up to buffer size in rust?

It seems that write! doe not write an argument when the buffer size is inadequate.

use std::fmt::Write;
use arrayvec::ArrayString; // 'arrayvec' crate

fn main() {
    const SIZE: usize = 16;
    let mut s = ArrayString::<SIZE>::new();
    match write!(s, "{}{}", "0123456789", "0123456789") {
        Ok(_) => println!("success!"),
        Err(err) => println!("{}", err),
    }
    println!("{}", s);
}

Output:

an error occurred when formatting an argument
0123456789

However, I want to write a formatted string as long as possible, up to the buffer size. In above example, my desired output is 0123456789012345.

In C, we can use snprintf to accomplish this.

#include <stdio.h>
#include <stdlib.h>

int main() {
    char buf[16];
    snprintf(buf, 16, "%s%s", "0123456789", "0123456789");
    printf("%s\n", buf); // output is "012345678901234", due to '\0'
}

How can I do this in rust?

Upvotes: 3

Views: 1051

Answers (1)

rodrigo
rodrigo

Reputation: 98368

You can write your own adaptor for the trait. Something like this:

struct FixedWriter<'a, W>(&'a mut W);

impl<'a, W: Write> Write for FixedWriter<'a, W> {
    fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
        for c in s.chars() {
            self.0.write_char(c)?;
        }
        Ok(())
    } 
}

To use it just wrap a mutable reference of your original writer:

write!(FixedWriter(&mut s), "{}{}", "0123456789", "0123456789");

You can check this playground, that prints 0123456789012345.

You could also eat the error to simulate a success, by replacing the ? operator with:

if self.0.write_char(c).is_err() {
    break;
}

, but it is not clear from the question if you need this.

Upvotes: 5

Related Questions