enrede 0.2.0

An easy-to-use string encoding library, providing an interface similar to str/String.
Documentation
use crate::encoding::sealed::Sealed;
use crate::encoding::{AlwaysValid, NullTerminable, ValidateError};
use crate::{Encoding, Str};
#[cfg(feature = "rand")]
use rand::distr::Distribution;
#[cfg(feature = "rand")]
use rand::Rng;

const DECODE_MAP_ROMAN: [char; 128] = [
    'Ä', 'Å', 'Ç', 'É', 'Ñ', 'Ö', 'Ü', 'á', 'à', 'â', 'ä', 'ã', 'å', 'ç', 'é', 'è', 'ê', 'ë', 'í',
    'ì', 'î', 'ï', 'ñ', 'ó', 'ò', 'ô', 'ö', 'õ', 'ú', 'ù', 'û', 'ü', '', '°', '¢', '£', '§', '',
    '', 'ß', '®', '©', '', '´', '¨', '', 'Æ', 'Ø', '', '±', '', '', '¥', 'µ', '', '', '',
    'π', '', 'ª', 'º', 'Ω', 'æ', 'ø', '¿', '¡', '¬', '', 'ƒ', '', '', '«', '»', '',
    '\u{00A0}', 'À', 'Ã', 'Õ', 'Œ', 'œ', '', '', '', '', '', '', '÷', '', 'ÿ', 'Ÿ', '',
    '', '', '', '', '', '', '·', '', '', '', 'Â', 'Ê', 'Á', 'Ë', 'È', 'Í', 'Î', 'Ï', 'Ì',
    'Ó', 'Ô', '\u{F8FF}', 'Ò', 'Ú', 'Û', 'Ù', 'ı', 'ˆ', '˜', '¯', '˘', '˙', '˚', '¸', '˝', '˛',
    'ˇ',
];

/// The [macOS Roman](https://en.wikipedia.org/wiki/Mac_OS_Roman) encoding.
#[non_exhaustive]
#[derive(Default)]
pub struct MacRoman;

impl Sealed for MacRoman {}

impl Encoding for MacRoman {
    const REPLACEMENT: char = '?';
    const MAX_LEN: usize = 1;
    type Bytes = u8;

    fn shorthand() -> &'static str {
        "mac_roman"
    }

    fn validate(_: &[u8]) -> Result<(), ValidateError> {
        Ok(())
    }

    fn encode_char(c: char) -> Option<Self::Bytes> {
        if (..0x80).contains(&(c as u32)) {
            Some(c as u8)
        } else {
            let pos = DECODE_MAP_ROMAN.iter().position(|v| *v == c)? as u8;
            Some(pos + 0x80)
        }
    }

    fn decode_char(str: &Str<Self>) -> (char, &Str<Self>) {
        let b = str.as_bytes()[0];
        if (..0x80).contains(&b) {
            (b as char, &str[1..])
        } else {
            (DECODE_MAP_ROMAN[b as usize - 0x80], &str[1..])
        }
    }

    fn char_bound(_: &Str<Self>, _: usize) -> bool {
        true
    }

    fn char_len(c: char) -> usize {
        if (c as u32) < 0x80 || DECODE_MAP_ROMAN.contains(&c) {
            1
        } else {
            0
        }
    }
}

impl NullTerminable for MacRoman {}

impl AlwaysValid for MacRoman {}

#[cfg(feature = "rand")]
impl Distribution<char> for MacRoman {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        // Number of characters
        let c = rng.random::<u8>();
        if c <= 0x7F {
            char::from(c)
        } else {
            DECODE_MAP_ROMAN[(c - 0x80) as usize]
        }
    }
}