#![cfg_attr(not(test), no_std)]
/// A trait of an encodable item. This is used to enable Option and Result with
/// passthrough.
pub trait EncodeItem {
type Output;
fn encode_with<F: Fn(u8) -> char>(self, f: &F) -> Self::Output;
}
impl EncodeItem for u8 {
type Output = char;
fn encode_with<F: Fn(u8) -> char>(self, f: &F) -> Self::Output {
f(self)
}
}
impl EncodeItem for Option<u8> {
type Output = Option<char>;
fn encode_with<F: Fn(u8) -> char>(self, f: &F) -> Self::Output {
self.map(f)
}
}
impl<E> EncodeItem for Result<u8, E> {
type Output = Result<char, E>;
fn encode_with<F: Fn(u8) -> char>(self, f: &F) -> Self::Output {
self.map(f)
}
}
pub type DecodeOutput = Result<u8, char>;
/// A trait of an encodable item. This is used to enable Option and Result with
/// passthrough.
pub trait DecodeItem {
type Output;
fn decode_with<F: Fn(char) -> Option<u8>>(self, f: &F) -> Self::Output;
}
impl DecodeItem for char {
type Output = DecodeOutput;
fn decode_with<F: Fn(char) -> Option<u8>>(self, f: &F) -> Self::Output {
f(self).ok_or(self)
}
}
impl DecodeItem for Option<char> {
type Output = Option<DecodeOutput>;
fn decode_with<F: Fn(char) -> Option<u8>>(self, f: &F) -> Self::Output {
self.map(|c| f(c).ok_or(c))
}
}
impl<E> DecodeItem for Result<char, E> {
type Output = Result<DecodeOutput, E>;
fn decode_with<F: Fn(char) -> Option<u8>>(self, f: &F) -> Self::Output {
self.map(|c| f(c).ok_or(c))
}
}
/// Encoder iterator, converting bytes into unicode chars based on the contained encoding callable.
pub struct Encoder<I, F>
where
I: Iterator<Item: EncodeItem>,
F: Fn(u8) -> char,
{
iterator: I,
encode: F,
}
impl<I, F> Encoder<I, F>
where
I: Iterator<Item: EncodeItem>,
F: Fn(u8) -> char,
{
pub fn new(iterator: I, encode: F) -> Self {
Self { iterator, encode }
}
}
impl<I, F> Iterator for Encoder<I, F>
where
I: Iterator<Item: EncodeItem>,
F: Fn(u8) -> char,
{
type Item = <I::Item as EncodeItem>::Output;
fn next(&mut self) -> Option<Self::Item> {
self.iterator
.next()
.map(|item| item.encode_with(&self.encode))
}
}
/// Encoder iterator, converting unicode chars into bytes based on the contained decoding callable.
/// Must be fallible because not all unicode codepoints are valid bytes.
pub struct Decoder<I, F>
where
I: Iterator<Item: DecodeItem>,
F: Fn(char) -> Option<u8>,
{
iterator: I,
decode: F,
}
impl<I, F> Decoder<I, F>
where
I: Iterator<Item: DecodeItem>,
F: Fn(char) -> Option<u8>,
{
pub fn new(iterator: I, decode: F) -> Self {
Self { iterator, decode }
}
}
impl<I, F> Iterator for Decoder<I, F>
where
I: Iterator<Item: DecodeItem>,
F: Fn(char) -> Option<u8>,
{
type Item = <I::Item as DecodeItem>::Output;
fn next(&mut self) -> Option<Self::Item> {
self.iterator
.next()
.map(|item| item.decode_with(&self.decode))
}
}
/// Encode function for encoding to a straight 1-to-1 byte-to-codepoint conversion.
pub fn encode_basic(byte: u8) -> char {
byte as char
}
/// Decoding function for encoding to a straight 1-to-1 byte-to-codepoint conversion.
pub fn decode_basic(c: char) -> Option<u8> {
c.try_into().ok()
}
/// Encode function for encoding to printable-ascii-preserving Unicode.
/// `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`.
/// `0x20..=0x7E` are mapped to the same bytes as printable ASCII.
/// `0x7F` is arbitrarily mapped from ASCII ESC to §.
/// `0x80..=0xFF` mapped to the range starting at `U+100`, Latin Extended-A, with the exception of
/// `0xC9`, which is mapped arbitrarily to `¤` to avoid the deprecated character at that codepoint.
pub fn encode_papu(byte: u8) -> char {
match byte {
b @ 0x00..=0x1F => (b + 0xB0) as char,
b @ 0x20..=0x7E => b as char,
0x7F => '§',
// Unsafe is fine here because these ranges are known to be safe char values.
b @ (0x80..=0xC8 | 0xCA..) => unsafe { char::from_u32_unchecked(b as u32 + 0x80) },
0xC9 => '¤',
}
}
/// Decode function for printable-ascii-preserving Unicode.
/// All values are mapped as the inverse of encode_papu. All other input chars map to None.
pub const fn decode_papu(c: char) -> Option<u8> {
Some(match c as u32 {
b @ 0xB0..=0xCF => (b - 0xB0) as u8,
b @ 0x20..=0x7E => b as u8,
0xA7 => 0x7F,
b @ (0x100..=0x148 | 0x14A..=0x17F) => (b - 0x80) as u8,
0xA4 => 0xC9,
_ => return None,
})
}
/// Encode function for encoding to tight-printable-ascii-preserving Unicode.
/// Similar to papu, but packed as tightly as possible while mapping to all printable characters, skipping deprecated and invisible characters (SHY and NSBP, primarily).
/// `0x00..=0x0B` is mapped to `U+A1..=U+AC`
/// `0x0C..=0x1F` is mapped to `U+AE..=U+C1`
/// `0x20..=0x7E` are mapped to the same bytes as printable ASCII.
/// `0x7F..=0xFF` is mapped to `U+C2..=U+142`
pub fn encode_tpapu(byte: u8) -> char {
match byte {
b @ 0x00..=0x0B => (b + 0xA1) as char,
b @ 0x0C..=0x1F => (b + (0xAE - 0x0C)) as char,
b @ 0x20..=0x7E => b as char,
b @ 0x7F..=0xFF => unsafe { char::from_u32_unchecked(b as u32 + (0xC2 - 0x7F)) },
}
}
/// Decode function for decoding from tight-printable-ascii-preserving Unicode.
pub fn decode_tpapu(c: char) -> Option<u8> {
Some(match c as u32 {
b @ 0xA1..=0xAC => (b - 0xA1) as u8,
b @ 0xAE..=0xC1 => (b - (0xAE - 0x0C)) as u8,
b @ 0x20..=0x7E => b as u8,
b @ 0xC2..=0x142 => (b - (0xC2 - 0x7F)) as u8,
_ => return None,
})
}
/// Encode function for encoding to emoji.
/// `0x00..=0x4F` is mapped to the range starting at `U+1F370` For some plants and foods.
/// `0x50..=0x8F` is mapped to the range starting at `U+1F400` for animals.
/// `0x90..=0xDF` is mapped to the range starting at `U+1F600` for expressions and hand signs.
/// `0xE0..=0xFF` is mapped to the range starting at `U+1F910` for more expressions and hand signs.
pub fn encode_emoji(byte: u8) -> char {
match byte {
b @ 0x00..=0x4F => unsafe { char::from_u32_unchecked(b as u32 + 0x1F330) },
b @ 0x50..=0x8F => unsafe { char::from_u32_unchecked(b as u32 + (0x1F400 - 0x50)) },
b @ 0x90..=0xDF => unsafe { char::from_u32_unchecked(b as u32 + (0x1F600 - 0x90)) },
b @ 0xE0..=0xFF => unsafe { char::from_u32_unchecked(b as u32 + (0x1F910 - 0xE0)) },
}
}
/// Decode function for emoji.
/// All values are mapped as the inverse of encode_emoji. All other input chars map to None.
pub const fn decode_emoji(c: char) -> Option<u8> {
Some(match c as u32 {
b @ 0x1F330..=0x1F37F => (b - 0x1F330) as u8,
b @ 0x1F400..=0x1F43F => (b - (0x1F400 - 0x50)) as u8,
b @ 0x1F600..=0x1F64F => (b - (0x1F600 - 0x90)) as u8,
b @ 0x1F910..=0x1F92F => (b - (0x1F910 - 0xE0)) as u8,
_ => return None,
})
}
pub trait Encode: Iterator<Item: EncodeItem>
where
Self: Sized,
{
fn base256u<F>(self, function: F) -> Encoder<Self, F>
where
F: Fn(u8) -> char,
{
Encoder::new(self, function)
}
fn base256u_basic(self) -> Encoder<Self, fn(u8) -> char> {
self.base256u(encode_basic)
}
fn base256u_papu(self) -> Encoder<Self, fn(u8) -> char> {
self.base256u(encode_papu)
}
fn base256u_tpapu(self) -> Encoder<Self, fn(u8) -> char> {
self.base256u(encode_tpapu)
}
fn base256u_emoji(self) -> Encoder<Self, fn(u8) -> char> {
self.base256u(encode_emoji)
}
}
impl<T> Encode for T where T: Iterator<Item: EncodeItem> {}
pub trait Decode: Iterator<Item: DecodeItem>
where
Self: Sized,
{
fn base256u<F>(self, function: F) -> Decoder<Self, F>
where
F: Fn(char) -> Option<u8>,
{
Decoder::new(self, function)
}
fn base256u_basic(self) -> Decoder<Self, fn(char) -> Option<u8>> {
self.base256u(decode_basic)
}
fn base256u_papu(self) -> Decoder<Self, fn(char) -> Option<u8>> {
self.base256u(decode_papu)
}
fn base256u_tpapu(self) -> Decoder<Self, fn(char) -> Option<u8>> {
self.base256u(decode_tpapu)
}
fn base256u_emoji(self) -> Decoder<Self, fn(char) -> Option<u8>> {
self.base256u(decode_emoji)
}
}
impl<T> Decode for T where T: Iterator<Item: DecodeItem> {}
#[cfg(test)]
mod tests {
use crate::{Decode, Encode};
#[test]
fn encoding_basic() {
let encoded: String = (u8::MIN..=u8::MAX).base256u_basic().collect();
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}");
let encoded: String = b"Pack my box with five dozen liquor jugs."
.into_iter()
.copied()
.base256u_basic()
.collect();
assert_eq!(encoded, "Pack my box with five dozen liquor jugs.");
}
#[test]
fn decoding_basic() {
let decoded: Vec<Result<u8, char>> = "\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();
let mut matcher: Vec<Result<u8, char>> = (u8::MIN..=u8::MAX).map(|b| Ok(b)).collect();
matcher.push(Err('Ɲ'));
matcher.push(Err('ʼn'));
assert_eq!(decoded, matcher);
let decoded: Vec<u8> = "Pack my box with five dozen liquor jugs."
.chars()
.base256u_basic()
.map(|c| c.unwrap())
.collect();
assert_eq!(
decoded.as_slice(),
b"Pack my box with five dozen liquor jugs."
);
}
#[test]
fn encoding_papu() {
let encoded: String = (u8::MIN..=u8::MAX).base256u_papu().collect();
assert_eq!(encoded, "°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~§ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇň¤ŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ");
let encoded: String = b"Pack my box with five dozen liquor jugs."
.into_iter()
.copied()
.base256u_papu()
.collect();
assert_eq!(encoded, "Pack my box with five dozen liquor jugs.");
}
#[test]
fn decoding_papu() {
let decoded: Vec<Result<u8, char>> = "°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~§ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇň¤ŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƝʼn".chars().base256u_papu().collect();
let mut matcher: Vec<Result<u8, char>> = (u8::MIN..=u8::MAX).map(|b| Ok(b)).collect();
matcher.push(Err('Ɲ'));
matcher.push(Err('ʼn'));
assert_eq!(decoded, matcher);
let decoded: Vec<u8> = "Pack my box with five dozen liquor jugs."
.chars()
.base256u_papu()
.map(|c| c.unwrap())
.collect();
assert_eq!(
decoded.as_slice(),
b"Pack my box with five dozen liquor jugs."
);
}
#[test]
fn encoding_tpapu() {
let encoded: String = (u8::MIN..=u8::MAX).base256u_tpapu().collect();
assert_eq!(encoded, "¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁł");
let encoded: String = b"Pack my box with five dozen liquor jugs."
.into_iter()
.copied()
.base256u_tpapu()
.collect();
assert_eq!(encoded, "Pack my box with five dozen liquor jugs.");
}
#[test]
fn decoding_tpapu() {
let decoded: Vec<Result<u8, char>> = "¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłƝʼn".chars().base256u_tpapu().collect();
let mut matcher: Vec<Result<u8, char>> = (u8::MIN..=u8::MAX).map(|b| Ok(b)).collect();
matcher.push(Err('Ɲ'));
matcher.push(Err('ʼn'));
assert_eq!(decoded, matcher);
let decoded: Vec<u8> = "Pack my box with five dozen liquor jugs."
.chars()
.base256u_tpapu()
.map(|c| c.unwrap())
.collect();
assert_eq!(
decoded.as_slice(),
b"Pack my box with five dozen liquor jugs."
);
}
#[test]
fn encoding_emoji() {
let encoded: String = (u8::MIN..=u8::MAX).base256u_emoji().collect();
assert_eq!(encoded, "🌰🌱🌲🌳🌴🌵🌶🌷🌸🌹🌺🌻🌼🌽🌾🌿🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬🍭🍮🍯🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼🍽🍾🍿🐀🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾🐿😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟😠😡😢😣😤😥😦😧😨😩😪😫😬😭😮😯😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀🙁🙂🙃🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏🤐🤑🤒🤓🤔🤕🤖🤗🤘🤙🤚🤛🤜🤝🤞🤟🤠🤡🤢🤣🤤🤥🤦🤧🤨🤩🤪🤫🤬🤭🤮🤯");
let encoded: String = b"Pack my box with five dozen liquor jugs."
.into_iter()
.copied()
.base256u_emoji()
.collect();
assert_eq!(
encoded,
"🐀🐑🐓🐛🍐🐝🐩🍐🐒🐟🐨🍐🐧🐙🐤🐘🍐🐖🐙🐦🐕🍐🐔🐟🐪🐕🐞🍐🐜🐙🐡🐥🐟🐢🍐🐚🐥🐗🐣🍞"
);
}
#[test]
fn decoding_emoji() {
let decoded: Vec<Result<u8, char>> = "🌰🌱🌲🌳🌴🌵🌶🌷🌸🌹🌺🌻🌼🌽🌾🌿🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬🍭🍮🍯🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼🍽🍾🍿🐀🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾🐿😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟😠😡😢😣😤😥😦😧😨😩😪😫😬😭😮😯😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀🙁🙂🙃🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏🤐🤑🤒🤓🤔🤕🤖🤗🤘🤙🤚🤛🤜🤝🤞🤟🤠🤡🤢🤣🤤🤥🤦🤧🤨🤩🤪🤫🤬🤭🤮🤯Ɲʼn".chars().base256u_emoji().collect();
let mut matcher: Vec<Result<u8, char>> = (u8::MIN..=u8::MAX).map(|b| Ok(b)).collect();
matcher.push(Err('Ɲ'));
matcher.push(Err('ʼn'));
assert_eq!(decoded, matcher);
let decoded: Vec<u8> =
"🐀🐑🐓🐛🍐🐝🐩🍐🐒🐟🐨🍐🐧🐙🐤🐘🍐🐖🐙🐦🐕🍐🐔🐟🐪🐕🐞🍐🐜🐙🐡🐥🐟🐢🍐🐚🐥🐗🐣🍞"
.chars()
.base256u_emoji()
.map(|c| c.unwrap())
.collect();
assert_eq!(
decoded.as_slice(),
b"Pack my box with five dozen liquor jugs."
);
}
#[test]
fn encoding_result_passthrough() {
let input: Vec<Result<u8, &'static str>> = vec![Ok(b'P'), Ok(b'a'), Err("boom"), Ok(0xFF)];
let encoded: Vec<Result<char, &'static str>> = input.into_iter().base256u_tpapu().collect();
assert_eq!(encoded, vec![Ok('P'), Ok('a'), Err("boom"), Ok('ł')]);
}
#[test]
fn encoding_option_passthrough() {
let input: Vec<Option<u8>> = vec![Some(b'P'), None, Some(0xFF)];
let encoded: Vec<Option<char>> = input.into_iter().base256u_tpapu().collect();
assert_eq!(encoded, vec![Some('P'), None, Some('ł')]);
}
#[test]
fn decoding_result_passthrough() {
let input: Vec<Result<char, &'static str>> =
vec![Ok('P'), Ok('a'), Err("boom"), Ok('ł'), Ok('\u{0}')];
let decoded: Vec<Result<Result<u8, char>, &'static str>> =
input.into_iter().base256u_tpapu().collect();
assert_eq!(
decoded,
vec![
Ok(Ok(b'P')),
Ok(Ok(b'a')),
Err("boom"),
Ok(Ok(0xFF)),
Ok(Err('\u{0}')),
]
);
}
#[test]
fn decoding_option_passthrough() {
let input: Vec<Option<char>> = vec![Some('P'), None, Some('ł'), Some('\u{0}')];
let decoded: Vec<Option<Result<u8, char>>> = input.into_iter().base256u_tpapu().collect();
assert_eq!(
decoded,
vec![Some(Ok(b'P')), None, Some(Ok(0xFF)), Some(Err('\u{0}'))]
);
}
}