1#![doc = include_str!("../README.md")]
8#![no_std]
9
10pub struct MaybeAscii<'a> {
15 pub bytes: &'a [u8],
16}
17
18impl<'a> core::fmt::Debug for MaybeAscii<'a> {
19 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
20 let mut start = 0;
21 while start < self.bytes.len() {
22 let is_ascii = self.bytes[start] < 128;
23 let mut end = start + 1;
24 loop {
25 if end >= self.bytes.len() {
26 break;
27 }
28 if (self.bytes[end] < 128) != is_ascii {
29 break;
30 }
31 end += 1;
32 }
33 if is_ascii {
34 let s = core::str::from_utf8(&self.bytes[start..end]).expect("The slice should only contain ascii characters (<128) which should be convertible to a utf8 string.");
35 f.write_str(s)?;
36 } else {
37 self.bytes[start..end].fmt(f)?;
38 }
39 start = end;
40 }
41 Ok(())
42 }
43}
44
45pub fn try_ascii(bytes: &[u8]) -> MaybeAscii<'_> {
48 MaybeAscii { bytes }
49}
50
51pub trait TryAscii {
55 fn try_ascii(&self) -> MaybeAscii<'_>;
56}
57
58impl TryAscii for [u8] {
59 fn try_ascii(&self) -> MaybeAscii<'_> {
60 try_ascii(self)
61 }
62}
63
64impl TryAscii for &[u8] {
65 fn try_ascii(&self) -> MaybeAscii<'_> {
66 try_ascii(self)
67 }
68}
69
70impl TryAscii for dyn AsRef<[u8]> {
71 fn try_ascii(&self) -> MaybeAscii<'_> {
72 try_ascii(self.as_ref())
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 extern crate std;
79 use crate::try_ascii;
80 use crate::TryAscii;
81 use std::*;
82
83 #[test]
84 fn format_ascii() {
85 let res = format!("{:?}", try_ascii(b"Hello, World"));
86 assert_eq!(res, "Hello, World");
87 }
88
89 #[test]
90 fn format_non_ascii() {
91 let res = format!("{:?}", try_ascii(b"Hello, \xa0"));
92 assert_eq!(res, "Hello, [160]");
93 }
94
95 #[test]
96 fn format_slice() {
97 let res = format!("{:?}", try_ascii(b"Hello, \xa0\xa1\xa2\xa3"));
98 assert_eq!(res, "Hello, [160, 161, 162, 163]");
99 }
100
101 #[test]
102 fn format_hex() {
103 let res = format!("{:x?}", try_ascii(b"Hello, \xa0\xa1\xa2\xa3"));
104 assert_eq!(res, "Hello, [a0, a1, a2, a3]");
105 }
106
107 #[test]
108 fn format_pretty() {
109 let res = format!("{:#X?}", try_ascii(&[0xa0, 0xa1]));
110 assert_eq!(res, "[\n 0xA0,\n 0xA1,\n]");
111 }
112
113 #[test]
114 fn format_empty() {
115 let res = format!("{:?}", try_ascii(&[]));
116 assert_eq!(res, "");
117 }
118
119 #[test]
120 fn trait_for_u8() {
121 let res = format!("{:x?}", b"Hello, \xa0\xa1\xa2\xa3".try_ascii());
122 assert_eq!(res, "Hello, [a0, a1, a2, a3]");
123 }
124
125 #[test]
126 fn trait_for_ref_u8() {
127 let arr: &[u8] = b"Hello, \xa0\xa1\xa2\xa3";
128 let res = format!("{:x?}", arr.try_ascii());
129 assert_eq!(res, "Hello, [a0, a1, a2, a3]");
130 }
131
132 #[test]
133 fn trait_for_as_ref_u8() {
134 let arr: [u8; 11] = *b"Hello, \xa0\xa1\xa2\xa3";
135 let res = format!("{:x?}", arr.as_ref().try_ascii());
136 assert_eq!(res, "Hello, [a0, a1, a2, a3]");
137 }
138}