Skip to main content

libtw2_common/
pretty.rs

1use arrayvec::ArrayVec;
2use std::ascii;
3use std::fmt;
4use std::mem;
5use std::ops;
6use std::str;
7
8pub struct AlmostString([u8]);
9
10impl AlmostString {
11    pub fn new(bytes: &[u8]) -> &AlmostString {
12        unsafe { mem::transmute(bytes) }
13    }
14}
15
16pub struct AlmostStringSlice<'a>([&'a [u8]]);
17
18impl<'a> AlmostStringSlice<'a> {
19    pub fn new<'b>(bytes_slice: &'b [&'a [u8]]) -> &'b AlmostStringSlice<'a> {
20        unsafe { mem::transmute(bytes_slice) }
21    }
22}
23
24pub struct Bytes([u8]);
25
26impl Bytes {
27    pub fn new(bytes: &[u8]) -> &Bytes {
28        unsafe { mem::transmute(bytes) }
29    }
30}
31
32pub struct BytesSlice<'a>([&'a [u8]]);
33
34impl<'a> BytesSlice<'a> {
35    pub fn new<'b>(bytes_slice: &'b [&'a [u8]]) -> &'b BytesSlice<'a> {
36        unsafe { mem::transmute(bytes_slice) }
37    }
38}
39
40struct Byte {
41    string: ArrayVec<[u8; 4]>,
42}
43
44impl Byte {
45    fn new(byte: u8) -> Byte {
46        let mut string = ArrayVec::new();
47        if byte == b'\\' || byte == b'\"' {
48            string.push(b'\\');
49            string.push(byte);
50        } else {
51            string.extend(ascii::escape_default(byte));
52        }
53        Byte { string: string }
54    }
55}
56
57impl ops::Deref for Byte {
58    type Target = str;
59    fn deref(&self) -> &str {
60        unsafe { str::from_utf8_unchecked(&self.string) }
61    }
62}
63
64impl fmt::Debug for Bytes {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        f.write_str("b\"")?;
67        for &byte in &self.0 {
68            f.write_str(&Byte::new(byte))?;
69        }
70        f.write_str("\"")?;
71        Ok(())
72    }
73}
74
75impl<'a> fmt::Debug for BytesSlice<'a> {
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        f.debug_list()
78            .entries(self.0.iter().cloned().map(Bytes::new))
79            .finish()
80    }
81}
82
83impl fmt::Debug for AlmostString {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        // FIXME: Replace this with a UTF-8 decoder.
86        let string = String::from_utf8_lossy(&self.0);
87        fmt::Debug::fmt(&string, f)
88    }
89}
90
91impl fmt::Display for AlmostString {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        // FIXME: Replace this with a UTF-8 decoder.
94        let string = String::from_utf8_lossy(&self.0);
95        if string.chars().any(|c| c < ' ' || c == '"') {
96            fmt::Debug::fmt(&string, f)
97        } else {
98            fmt::Display::fmt(&string, f)
99        }
100    }
101}
102
103impl<'a> fmt::Debug for AlmostStringSlice<'a> {
104    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105        f.debug_list()
106            .entries(self.0.iter().cloned().map(AlmostString::new))
107            .finish()
108    }
109}