anyxml-encoding 0.1.4

simple character encoding and decoding library for XML
Documentation
use crate::{DecodeError, Decoder, EncodeError, Encoder};

/// Encoding name for KOI8-R.
pub const KOI8R_NAME: &str = "KOI8-R";

/// Encoder for KOI8-R.
pub struct KOI8REncoder;
impl Encoder for KOI8REncoder {
    fn name(&self) -> &'static str {
        KOI8R_NAME
    }

    fn encode(
        &mut self,
        src: &str,
        dst: &mut [u8],
        finish: bool,
    ) -> Result<(usize, usize), EncodeError> {
        if src.is_empty() {
            return if finish {
                Ok((0, 0))
            } else {
                Err(EncodeError::InputIsEmpty)
            };
        }

        if dst.len() < 2 {
            return Err(EncodeError::OutputTooShort);
        }

        let (mut read, mut write) = (0, 0);
        for c in src.chars() {
            if c.is_ascii() {
                read += 1;
                dst[write] = c as u8;
                write += 1;
            } else {
                read += c.len_utf8();
                if let Ok(pos) = UCS_TO_KOI8R.binary_search_by_key(&(c as u32), |v| v.0 as u32) {
                    dst[write] = UCS_TO_KOI8R[pos].1;
                    write += 1;
                } else {
                    return Err(EncodeError::Unmappable { read, write, c });
                }
            }
            if dst.len() == write {
                break;
            }
        }
        Ok((read, write))
    }
}

/// Decoder for KOI8-R.
pub struct KOI8RDecoder;
impl Decoder for KOI8RDecoder {
    fn name(&self) -> &'static str {
        KOI8R_NAME
    }

    fn decode(
        &mut self,
        src: &[u8],
        dst: &mut String,
        finish: bool,
    ) -> Result<(usize, usize), DecodeError> {
        if src.is_empty() {
            return if finish {
                Ok((0, 0))
            } else {
                Err(DecodeError::InputIsEmpty)
            };
        }
        let mut len = dst.capacity() - dst.len();
        if len < 4 {
            return Err(DecodeError::OutputTooShort);
        }

        let (mut read, mut write) = (0, 0);
        while read < src.len() && len > 0 {
            read += 1;
            let b = src[read];
            if b < 0x80 {
                // ASCII compatible
                dst.push(b as char);
                write += 1;
                len -= 1;
            } else {
                let b = b - 0x80;
                let ucs_code = KOI8R_TO_UCS[b as usize];
                let ucs = unsafe {
                    // # Safety
                    // No input other than the embedded UCS code is ever accepted,
                    // so as long as the embedded UCS code is correct, it is always safe.
                    char::from_u32_unchecked(ucs_code as u32)
                };
                if len < ucs.len_utf8() {
                    read -= 1;
                    break;
                }
                len -= ucs.len_utf8();
                write += ucs.len_utf8();
                dst.push(ucs);
            }
        }
        Ok((read, write))
    }
}

