use std::fmt;
use std::io;
#[macro_export]
macro_rules! format_bytes {
($($args: tt)*) => {{
let mut vec = Vec::<u8>::new();
$crate::write_bytes!(&mut vec, $($args)*)
.unwrap();
vec
}}
}
#[doc(hidden)]
pub use format_bytes_macros::{_message, _write_bytes};
#[macro_export]
macro_rules! write_bytes {
($($args: tt)*) => {
$crate::_write_bytes!([$crate] $($args)*)
};
}
pub trait DisplayBytes {
fn display_bytes(&self, output: &mut dyn io::Write) -> io::Result<()>;
fn visit(&self, visitor: &mut dyn Visit) -> io::Result<()> {
let mut bytes = vec![];
self.display_bytes(&mut bytes)?;
visitor.bytes(&bytes)
}
}
pub trait Visit {
fn bytes(&mut self, value: &[u8]) -> io::Result<()>;
fn str(&mut self, value: &str) -> io::Result<()>;
fn int(&mut self, value: i128) -> io::Result<()> {
self.str(&value.to_string())
}
fn uint(&mut self, value: u128) -> io::Result<()> {
self.str(&value.to_string())
}
fn seq(
&mut self,
items: &[&dyn DisplayBytes],
separator: &dyn DisplayBytes,
) -> io::Result<()> {
let mut bytes = vec![];
join(items, separator).display_bytes(&mut bytes)?;
self.bytes(&bytes)
}
fn message(&mut self, message: &Message) -> io::Result<()> {
let mut bytes = vec![];
message.display_bytes(&mut bytes)?;
self.bytes(&bytes)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArgName {
Index(usize),
Name(&'static str),
}
pub trait Sink {
fn literal(&mut self, text: &str) -> io::Result<()>;
fn arg(
&mut self,
name: ArgName,
value: &dyn DisplayBytes,
) -> io::Result<()>;
}
impl<W: io::Write + ?Sized> Sink for W {
fn literal(&mut self, text: &str) -> io::Result<()> {
self.write_all(text.as_bytes())
}
fn arg(&mut self, _: ArgName, value: &dyn DisplayBytes) -> io::Result<()> {
value.display_bytes(&mut &mut *self)
}
}
#[macro_export]
macro_rules! message {
($($args: tt)*) => {
$crate::_message!([$crate] $($args)*)
};
}
#[derive(Debug)]
pub struct Template {
pub source: &'static str,
pub pieces: &'static [Piece],
pub args: &'static [ArgName],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Piece {
Literal(&'static str),
Arg(usize),
}
pub struct Message {
template: &'static Template,
args: Vec<Box<dyn DisplayBytes + Send + Sync>>,
}
impl Message {
#[doc(hidden)]
pub fn new(
template: &'static Template,
args: Vec<Box<dyn DisplayBytes + Send + Sync>>,
) -> Self {
Self { template, args }
}
pub fn template(&self) -> &'static Template {
self.template
}
pub fn arg(&self, index: usize) -> &dyn DisplayBytes {
&*self.args[index]
}
pub fn write_to(&self, sink: &mut dyn Sink) -> io::Result<()> {
for piece in self.template.pieces {
match *piece {
Piece::Literal(text) => sink.literal(text)?,
Piece::Arg(index) => {
sink.arg(self.template.args[index], self.arg(index))?
}
}
}
Ok(())
}
}
impl DisplayBytes for Message {
fn display_bytes(&self, mut output: &mut dyn io::Write) -> io::Result<()> {
self.write_to(&mut output)
}
fn visit(&self, visitor: &mut dyn Visit) -> io::Result<()> {
visitor.message(self)
}
}
impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut bytes = vec![];
self.write_to(&mut bytes).map_err(|_| fmt::Error)?;
f.debug_tuple("Message")
.field(&String::from_utf8_lossy(&bytes))
.finish()
}
}
macro_rules! impl_through_deref {
($Inner: ident => $( $Wrapper: ty, )*) => {
$(
impl<$Inner: ?Sized + DisplayBytes> DisplayBytes for $Wrapper {
#[inline]
fn display_bytes(&self, output: &mut dyn io::Write) -> io::Result<()> {
(**self).display_bytes(output)
}
#[inline]
fn visit(&self, visitor: &mut dyn Visit) -> io::Result<()> {
(**self).visit(visitor)
}
}
)*
};
}
impl_through_deref! {
Inner =>
&'_ Inner,
&'_ mut Inner,
Box<Inner>,
std::rc::Rc<Inner>,
std::sync::Arc<Inner>,
}
impl<Inner> DisplayBytes for std::borrow::Cow<'_, Inner>
where
Inner: ?Sized + ToOwned + DisplayBytes,
{
#[inline]
fn display_bytes(&self, output: &mut dyn io::Write) -> io::Result<()> {
(**self).display_bytes(output)
}
#[inline]
fn visit(&self, visitor: &mut dyn Visit) -> io::Result<()> {
(**self).visit(visitor)
}
}
macro_rules! impl_for_byte_string {
($($Ty: ty),+) => {
$(
impl DisplayBytes for $Ty {
#[inline]
fn display_bytes(&self, output: &mut dyn io::Write) -> io::Result<()> {
output.write_all(self)
}
}
)+
};
}
impl_for_byte_string!([u8], Vec<u8>);
macro_rules! impl_for_arrays {
($( $LEN: expr )+) => {
impl_for_byte_string! {
$( [u8; $LEN] ),+
}
};
}
impl_for_arrays! {
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
}
pub struct Utf8<Inner>(pub Inner);
impl<Inner: fmt::Display> DisplayBytes for Utf8<Inner> {
fn display_bytes(&self, output: &mut dyn io::Write) -> io::Result<()> {
struct Adapter<'a> {
output: &'a mut dyn io::Write,
result: io::Result<()>,
}
impl fmt::Write for Adapter<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
if self.result.is_err() {
return Err(fmt::Error);
}
let utf8 = s.as_bytes();
match self.output.write_all(utf8) {
Ok(()) => Ok(()),
Err(error) => {
self.result = Err(error);
Err(fmt::Error)
}
}
}
}
let mut adapter = Adapter {
output,
result: Ok(()),
};
{
use fmt::Write;
write!(adapter, "{}", self.0)
.map_err(|fmt::Error| adapter.result.unwrap_err())
}
}
fn visit(&self, visitor: &mut dyn Visit) -> io::Result<()> {
visitor.str(&self.0.to_string())
}
}
macro_rules! impl_ascii_only {
($( $Ty: ident )* => |$value: ident, $visitor: ident| $visit: expr) => {
$(
impl DisplayBytes for $Ty {
#[inline]
fn display_bytes(&self, output: &mut dyn io::Write) -> io::Result<()> {
Utf8(self).display_bytes(output)
}
#[inline]
fn visit(&self, $visitor: &mut dyn Visit) -> io::Result<()> {
let $value = *self;
$visit
}
}
)*
};
}
impl_ascii_only! {
u8 u16 u32 u64 u128 usize => |value, visitor| visitor.uint(value as u128)
}
impl_ascii_only! {
i8 i16 i32 i64 i128 isize => |value, visitor| visitor.int(value as i128)
}
impl_ascii_only! {
f32 f64 => |value, visitor| visitor.str(&value.to_string())
}
pub fn join(
iterable: impl IntoIterator<Item = impl DisplayBytes>,
separator: impl DisplayBytes,
) -> impl DisplayBytes {
Join {
items: iterable.into_iter().collect::<Vec<_>>(),
separator,
}
}
struct Join<T, S> {
items: Vec<T>,
separator: S,
}
impl<T: DisplayBytes, S: DisplayBytes> DisplayBytes for Join<T, S> {
fn display_bytes(&self, output: &mut dyn io::Write) -> io::Result<()> {
for (i, item) in self.items.iter().enumerate() {
if i > 0 {
self.separator.display_bytes(output)?;
}
item.display_bytes(output)?;
}
Ok(())
}
fn visit(&self, visitor: &mut dyn Visit) -> io::Result<()> {
let items: Vec<&dyn DisplayBytes> =
self.items.iter().map(|item| item as _).collect();
visitor.seq(&items, &self.separator)
}
}