use std::fmt::{self, Display, Formatter, Write};
use std::ops::Range;
use std::iter::{FlatMap, FusedIterator};
use std::slice;
fn escape_byte(output: &mut [u8; 4], byte: u8) -> Range<u8> {
#[inline]
fn backslash(byte: u8) -> ([u8; 4], u8) {
([b'\\', byte, 0, 0], 2)
}
#[inline]
fn ctrl(byte: u8) -> ([u8; 4], u8) {
([b'^', byte, 0, 0], 2)
}
#[inline]
fn octal(byte: u8) -> ([u8; 4], u8) {
([b'\\', (byte >> 6) + b'0', (byte >> 3 & 7) + b'0', (byte & 7) + b'0'], 4)
}
#[inline]
fn bare(byte: u8) -> ([u8; 4], u8) {
([byte, 0, 0, 0], 1)
}
let (data, len) = match byte {
0x07 => backslash(b'a'), 0x08 => backslash(b'b'), 0x1B => backslash(b'e'), 0x0C => backslash(b'f'), b'\n' => backslash(b'n'), b'\r' => backslash(b'r'),
b'\t' => backslash(b't'),
b'^' => backslash(b'^'),
b'\\' => backslash(b'\\'),
b',' => backslash(b','),
b'\0' => backslash(b'0'),
x if x < 32 => ctrl(x + b'@'), x if x > 126 => octal(x), x => bare(x),
};
*output = data;
0..len
}
#[derive(Clone)]
struct EscapeIter {
data: [u8; 4],
alive: Range<u8>
}
impl EscapeIter {
#[inline]
fn new(&byte: &u8) -> Self {
let mut data = [0; 4];
let alive = escape_byte(&mut data, byte);
Self { data, alive }
}
#[inline]
fn _next(&mut self) -> Option<u8> {
self.alive.next().map(|i| self.data[usize::from(i)])
}
#[inline]
fn _next_back(&mut self) -> Option<u8> {
self.alive.next_back().map(|i| self.data[usize::from(i)])
}
#[inline]
fn _len(&self) -> usize {
usize::from(self.alive.end - self.alive.start)
}
}
impl Iterator for EscapeIter {
type Item = u8;
#[inline]
fn next(&mut self) -> Option<u8> {
self._next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self._len();
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
self._len()
}
#[inline]
fn last(mut self) -> Option<u8> {
self._next_back()
}
}
impl DoubleEndedIterator for EscapeIter {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self._next_back()
}
}
impl ExactSizeIterator for EscapeIter {
#[inline]
fn len(&self) -> usize {
self._len()
}
}
impl FusedIterator for EscapeIter {}
#[derive(Clone)]
pub struct EscapeTerminfo<'a> {
inner: FlatMap<slice::Iter<'a, u8>, EscapeIter, fn(&u8) -> EscapeIter>
}
impl<'a> Iterator for EscapeTerminfo<'a> {
type Item = u8;
#[inline]
fn next(&mut self) -> Option<u8> {
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.fold(init, fold)
}
#[inline]
fn last(mut self) -> Option<u8> {
self.next_back()
}
}
impl<'a> DoubleEndedIterator for EscapeTerminfo<'a> {
fn next_back(&mut self) -> Option<u8> {
self.inner.next_back()
}
}
impl<'a> FusedIterator for EscapeTerminfo<'a> {}
impl<'a> Display for EscapeTerminfo<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.clone().try_for_each(|b| f.write_char(b as char))
}
}
pub fn escape_terminfo(slice: &[u8]) -> EscapeTerminfo {
EscapeTerminfo { inner: slice.iter().flat_map(EscapeIter::new) }
}