Let's look at some code first
impl fmt::Write for ByteMutWriter<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let cap = self.capacity();
for (i, &b) in self.buf[self.cursor..cap]
.iter_mut()
.zip(s.as_bytes().iter())
{
*i = b;
}
self.cursor = usize::min(cap, self.cursor + s.as_bytes().len());
Ok(())
}
}
This the meat and potatoes, although I haven't had time to optimise this for performance by any means. Astute readers are welcome to comment and share any improvements this can use.
We can also write this in a functional style. A mutable iterator is created into the shared slice
buf
and then zip
ed with an iterator of the bytes of the provided &str
. This is then completed with for_each
which uses a closure to access the results of zip
, which are bytes of buf
as i
and the bytes of the provided &str
as &b
. self.buf[self.cursor..cap]
.iter_mut()
.zip(s.as_bytes().iter())
.for_each(|(i, &b)| {
*i = b;
});
To use this on multiple values, we need to initialise 2-bytes for each value that needs to be padded. In this particular example, I'm dealing with
values <= 99
. If you need to handle the largest value of a u8
(255), then this will only need 3-bytes.fn main() {
let h = 09u8;
let m = 10u8;
fn left_pad<'a>(buf: &'a mut crate::formatter::ByteMutWriter<'_>, value: u8) -> &'a str {
buf.clear();
write!(buf, "{}{}", if value < 10 { "0" } else { "" }, value).unwrap();
buf.as_str()
}
let mut buf = [0u8; 2];
let mut buf = ByteMutWriter::new(&mut buf[..]);
let hours = left_pad(&mut buf, h);
let mut buf = [0u8; 2];
let mut buf = ByteMutWriter::new(&mut buf[..]);
let seconds = left_pad(&mut buf, m);
println!("hours: {} / seconds: {}", hours, seconds);
}
Click to give this a whirl in the playground.