Expand description
This crate exposes procedural macros that allow you to format bytestrings. For more background on why you would want to do that, read this article.
§Usage
Add this to your Cargo.toml:
[dependencies]
format-bytes = "0.4"Requires Rust 1.85 or later. See the changelog.
Then use the macro like so:
use format_bytes::format_bytes;
fn main() {
assert_eq!(
format_bytes!(b"look at those {} bytes", &[0u8, 1, 2]),
b"look at those \x00\x01\x02 bytes"
);
let path = b"caf\xe9";
assert_eq!(
format_bytes!("{{{path}}} is {len} bytes long", len = path.len()),
b"{caf\xe9} is 4 bytes long"
);
}See more examples of how it works on the documentation of
format_bytes! itself.
Arguments can be of any type that implements DisplayBytes: bytestrings,
integers and floats, Utf8 for std::fmt::Display types, join() for
sequences, and references and smart pointers to those.
§Writing to a stream: write_bytes!
write_bytes! takes a &mut to the stream to write to, followed by the same
arguments as format_bytes!:
use format_bytes::write_bytes;
use std::io;
fn write_entry(out: &mut dyn io::Write, path: &[u8]) -> io::Result<()> {
write_bytes!(out, b"{}: {} bytes\n", path, path.len())
}
fn main() {
let mut out = vec![];
write_entry(&mut out, b"caf\xe9").unwrap();
assert_eq!(out, b"caf\xe9: 4 bytes\n");
}The stream can be any std::io::Write, or any Sink.
§Formatting later: message!
message! takes the same arguments as format_bytes!, but returns a
Message that keeps the format string and the arguments, to be written
later, for example by an error handler. Arguments are moved into the message,
so they must be 'static, Send and Sync.
use format_bytes::{Message, format_bytes, message};
fn unknown_revision(rev: u32) -> Message {
message!("unknown revision {rev}")
}
fn main() {
let msg = unknown_revision(42);
assert_eq!(format_bytes!("abort: {msg}"), b"abort: unknown revision 42");
assert_eq!(msg.template().source, "unknown revision {rev}");
}A Message is itself a DisplayBytes argument. Message::write_to
writes it to a Sink, and Message::template gives the format string,
parsed at compile time.
§Custom output: Sink
A Sink receives the format string separately from each argument and its
name (ArgName). Every std::io::Write is a Sink that writes both
as-is. Other sinks can, for example, tell user data apart from the message
around it:
use format_bytes::{ArgName, DisplayBytes, Sink, write_bytes};
use std::io;
/// Quotes arguments
struct Quoting(Vec<u8>);
impl Sink for Quoting {
fn literal(&mut self, text: &str) -> io::Result<()> {
self.0.literal(text)
}
fn arg(&mut self, _: ArgName, value: &dyn DisplayBytes) -> io::Result<()> {
write_bytes!(&mut self.0, "'{}'", value)
}
}
fn main() {
let mut sink = Quoting(vec![]);
write_bytes!(&mut sink, "cannot open {path}", path = b"caf\xe9").unwrap();
assert_eq!(sink.0, b"cannot open 'caf\xe9'");
}A sink that cares about types for structured output, can call
DisplayBytes::visit with a Visit, which implements methods for
integers, UTF-8 text, bytes, a join() sequence or a nested Message.
§Missing features
format!-like explicit indices ({0}) and format specs ({:?}, padding): if the need manifests itself, they might appear#[no_std]support
§Why not 1.0?
Not until the macro gets a bit of mileage (it will be used in Mercurial).
Macros§
- format_
bytes - Creates a
Vec<u8>using interpolation of runtime expressions. - message
- Creates a
Message: likeformat_bytes!, but the arguments are kept, for aSinkto write later. - write_
bytes - Like
format_bytes!, but writes to a stream given as an additional first argument.
Structs§
- Message
- A format string with its arguments, made by
message!. - Template
- A format string, parsed at compile time.
- Utf8
- Adaptor for types that implement
std::fmt::Display. The Unicode output is encoded as UTF-8.
Enums§
Traits§
- Display
Bytes - Let types decide how to format themselves for presentation to users in a byte-stream output.
- Sink
- Destination of formatting, which keeps the format string’s text apart from its arguments.
- Visit
- Receives a value described by
DisplayBytes::visit.
Functions§
- join
- Format a sequence of values with the given separator repeated between any two consecutive values, but not at the start or end of the sequence.