json 0.8.0

JSON implementation in Rust
Documentation
use std::io::Write;
use std::num::FpCategory;
use JsonValue;

pub trait Generator {
    fn get_buffer(&mut self) -> &mut Vec<u8>;

    fn current_index(&mut self) -> usize {
        self.get_buffer().len()
    }

    #[inline(always)]
    fn write(&mut self, slice: &[u8]) {
        self.get_buffer().extend_from_slice(slice)
    }

    #[inline(always)]
    fn write_char(&mut self, ch: u8) {
        self.get_buffer().push(ch)
    }

    fn write_min(&mut self, slice: &[u8], minslice: &[u8]);

    fn new_line(&mut self) {}

    fn indent(&mut self) {}

    fn dedent(&mut self) {}

    fn write_string(&mut self, string: &str) {
        self.write_char(b'"');

        for ch in string.bytes() {
            match ch {
                b'\\' | b'"' => {
                    self.write_char(b'\\');
                    self.write_char(ch);
                },
                b'\n' => self.write(b"\\n"),
                b'\r' => self.write(b"\\r"),
                b'\t' => self.write(b"\\t"),
                0xC   => self.write(b"\\f"),
                0x8   => self.write(b"\\b"),
                _     => self.write_char(ch)
            }
        }

        self.write_char(b'"');
    }

    fn write_digits_from_u64(&mut self, mut num: u64) {
        let digit = (num % 10) as u8;
        if num > 9 {
            num /= 10;
            self.write_digits_from_u64(num);
        }
        self.write_char(digit + b'0');
    }

    fn write_number(&mut self, mut num: f64) {
        match num.classify() {
            FpCategory::Nan      |
            FpCategory::Infinite => {
                self.write(b"null");
                return;
            },
            FpCategory::Zero => {
                self.write(if num.is_sign_negative() { b"-0" } else { b"0" });
                return;
            },
            _ => {},
        }

        if num.is_sign_negative() {
            num = num.abs();
            self.write_char(b'-');
        }

        let fract = num.fract();

        if fract > 0.0 {
            if num < 1e-15 {
                write!(self.get_buffer(), "{:e}", num).unwrap();
            } else {
                write!(self.get_buffer(), "{}", num).unwrap();
            }
            return;
        }

        if num > 1e19 || num < 1e-15 {
            write!(self.get_buffer(), "{:e}", num).unwrap();
            return;
        }

        self.write_digits_from_u64(num as u64);
    }

    fn write_json(&mut self, json: &JsonValue) {
        match *json {
            JsonValue::String(ref string) => self.write_string(string),
            JsonValue::Number(ref number) => self.write_number(*number),
            JsonValue::Boolean(true)      => self.write(b"true"),
            JsonValue::Boolean(false)     => self.write(b"false"),
            JsonValue::Null               => self.write(b"null"),
            JsonValue::Array(ref array)   => {
                self.write_char(b'[');
                self.indent();
                let mut first = true;
                for item in array {
                    if first {
                        first = false;
                        self.new_line();
                    } else {
                        self.write(b",");
                        self.new_line();
                    }
                    self.write_json(item);
                }
                self.dedent();
                self.new_line();
                self.write_char(b']');
            },
            JsonValue::Object(ref object) => {
                self.write_char(b'{');
                self.indent();
                let mut first = true;
                for (key, value) in object.iter() {
                    if first {
                        first = false;
                        self.new_line();
                    } else {
                        self.write(b",");
                        self.new_line();
                    }
                    self.write_string(key);
                    self.write_min(b": ", b":");
                    self.write_json(value);
                }
                self.dedent();
                self.new_line();
                self.write_char(b'}');
            }
        }
    }

    fn consume(self) -> String;
}

pub struct DumpGenerator {
    code: Vec<u8>,
}

impl DumpGenerator {
    pub fn new() -> Self {
        DumpGenerator {
            code: Vec::with_capacity(1024),
        }
    }
}

impl Generator for DumpGenerator {
    #[inline(always)]
    fn get_buffer(&mut self) -> &mut Vec<u8> {
        &mut self.code
    }

    #[inline(always)]
    fn write_min(&mut self, _: &[u8], minslice: &[u8]) {
        self.code.extend_from_slice(minslice);
    }

    fn consume(self) -> String {
        String::from_utf8(self.code).unwrap()
    }
}

pub struct PrettyGenerator {
    code: Vec<u8>,
    dent: u16,
    spaces_per_indent: u16,
}

impl PrettyGenerator {
    pub fn new(spaces: u16) -> Self {
        PrettyGenerator {
            code: Vec::with_capacity(1024),
            dent: 0,
            spaces_per_indent: spaces
        }
    }
}

impl Generator for PrettyGenerator {
    #[inline(always)]
    fn get_buffer(&mut self) -> &mut Vec<u8> {
        &mut self.code
    }

    #[inline(always)]
    fn write_min(&mut self, slice: &[u8], _: &[u8]) {
        self.code.extend_from_slice(slice);
    }

    fn new_line(&mut self) {
        self.code.push(b'\n');
        for _ in 0..(self.dent * self.spaces_per_indent) {
            self.code.push(b' ');
        }
    }

    fn indent(&mut self) {
        self.dent += 1;
    }

    fn dedent(&mut self) {
        self.dent -= 1;
    }

    fn consume(self) -> String {
        String::from_utf8(self.code).unwrap()
    }
}