Skip to main content

base256u/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3/// Encoder iterator, converting bytes into unicode chars based on the contained encoding callable.
4pub struct Encoder<I, F>
5where
6    I: Iterator<Item = u8>,
7    F: Fn(u8) -> char,
8{
9    iterator: I,
10    encode: F,
11}
12
13impl<I, F> Encoder<I, F>
14where
15    I: Iterator<Item = u8>,
16    F: Fn(u8) -> char,
17{
18    pub fn new(iterator: I, encode: F) -> Self {
19        Self { iterator, encode }
20    }
21}
22
23impl<I, F> Iterator for Encoder<I, F>
24where
25    I: Iterator<Item = u8>,
26    F: Fn(u8) -> char,
27{
28    type Item = char;
29
30    fn next(&mut self) -> Option<Self::Item> {
31        self.iterator.next().map(|byte| (self.encode)(byte))
32    }
33}
34
35/// Encoder iterator, converting unicode chars into bytes based on the contained decoding callable.
36/// Must be fallible because not all unicode codepoints are valid bytes.
37pub struct Decoder<I, F>
38where
39    I: Iterator<Item = char>,
40    F: Fn(char) -> Option<u8>,
41{
42    iterator: I,
43    decode: F,
44}
45
46impl<I, F> Decoder<I, F>
47where
48    I: Iterator<Item = char>,
49    F: Fn(char) -> Option<u8>,
50{
51    pub fn new(iterator: I, decode: F) -> Self {
52        Self { iterator, decode }
53    }
54}
55
56impl<I, F> Iterator for Decoder<I, F>
57where
58    I: Iterator<Item = char>,
59    F: Fn(char) -> Option<u8>,
60{
61    type Item = Option<u8>;
62
63    fn next(&mut self) -> Option<Self::Item> {
64        self.iterator.next().map(|byte| (self.decode)(byte))
65    }
66}
67
68/// Encode function for encoding to a straight 1-to-1 byte-to-codepoint conversion.
69pub fn encode_basic(byte: u8) -> char {
70    byte as char
71}
72
73/// Decoding function for encoding to a straight 1-to-1 byte-to-codepoint conversion.
74pub fn decode_basic(c: char) -> Option<u8> {
75    c.try_into().ok()
76}
77
78/// Encode function for encoding to printable-ascii-preserving Unicode.
79/// `0x00..=0x1F` is mapped to the range starting at `U+B0` to map into the Latin-1 Supplement block in the first range that is 8-byte aligned and fully printable, skipping `NBSP` and `SHY`.
80/// `0x20..=0x7E` are mapped to the same bytes as printable ASCII.
81/// `0x7F` is arbitrarily mapped from ASCII ESC to §.
82/// `0x80..=0xFF`  mapped to the range starting at `U+100`, Latin Extended-A, with the exception of
83/// `0xC9`, which is mapped arbitrarily to `¤` to avoid the deprecated character at that codepoint.
84pub fn encode_papu(byte: u8) -> char {
85    match byte {
86        b @ 0x00..=0x1F => (b + 0xB0) as char,
87        b @ 0x20..=0x7E => b as char,
88        0x7F => '§',
89        // Unsafe is fine here because these ranges are known to be safe char values.
90        b @ (0x80..=0xC8 | 0xCA..) => unsafe { char::from_u32_unchecked(b as u32 + 0x80) },
91        0xC9 => '¤',
92    }
93}
94
95/// Decode function for printable-ascii-preserving Unicode.
96/// All values are mapped as the inverse of encode_papu.  All other input chars map to None.
97pub const fn decode_papu(c: char) -> Option<u8> {
98    Some(match c as u32 {
99        b @ 0xB0..=0xCF => (b - 0xB0) as u8,
100        b @ 0x20..=0x7E => b as u8,
101        0xA7 => 0x7F,
102        b @ (0x100..=0x148 | 0x14A..=0x17F) => (b - 0x80) as u8,
103        0xA4 => 0xC9,
104        _ => return None,
105    })
106}
107
108/// Encode function for encoding to tight-printable-ascii-preserving Unicode.
109/// Similar to papu, but packed as tightly as possible while mapping to all printable characters, skipping deprecated and invisible characters (SHY and NSBP, primarily).
110/// `0x00..=0x0B` is mapped to `U+A1..=U+AC`
111/// `0x0C..=0x1F` is mapped to `U+AE..=U+C1`
112/// `0x20..=0x7E` are mapped to the same bytes as printable ASCII.
113/// `0x7F..=0xFF` is mapped to `U+C2..=U+142`
114pub fn encode_tpapu(byte: u8) -> char {
115    match byte {
116        b @ 0x00..=0x0B => (b + 0xA1) as char,
117        b @ 0x0C..=0x1F => (b + (0xAE - 0x0C)) as char,
118        b @ 0x20..=0x7E => b as char,
119        b @ 0x7F..=0xFF => unsafe { char::from_u32_unchecked(b as u32 + (0xC2 - 0x7F)) },
120    }
121}
122
123/// Decode function for decoding from tight-printable-ascii-preserving Unicode.
124pub fn decode_tpapu(c: char) -> Option<u8> {
125    Some(match c as u32 {
126        b @ 0xA1..=0xAC => (b - 0xA1) as u8,
127        b @ 0xAE..=0xC1 => (b - (0xAE - 0x0C)) as u8,
128        b @ 0x20..=0x7E => b as u8,
129        b @ 0xC2..=0x142 => (b - (0xC2 - 0x7F)) as u8,
130        _ => return None,
131    })
132}
133
134/// Encode function for encoding to emoji.
135/// `0x00..=0x4F` is mapped to the range starting at `U+1F370` For some plants and foods.
136/// `0x50..=0x8F` is mapped to the range starting at `U+1F400` for animals.
137/// `0x90..=0xDF` is mapped to the range starting at `U+1F600` for expressions and hand signs.
138/// `0xE0..=0xFF` is mapped to the range starting at `U+1F910` for more expressions and hand signs.
139pub fn encode_emoji(byte: u8) -> char {
140    match byte {
141        b @ 0x00..=0x4F => unsafe { char::from_u32_unchecked(b as u32 + 0x1F330) },
142        b @ 0x50..=0x8F => unsafe { char::from_u32_unchecked(b as u32 + (0x1F400 - 0x50)) },
143        b @ 0x90..=0xDF => unsafe { char::from_u32_unchecked(b as u32 + (0x1F600 - 0x90)) },
144        b @ 0xE0..=0xFF => unsafe { char::from_u32_unchecked(b as u32 + (0x1F910 - 0xE0)) },
145    }
146}
147
148/// Decode function for emoji.
149/// All values are mapped as the inverse of encode_emoji.  All other input chars map to None.
150pub const fn decode_emoji(c: char) -> Option<u8> {
151    Some(match c as u32 {
152        b @ 0x1F330..=0x1F37F => (b - 0x1F330) as u8,
153        b @ 0x1F400..=0x1F43F => (b - (0x1F400 - 0x50)) as u8,
154        b @ 0x1F600..=0x1F64F => (b - (0x1F600 - 0x90)) as u8,
155        b @ 0x1F910..=0x1F92F => (b - (0x1F910 - 0xE0)) as u8,
156        _ => return None,
157    })
158}
159
160pub trait Encode: Iterator<Item = u8>
161where
162    Self: Sized,
163{
164    fn base256u<F>(self, function: F) -> Encoder<Self, F>
165    where
166        F: Fn(u8) -> char,
167    {
168        Encoder::new(self, function)
169    }
170
171    fn base256u_basic(self) -> Encoder<Self, fn(u8) -> char> {
172        self.base256u(encode_basic)
173    }
174    fn base256u_papu(self) -> Encoder<Self, fn(u8) -> char> {
175        self.base256u(encode_papu)
176    }
177    fn base256u_tpapu(self) -> Encoder<Self, fn(u8) -> char> {
178        self.base256u(encode_tpapu)
179    }
180    fn base256u_emoji(self) -> Encoder<Self, fn(u8) -> char> {
181        self.base256u(encode_emoji)
182    }
183}
184
185impl<T> Encode for T where T: Iterator<Item = u8> {}
186
187pub trait Decode: Iterator<Item = char>
188where
189    Self: Sized,
190{
191    fn base256u<F>(self, function: F) -> Decoder<Self, F>
192    where
193        F: Fn(char) -> Option<u8>,
194    {
195        Decoder::new(self, function)
196    }
197
198    fn base256u_basic(self) -> Decoder<Self, fn(char) -> Option<u8>> {
199        self.base256u(decode_basic)
200    }
201    fn base256u_papu(self) -> Decoder<Self, fn(char) -> Option<u8>> {
202        self.base256u(decode_papu)
203    }
204    fn base256u_tpapu(self) -> Decoder<Self, fn(char) -> Option<u8>> {
205        self.base256u(decode_tpapu)
206    }
207    fn base256u_emoji(self) -> Decoder<Self, fn(char) -> Option<u8>> {
208        self.base256u(decode_emoji)
209    }
210}
211
212impl<T> Decode for T where T: Iterator<Item = char> {}
213
214#[cfg(test)]
215mod tests {
216    use crate::{Decode, Encode};
217
218    #[test]
219    fn encoding_basic() {
220        let encoded: String = (u8::MIN..=u8::MAX).base256u_basic().collect();
221        assert_eq!(encoded, "\u{0}\u{1}\u{2}\u{3}\u{4}\u{5}\u{6}\u{7}\u{8}\u{9}\u{A}\u{B}\u{C}\u{D}\u{E}\u{F}\u{10}\u{11}\u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\u{1A}\u{1B}\u{1C}\u{1D}\u{1E}\u{1F}\u{20}\u{21}\u{22}\u{23}\u{24}\u{25}\u{26}\u{27}\u{28}\u{29}\u{2A}\u{2B}\u{2C}\u{2D}\u{2E}\u{2F}\u{30}\u{31}\u{32}\u{33}\u{34}\u{35}\u{36}\u{37}\u{38}\u{39}\u{3A}\u{3B}\u{3C}\u{3D}\u{3E}\u{3F}\u{40}\u{41}\u{42}\u{43}\u{44}\u{45}\u{46}\u{47}\u{48}\u{49}\u{4A}\u{4B}\u{4C}\u{4D}\u{4E}\u{4F}\u{50}\u{51}\u{52}\u{53}\u{54}\u{55}\u{56}\u{57}\u{58}\u{59}\u{5A}\u{5B}\u{5C}\u{5D}\u{5E}\u{5F}\u{60}\u{61}\u{62}\u{63}\u{64}\u{65}\u{66}\u{67}\u{68}\u{69}\u{6A}\u{6B}\u{6C}\u{6D}\u{6E}\u{6F}\u{70}\u{71}\u{72}\u{73}\u{74}\u{75}\u{76}\u{77}\u{78}\u{79}\u{7A}\u{7B}\u{7C}\u{7D}\u{7E}\u{7F}\u{80}\u{81}\u{82}\u{83}\u{84}\u{85}\u{86}\u{87}\u{88}\u{89}\u{8A}\u{8B}\u{8C}\u{8D}\u{8E}\u{8F}\u{90}\u{91}\u{92}\u{93}\u{94}\u{95}\u{96}\u{97}\u{98}\u{99}\u{9A}\u{9B}\u{9C}\u{9D}\u{9E}\u{9F}\u{A0}\u{A1}\u{A2}\u{A3}\u{A4}\u{A5}\u{A6}\u{A7}\u{A8}\u{A9}\u{AA}\u{AB}\u{AC}\u{AD}\u{AE}\u{AF}\u{B0}\u{B1}\u{B2}\u{B3}\u{B4}\u{B5}\u{B6}\u{B7}\u{B8}\u{B9}\u{BA}\u{BB}\u{BC}\u{BD}\u{BE}\u{BF}\u{C0}\u{C1}\u{C2}\u{C3}\u{C4}\u{C5}\u{C6}\u{C7}\u{C8}\u{C9}\u{CA}\u{CB}\u{CC}\u{CD}\u{CE}\u{CF}\u{D0}\u{D1}\u{D2}\u{D3}\u{D4}\u{D5}\u{D6}\u{D7}\u{D8}\u{D9}\u{DA}\u{DB}\u{DC}\u{DD}\u{DE}\u{DF}\u{E0}\u{E1}\u{E2}\u{E3}\u{E4}\u{E5}\u{E6}\u{E7}\u{E8}\u{E9}\u{EA}\u{EB}\u{EC}\u{ED}\u{EE}\u{EF}\u{F0}\u{F1}\u{F2}\u{F3}\u{F4}\u{F5}\u{F6}\u{F7}\u{F8}\u{F9}\u{FA}\u{FB}\u{FC}\u{FD}\u{FE}\u{FF}");
222        let encoded: String = b"Pack my box with five dozen liquor jugs."
223            .into_iter()
224            .copied()
225            .base256u_basic()
226            .collect();
227        assert_eq!(encoded, "Pack my box with five dozen liquor jugs.");
228    }
229
230    #[test]
231    fn decoding_basic() {
232        let decoded: Vec<Option<u8>> = "\u{0}\u{1}\u{2}\u{3}\u{4}\u{5}\u{6}\u{7}\u{8}\u{9}\u{A}\u{B}\u{C}\u{D}\u{E}\u{F}\u{10}\u{11}\u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\u{1A}\u{1B}\u{1C}\u{1D}\u{1E}\u{1F}\u{20}\u{21}\u{22}\u{23}\u{24}\u{25}\u{26}\u{27}\u{28}\u{29}\u{2A}\u{2B}\u{2C}\u{2D}\u{2E}\u{2F}\u{30}\u{31}\u{32}\u{33}\u{34}\u{35}\u{36}\u{37}\u{38}\u{39}\u{3A}\u{3B}\u{3C}\u{3D}\u{3E}\u{3F}\u{40}\u{41}\u{42}\u{43}\u{44}\u{45}\u{46}\u{47}\u{48}\u{49}\u{4A}\u{4B}\u{4C}\u{4D}\u{4E}\u{4F}\u{50}\u{51}\u{52}\u{53}\u{54}\u{55}\u{56}\u{57}\u{58}\u{59}\u{5A}\u{5B}\u{5C}\u{5D}\u{5E}\u{5F}\u{60}\u{61}\u{62}\u{63}\u{64}\u{65}\u{66}\u{67}\u{68}\u{69}\u{6A}\u{6B}\u{6C}\u{6D}\u{6E}\u{6F}\u{70}\u{71}\u{72}\u{73}\u{74}\u{75}\u{76}\u{77}\u{78}\u{79}\u{7A}\u{7B}\u{7C}\u{7D}\u{7E}\u{7F}\u{80}\u{81}\u{82}\u{83}\u{84}\u{85}\u{86}\u{87}\u{88}\u{89}\u{8A}\u{8B}\u{8C}\u{8D}\u{8E}\u{8F}\u{90}\u{91}\u{92}\u{93}\u{94}\u{95}\u{96}\u{97}\u{98}\u{99}\u{9A}\u{9B}\u{9C}\u{9D}\u{9E}\u{9F}\u{A0}\u{A1}\u{A2}\u{A3}\u{A4}\u{A5}\u{A6}\u{A7}\u{A8}\u{A9}\u{AA}\u{AB}\u{AC}\u{AD}\u{AE}\u{AF}\u{B0}\u{B1}\u{B2}\u{B3}\u{B4}\u{B5}\u{B6}\u{B7}\u{B8}\u{B9}\u{BA}\u{BB}\u{BC}\u{BD}\u{BE}\u{BF}\u{C0}\u{C1}\u{C2}\u{C3}\u{C4}\u{C5}\u{C6}\u{C7}\u{C8}\u{C9}\u{CA}\u{CB}\u{CC}\u{CD}\u{CE}\u{CF}\u{D0}\u{D1}\u{D2}\u{D3}\u{D4}\u{D5}\u{D6}\u{D7}\u{D8}\u{D9}\u{DA}\u{DB}\u{DC}\u{DD}\u{DE}\u{DF}\u{E0}\u{E1}\u{E2}\u{E3}\u{E4}\u{E5}\u{E6}\u{E7}\u{E8}\u{E9}\u{EA}\u{EB}\u{EC}\u{ED}\u{EE}\u{EF}\u{F0}\u{F1}\u{F2}\u{F3}\u{F4}\u{F5}\u{F6}\u{F7}\u{F8}\u{F9}\u{FA}\u{FB}\u{FC}\u{FD}\u{FE}\u{FF}Ɲʼn".chars().base256u_basic().collect();
233        let mut matcher: Vec<Option<u8>> = (u8::MIN..=u8::MAX).map(|b| Some(b)).collect();
234        matcher.push(None);
235        matcher.push(None);
236        assert_eq!(decoded, matcher);
237        let decoded: Vec<u8> = "Pack my box with five dozen liquor jugs."
238            .chars()
239            .base256u_basic()
240            .map(|c| c.unwrap())
241            .collect();
242        assert_eq!(
243            decoded.as_slice(),
244            b"Pack my box with five dozen liquor jugs."
245        );
246    }
247    #[test]
248    fn encoding_papu() {
249        let encoded: String = (u8::MIN..=u8::MAX).base256u_papu().collect();
250        assert_eq!(encoded, "°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~§ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇň¤ŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ");
251        let encoded: String = b"Pack my box with five dozen liquor jugs."
252            .into_iter()
253            .copied()
254            .base256u_papu()
255            .collect();
256        assert_eq!(encoded, "Pack my box with five dozen liquor jugs.");
257    }
258
259    #[test]
260    fn decoding_papu() {
261        let decoded: Vec<Option<u8>> = "°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~§ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇň¤ŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƝʼn".chars().base256u_papu().collect();
262        let mut matcher: Vec<Option<u8>> = (u8::MIN..=u8::MAX).map(|b| Some(b)).collect();
263        matcher.push(None);
264        matcher.push(None);
265        assert_eq!(decoded, matcher);
266        let decoded: Vec<u8> = "Pack my box with five dozen liquor jugs."
267            .chars()
268            .base256u_papu()
269            .map(|c| c.unwrap())
270            .collect();
271        assert_eq!(
272            decoded.as_slice(),
273            b"Pack my box with five dozen liquor jugs."
274        );
275    }
276
277    #[test]
278    fn encoding_tpapu() {
279        let encoded: String = (u8::MIN..=u8::MAX).base256u_tpapu().collect();
280        assert_eq!(encoded, "¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁł");
281        let encoded: String = b"Pack my box with five dozen liquor jugs."
282            .into_iter()
283            .copied()
284            .base256u_tpapu()
285            .collect();
286        assert_eq!(encoded, "Pack my box with five dozen liquor jugs.");
287    }
288
289    #[test]
290    fn decoding_tpapu() {
291        let decoded: Vec<Option<u8>> = "¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłƝʼn".chars().base256u_tpapu().collect();
292        let mut matcher: Vec<Option<u8>> = (u8::MIN..=u8::MAX).map(|b| Some(b)).collect();
293        matcher.push(None);
294        matcher.push(None);
295        assert_eq!(decoded, matcher);
296        let decoded: Vec<u8> = "Pack my box with five dozen liquor jugs."
297            .chars()
298            .base256u_tpapu()
299            .map(|c| c.unwrap())
300            .collect();
301        assert_eq!(
302            decoded.as_slice(),
303            b"Pack my box with five dozen liquor jugs."
304        );
305    }
306    #[test]
307    fn encoding_emoji() {
308        let encoded: String = (u8::MIN..=u8::MAX).base256u_emoji().collect();
309        assert_eq!(encoded, "🌰🌱🌲🌳🌴🌵🌶🌷🌸🌹🌺🌻🌼🌽🌾🌿🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬🍭🍮🍯🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼🍽🍾🍿🐀🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾🐿😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟😠😡😢😣😤😥😦😧😨😩😪😫😬😭😮😯😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀🙁🙂🙃🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏🤐🤑🤒🤓🤔🤕🤖🤗🤘🤙🤚🤛🤜🤝🤞🤟🤠🤡🤢🤣🤤🤥🤦🤧🤨🤩🤪🤫🤬🤭🤮🤯");
310        let encoded: String = b"Pack my box with five dozen liquor jugs."
311            .into_iter()
312            .copied()
313            .base256u_emoji()
314            .collect();
315        assert_eq!(
316            encoded,
317            "🐀🐑🐓🐛🍐🐝🐩🍐🐒🐟🐨🍐🐧🐙🐤🐘🍐🐖🐙🐦🐕🍐🐔🐟🐪🐕🐞🍐🐜🐙🐡🐥🐟🐢🍐🐚🐥🐗🐣🍞"
318        );
319    }
320    #[test]
321    fn decoding_emoji() {
322        let decoded: Vec<Option<u8>> = "🌰🌱🌲🌳🌴🌵🌶🌷🌸🌹🌺🌻🌼🌽🌾🌿🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬🍭🍮🍯🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼🍽🍾🍿🐀🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾🐿😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟😠😡😢😣😤😥😦😧😨😩😪😫😬😭😮😯😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀🙁🙂🙃🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏🤐🤑🤒🤓🤔🤕🤖🤗🤘🤙🤚🤛🤜🤝🤞🤟🤠🤡🤢🤣🤤🤥🤦🤧🤨🤩🤪🤫🤬🤭🤮🤯Ɲʼn".chars().base256u_emoji().collect();
323        let mut matcher: Vec<Option<u8>> = (u8::MIN..=u8::MAX).map(|b| Some(b)).collect();
324        matcher.push(None);
325        matcher.push(None);
326        assert_eq!(decoded, matcher);
327        let decoded: Vec<u8> =
328            "🐀🐑🐓🐛🍐🐝🐩🍐🐒🐟🐨🍐🐧🐙🐤🐘🍐🐖🐙🐦🐕🍐🐔🐟🐪🐕🐞🍐🐜🐙🐡🐥🐟🐢🍐🐚🐥🐗🐣🍞"
329                .chars()
330                .base256u_emoji()
331                .map(|c| c.unwrap())
332                .collect();
333        assert_eq!(
334            decoded.as_slice(),
335            b"Pack my box with five dozen liquor jugs."
336        );
337    }
338}