jay-compositor 1.15.0

The Jay compositor
use crate::fixed::Fixed;
use crate::utils::spaces::spaces;
use crate::utils::str_fmt::StrCtx;
use crate::utils::str_fmt::StrFmt;
use crate::utils::str_fmt::StrFmtFmt;
use arrayvec::ArrayVec;
use bstr::BStr;
use std::borrow::Borrow;
use std::borrow::Cow;
use std::cell::OnceCell;
use std::rc::Rc;
use uapi::OwnedFd;

impl<T> StrFmt for [T]
where
    T: StrFmt,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        let ctx = &StrCtx {
            toplevel: false,
            ..*ctx
        };
        match ctx.fmt {
            StrFmtFmt::Human => {
                let cctx = &StrCtx {
                    spaces: &spaces(ctx.spaces.len() + 2),
                    ..*ctx
                };
                for (idx, v) in self.iter().enumerate() {
                    if idx > 0 {
                        dst.push_str("\n");
                        dst.push_str(&ctx.prefix);
                        dst.push_str(&ctx.spaces);
                    }
                    dst.push_str("- ");
                    v.str_fmt(dst, cctx);
                }
            }
            StrFmtFmt::Jsonl => {
                dst.push_str("[");
                for (idx, v) in self.iter().enumerate() {
                    if idx > 0 {
                        dst.push_str(",");
                    }
                    v.str_fmt(dst, ctx);
                }
                dst.push_str("]");
            }
            StrFmtFmt::Trace => {
                dst.push_str("[");
                for (idx, v) in self.iter().enumerate() {
                    if idx > 0 {
                        dst.push_str(", ");
                    }
                    v.str_fmt(dst, ctx);
                }
                dst.push_str("]");
            }
        }
    }
}

impl<T, const N: usize> StrFmt for [T; N]
where
    T: StrFmt,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        self[..].str_fmt(dst, ctx);
    }
}

impl StrFmt for BStr {
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        if ctx.toplevel && ctx.fmt == StrFmtFmt::Human {
            for chunk in self.utf8_chunks() {
                dst.push_str(chunk.valid());
                for _ in 0..chunk.invalid().len() {
                    dst.push_str("�");
                }
            }
            return;
        }
        dst.push_str("\"");
        for chunk in self.utf8_chunks() {
            fmt_str(dst, chunk.valid(), ctx);
            for _ in 0..chunk.invalid().len() {
                dst.push_str("�");
            }
        }
        dst.push_str("\"");
    }
}

impl StrFmt for str {
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        if ctx.toplevel && ctx.fmt == StrFmtFmt::Human {
            dst.push_str(self);
            return;
        }
        dst.push_str("\"");
        fmt_str(dst, self, ctx);
        dst.push_str("\"");
    }
}

fn fmt_str(dst: &mut String, b: &str, ctx: &StrCtx<'_>) {
    let dst = unsafe { dst.as_mut_vec() };
    for &b in b.as_bytes() {
        match b {
            b'\n' => dst.extend_from_slice(b"\\n"),
            b'\r' => dst.extend_from_slice(b"\\r"),
            b'\t' => dst.extend_from_slice(b"\\t"),
            b'\x00'..=b'\x1f' => {
                if ctx.fmt == StrFmtFmt::Jsonl {
                    dst.extend_from_slice(b"\\u00");
                } else {
                    dst.extend_from_slice(b"\\x");
                }
                static HEX: [u8; 16] = *b"0123456789abcdef";
                let lo = ((b >> 0) & 0xf) as usize;
                let hi = ((b >> 4) & 0xf) as usize;
                dst.push(HEX[hi]);
                dst.push(HEX[lo]);
            }
            b'"' => dst.extend_from_slice(b"\\\""),
            b'\\' => dst.extend_from_slice(b"\\\\"),
            _ => dst.push(b),
        }
    }
}

macro_rules! integer {
    ($ty:ty) => {
        impl StrFmt for $ty {
            fn str_fmt(&self, dst: &mut String, _ctx: &StrCtx<'_>) {
                let mut buf = itoa::Buffer::new();
                let str = buf.format(*self);
                dst.push_str(str);
            }
        }
    };
}

integer!(u8);
integer!(u16);
integer!(u32);
integer!(u64);
integer!(u128);
integer!(usize);
integer!(i8);
integer!(i16);
integer!(i32);
integer!(i64);
integer!(i128);
integer!(isize);

macro_rules! float {
    ($ty:ty) => {
        impl StrFmt for $ty {
            fn str_fmt(&self, dst: &mut String, _ctx: &StrCtx<'_>) {
                let mut buf = zmij::Buffer::new();
                let str = buf.format(*self);
                dst.push_str(str);
            }
        }
    };
}

float!(f32);
float!(f64);

impl StrFmt for Fixed {
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        self.to_f64().str_fmt(dst, ctx);
    }
}

impl StrFmt for bool {
    fn str_fmt(&self, dst: &mut String, _ctx: &StrCtx<'_>) {
        match *self {
            true => dst.push_str("true"),
            false => dst.push_str("false"),
        }
    }
}

impl<T> StrFmt for &T
where
    T: StrFmt + ?Sized,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        T::str_fmt(*self, dst, ctx);
    }
}

impl<T> StrFmt for Option<T>
where
    T: StrFmt,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        match self {
            None if ctx.fmt == StrFmtFmt::Jsonl => dst.push_str("null"),
            None => dst.push_str("nil"),
            Some(v) => v.str_fmt(dst, ctx),
        }
    }
}

impl<A, B> StrFmt for (A, B)
where
    A: StrFmt,
    B: StrFmt,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        ctx.struct_prefix(dst);
        ctx.struct_field(dst, "0", &self.0, true);
        ctx.struct_field(dst, "1", &self.1, false);
        ctx.struct_suffix(dst);
    }
}

impl<T> StrFmt for Rc<T>
where
    T: StrFmt + ?Sized,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        T::str_fmt(self, dst, ctx);
    }
}

impl<T> StrFmt for OnceCell<T>
where
    T: StrFmt,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        self.get().str_fmt(dst, ctx);
    }
}

impl<T> StrFmt for Box<T>
where
    T: StrFmt + ?Sized,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        T::str_fmt(self, dst, ctx);
    }
}

impl<T> StrFmt for Cow<'_, T>
where
    T: ToOwned + StrFmt + ?Sized,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        let t: &T = self.borrow();
        t.str_fmt(dst, ctx);
    }
}

impl StrFmt for OwnedFd {
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        self.raw().str_fmt(dst, ctx);
    }
}

impl<T, const N: usize> StrFmt for ArrayVec<T, N>
where
    T: StrFmt,
{
    fn str_fmt(&self, dst: &mut String, ctx: &StrCtx<'_>) {
        self.as_slice().str_fmt(dst, ctx);
    }
}