const KOI8R_TO_UCS: [u16; 128] = [
    0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, 0x252C, 0x2534, 0x253C, 0x2580,
    0x2584, 0x2588, 0x258C, 0x2590, 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
    0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, 0x2550, 0x2551, 0x2552, 0x0451,
    0x2553, 0x2554, 0x2555, 0x2556, 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E,
    0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567, 0x2568, 0x2569,
    0x256A, 0x256B, 0x256C, 0x00A9, 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
    0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x044F, 0x0440, 0x0441,
    0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
    0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A,
    0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
    0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A,
];
const UCS_TO_KOI8R: [(u16, u8); 128] = [
    (0x00A0, 0x9A),
    (0x00A9, 0xBF),
    (0x00B0, 0x9C),
    (0x00B2, 0x9D),
    (0x00B7, 0x9E),
    (0x00F7, 0x9F),
    (0x0401, 0xB3),
    (0x0410, 0xE1),
    (0x0411, 0xE2),
    (0x0412, 0xF7),
    (0x0413, 0xE7),
    (0x0414, 0xE4),
    (0x0415, 0xE5),
    (0x0416, 0xF6),
    (0x0417, 0xFA),
    (0x0418, 0xE9),
    (0x0419, 0xEA),
    (0x041A, 0xEB),
    (0x041B, 0xEC),
    (0x041C, 0xED),
    (0x041D, 0xEE),
    (0x041E, 0xEF),
    (0x041F, 0xF0),
    (0x0420, 0xF2),
    (0x0421, 0xF3),
    (0x0422, 0xF4),
    (0x0423, 0xF5),
    (0x0424, 0xE6),
    (0x0425, 0xE8),
    (0x0426, 0xE3),
    (0x0427, 0xFE),
    (0x0428, 0xFB),
    (0x0429, 0xFD),
    (0x042A, 0xFF),
    (0x042B, 0xF9),
    (0x042C, 0xF8),
    (0x042D, 0xFC),
    (0x042E, 0xE0),
    (0x042F, 0xF1),
    (0x0430, 0xC1),
    (0x0431, 0xC2),
    (0x0432, 0xD7),
    (0x0433, 0xC7),
    (0x0434, 0xC4),
    (0x0435, 0xC5),
    (0x0436, 0xD6),
    (0x0437, 0xDA),
    (0x0438, 0xC9),
    (0x0439, 0xCA),
    (0x043A, 0xCB),
    (0x043B, 0xCC),
    (0x043C, 0xCD),
    (0x043D, 0xCE),
    (0x043E, 0xCF),
    (0x043F, 0xD0),
    (0x0440, 0xD2),
    (0x0441, 0xD3),
    (0x0442, 0xD4),
    (0x0443, 0xD5),
    (0x0444, 0xC6),
    (0x0445, 0xC8),
    (0x0446, 0xC3),
    (0x0447, 0xDE),
    (0x0448, 0xDB),
    (0x0449, 0xDD),
    (0x044A, 0xDF),
    (0x044B, 0xD9),
    (0x044C, 0xD8),
    (0x044D, 0xDC),
    (0x044E, 0xC0),
    (0x044F, 0xD1),
    (0x0451, 0xA3),
    (0x2219, 0x95),
    (0x221A, 0x96),
    (0x2248, 0x97),
    (0x2264, 0x98),
    (0x2265, 0x99),
    (0x2320, 0x93),
    (0x2321, 0x9B),
    (0x2500, 0x80),
    (0x2502, 0x81),
    (0x250C, 0x82),
    (0x2510, 0x83),
    (0x2514, 0x84),
    (0x2518, 0x85),
    (0x251C, 0x86),
    (0x2524, 0x87),
    (0x252C, 0x88),
    (0x2534, 0x89),
    (0x253C, 0x8A),
    (0x2550, 0xA0),
    (0x2551, 0xA1),
    (0x2552, 0xA2),
    (0x2553, 0xA4),
    (0x2554, 0xA5),
    (0x2555, 0xA6),
    (0x2556, 0xA7),
    (0x2557, 0xA8),
    (0x2558, 0xA9),
    (0x2559, 0xAA),
    (0x255A, 0xAB),
    (0x255B, 0xAC),
    (0x255C, 0xAD),
    (0x255D, 0xAE),
    (0x255E, 0xAF),
    (0x255F, 0xB0),
    (0x2560, 0xB1),
    (0x2561, 0xB2),
    (0x2562, 0xB4),
    (0x2563, 0xB5),
    (0x2564, 0xB6),
    (0x2565, 0xB7),
    (0x2566, 0xB8),
    (0x2567, 0xB9),
    (0x2568, 0xBA),
    (0x2569, 0xBB),
    (0x256A, 0xBC),
    (0x256B, 0xBD),
    (0x256C, 0xBE),
    (0x2580, 0x8B),
    (0x2584, 0x8C),
    (0x2588, 0x8D),
    (0x258C, 0x8E),
    (0x2590, 0x8F),
    (0x2591, 0x90),
    (0x2592, 0x91),
    (0x2593, 0x92),
    (0x25A0, 0x94),
];