From f39ff819225182bbd5f76c029cbc3920c4a4d11a Mon Sep 17 00:00:00 2001 From: Berkus Decker Date: Sun, 20 Jan 2019 02:24:38 +0200 Subject: [PATCH] Add write_to helper --- src/main.rs | 1 + src/platform/uart.rs | 6 ++-- src/write_to.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/write_to.rs diff --git a/src/main.rs b/src/main.rs index 4a9f1e9..0918c53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ extern crate rlibc; pub mod arch; pub use arch::*; pub mod platform; +mod write_to; use core::fmt::Write; use platform::{ diff --git a/src/platform/uart.rs b/src/platform/uart.rs index 0b05df1..757ba1c 100644 --- a/src/platform/uart.rs +++ b/src/platform/uart.rs @@ -1,5 +1,5 @@ use arch::*; -use core::ops; +use core::{fmt, ops}; use platform::{gpio, rpi3::PERIPHERAL_BASE}; use register::mmio::*; @@ -232,8 +232,8 @@ impl MiniUart { } } -impl core::fmt::Write for MiniUart { - fn write_str(&mut self, s: &str) -> core::fmt::Result { +impl fmt::Write for MiniUart { + fn write_str(&mut self, s: &str) -> fmt::Result { self.puts(s); Ok(()) } diff --git a/src/write_to.rs b/src/write_to.rs new file mode 100644 index 0000000..42d2023 --- /dev/null +++ b/src/write_to.rs @@ -0,0 +1,69 @@ +// No-alloc write!() implementation from https://stackoverflow.com/a/50201632/145434 +// Requires you to allocate a buffer somewhere manually. +// + +use core::cmp::min; +use core::fmt; + +pub struct WriteTo<'a> { + buffer: &'a mut [u8], + // on write error (i.e. not enough space in buffer) this grows beyond + // `buffer.len()`. + used: usize, +} + +impl<'a> WriteTo<'a> { + pub fn new(buffer: &'a mut [u8]) -> Self { + WriteTo { buffer, used: 0 } + } + + pub fn as_str(self) -> Option<&'a str> { + if self.used <= self.buffer.len() { + // only successful concats of str - must be a valid str. + use core::str::from_utf8_unchecked; + Some(unsafe { from_utf8_unchecked(&self.buffer[..self.used]) }) + } else { + None + } + } +} + +impl<'a> fmt::Write for WriteTo<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + if self.used > self.buffer.len() { + return Err(fmt::Error); + } + let remaining_buf = &mut self.buffer[self.used..]; + let raw_s = s.as_bytes(); + let write_num = min(raw_s.len(), remaining_buf.len()); + remaining_buf[..write_num].copy_from_slice(&raw_s[..write_num]); + self.used += raw_s.len(); + if write_num < raw_s.len() { + Err(fmt::Error) + } else { + Ok(()) + } + } +} + +pub fn show<'a>(buffer: &'a mut [u8], args: fmt::Arguments) -> Result<&'a str, fmt::Error> { + let mut w = WriteTo::new(buffer); + fmt::write(&mut w, args)?; + w.as_str().ok_or(fmt::Error) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + pub fn test() { + let mut buf = [0u8; 64]; + let s: &str = show( + &mut buf, + format_args!("write some stuff {:?}: {}", "foo", 42), + ) + .unwrap(); + assert_eq!(s, "write some stuff foo: 42"); + } +}