    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46

    use lib::*;

    const TAG_CONT: u8 = 0b1000_0000;
    const TAG_TWO_B: u8 = 0b1100_0000;
    const TAG_THREE_B: u8 = 0b1110_0000;
    const TAG_FOUR_B: u8 = 0b1111_0000;
    const MAX_ONE_B: u32 = 0x80;
    const MAX_TWO_B: u32 = 0x800;
    const MAX_THREE_B: u32 = 0x10000;

    #[inline]
    pub fn encode(c: char) -> Encode {
        let code = c as u32;
        let mut buf = [0; 4];
        let pos = if code < MAX_ONE_B {
            buf[3] = code as u8;
            3
        } else if code < MAX_TWO_B {
            buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
            buf[3] = (code & 0x3F) as u8 | TAG_CONT;
            2
        } else if code < MAX_THREE_B {
            buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
            buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
            buf[3] = (code & 0x3F) as u8 | TAG_CONT;
            1
        } else {
            buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
            buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
            buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
            buf[3] = (code & 0x3F) as u8 | TAG_CONT;
            0
        };
        Encode { buf: buf, pos: pos }
    }

    pub struct Encode {
        buf: [u8; 4],
        pos: usize,
    }

    impl Encode {
        pub fn as_str(&self) -> &str {
            str::from_utf8(&self.buf[self.pos..]).unwrap()
        }
    }