Crate aya_ufmt

Crate aya_ufmt 

Source
Expand description

μfmt, a (6-40x) smaller, (2-9x) faster and panic-free alternative to core::fmt

§Design goals

From highest priority to lowest priority

  • Optimized for binary size and speed (rather than for compilation time)
  • No dynamic dispatch in generated code
  • No panicking branches in generated code, when optimized
  • No recursion where possible

§Features

§Non-features

These are out of scope

  • Padding, alignment and other formatting options
  • Formatting floating point numbers

§Examples

  • uwrite! / uwriteln!
use ufmt::{derive::uDebug, uwrite};

#[derive(uDebug)]
struct Pair { x: u32, y: u32 }

let mut s = String::new();
let pair = Pair { x: 1, y: 2 };
uwrite!(s, "{:?}", pair).unwrap();
assert_eq!(s, "Pair { x: 1, y: 2 }");
  • implementing uWrite

When implementing the uWrite trait you should prefer the ufmt_write::uWrite crate over the ufmt::uWrite crate for better forward compatibility.

use core::convert::Infallible;

use ufmt_write::uWrite;

struct MyWriter;

impl uWrite for MyWriter {
    type Error = Infallible;

    fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
        // ..
        Ok(())
    }
}
  • writing a macro_rules! macro that uses uwrite! (or uwriteln!).

Both ufmt macros are implemented using proc-macro-hack; care is needed to avoid running into the compiler bug #43081. See also dtolnay/proc-macro-hack#46.

// like `std::format!` it returns a `std::String` but uses `uwrite!` instead of `write!`
macro_rules! uformat {
    // IMPORTANT use `tt` fragments instead of `expr` fragments (i.e. `$($exprs:expr),*`)
    ($($tt:tt)*) => {{
        let mut s = String::new();
        match ufmt::uwrite!(&mut s, $($tt)*) {
            Ok(_) => Ok(s),
            Err(e) => Err(e),
        }
    }}
}

§Benchmarks

The benchmarks ran on a ARM Cortex-M3 chip (thumbv7m-none-eabi).

The benchmarks were compiled with nightly-2019-05-01, -C opt-level=3, lto = true, codegen-units = 1.

In all benchmarks x = i32::MIN and y = i32::MIN plus some obfuscation was applied to prevent const-propagation of the *write! arguments.

The unit of time is one core clock cycle: 125 ns (8 MHz)

The .text and .rodata columns indicate the delta (in bytes) when commenting out the *write! statement.

CodeTime%.text%.rodata%
write!("Hello, world!")154~1906~248~
uwrite!("Hello, world!")2013.0%341.8%166.5%
write!(w, "{}", 0i32)256~1958~232~
uwrite!(w, "{}", 0i32)3714.5%28814.7%00%
write!(w, "{}", x)381~
uwrite!(w, "{}", x)29577.4%
write!(w, "{:?}", Pair { x: 0, y: 0 })996~4704~312~
uwrite!(w, "{:?}", Pair { x: 0, y: 0 })25425.5%75216.0%247.7%
write!(w, "{:?}", Pair { x, y })1264~
uwrite!(w, "{:?}", Pair { x, y })77661.4%
write!(w, "{:#?}", Pair { x: 0, y: 0 })2853~4710~348~
uwrite!(w, "{:#?}", Pair { x: 0, y: 0 })30110.6%75416.0%246.9%
write!(w, "{:#?}", Pair { x, y })3693~
uwrite!(w, "{:#?}", Pair { x, y })82322.3%

Benchmark program:

static X: AtomicI32 = AtomicI32::new(i32::MIN); // or `0`
static Y: AtomicI32 = AtomicI32::new(i32::MIN); // or `0`

#[exception]
fn PendSV() {
   // read DWT.CYCCNT here

   let x = X.load(Ordering::Relaxed);
   let y = Y.load(Ordering::Relaxed);

   let p = Pair { x, y };

   uwrite!(&mut W, "{:#?}", p).ok();

   // write!(&mut W, "{:#?}", p).ok();

   asm::bkpt(); // read DWT.CYCCNT here
}

Writer used in the benchmarks:

use core::{convert::Infallible, fmt, ptr};

use ufmt::uWrite;

struct W;

impl uWrite for W {
    type Error = Infallible;

    fn write_str(&mut self, s: &str) -> Result<(), Infallible> {
        s.as_bytes()
            .iter()
            .for_each(|b| unsafe { drop(ptr::read_volatile(b)) });

        Ok(())
    }
}

impl fmt::Write for W {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        s.as_bytes()
            .iter()
            .for_each(|b| unsafe { drop(ptr::read_volatile(b)) });

        Ok(())
    }
}

§Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.34 and up. It might compile on older versions but that may change in any new patch release.

Modules§

derive
Derive macros

Macros§

uwrite
Write formatted data into a buffer
uwriteln
Write formatted data into a buffer, with a newline appended

Structs§

DebugList
A struct to help with uDebug implementations.
DebugMap
A struct to help with uDebug implementations.
DebugStruct
A struct to help with uDebug implementations.
DebugTuple
A struct to help with uDebug implementations.
Formatter
Configuration for formatting

Traits§

uDebug
Just like core::fmt::Debug
uDisplay
Just like core::fmt::Display
uWrite
A collection of methods that are required / used to format a message into a stream.