<commit_before>use std::collections::BTreeMap;
use std::cmp;
use innovation::Innovation;

mod innovation;

trait Gene {
    fn weight_distance(&self, other: &Self) -> f64;
}

enum NodeType {
    Input,
    Output,
    Hidden,
}

struct NodeGene {
    node_type: NodeType,
}

// To avoid node collisions we use Innovation numbers instead. Every newly created node gets it's
// own innovation number.
struct LinkGene {
    // This points to the NodeGene of that innovation
    source_node_gene: Innovation,
    // This points to the NodeGene of that innovation
    target_node_gene: Innovation,
    weight: f64,
    active: bool,
}

impl Gene for LinkGene {
    fn weight_distance(&self, other: &LinkGene) -> f64 {
        self.weight - other.weight
    }
}

// always take excess/disjoint genes if they appear on the fitter parent.
// if they appear on the less fit parent, take them only to a specified
// probability

struct Genome {
    link_genes: BTreeMap<Innovation, LinkGene>,
    node_genes: BTreeMap<Innovation, NodeGene>,
}

struct Coefficients {
    excess: f64,
    disjoint: f64,
    weight: f64,
}

fn genes_compatibility<T: Gene>(genes1: &BTreeMap<Innovation, T>,
                                genes2: &BTreeMap<Innovation, T>,
                                c: &Coefficients)
                                -> f64 {
    let max_len = cmp::max(genes1.len(), genes2.len());
    assert!(max_len > 0);

    let range1 = innovation::innovation_range(genes1);
    let range2 = innovation::innovation_range(genes2);

    // calculate the number of excess genes of
    let mut excess = 0;
    let mut disjoint = 0;
    let mut matching = 0;
    let mut weight_dist = 0.0;

    for (innov1, gene) in genes1.iter() {
        if innov1.is_within(&range2) {
            match genes2.get(innov1) {
                Some(other_gene) => {
                    matching += 1;
                    weight_dist += gene.weight_distance(other_gene);
                }
                None => {
                    disjoint += 1;
                }
            }
        } else {
            excess += 1;
        }
    }

    for innov2 in genes2.keys() {
        if innov2.is_within(&range1) {
            if !genes1.contains_key(innov2) {
                disjoint += 1;
            }
        } else {
            excess += 1;
        }
    }

    assert!(2 * matching + disjoint + excess == genes1.len() + genes2.len());

    c.excess * (excess as f64) / (max_len as f64) +
    c.disjoint * (disjoint as f64) / (max_len as f64) +
    if matching > 0 {
        weight_dist / (matching as f64)
    } else {
        0.0
    }
}
<commit_msg>Use weight coeff<commit_after>use std::collections::BTreeMap;
use std::cmp;
use innovation::Innovation;

mod innovation;

trait Gene {
    fn weight_distance(&self, other: &Self) -> f64;
}

enum NodeType {
    Input,
    Output,
    Hidden,
}

struct NodeGene {
    node_type: NodeType,
}

// To avoid node collisions we use Innovation numbers instead. Every newly created node gets it's
// own innovation number.
struct LinkGene {
    // This points to the NodeGene of that innovation
    source_node_gene: Innovation,
    // This points to the NodeGene of that innovation
    target_node_gene: Innovation,
    weight: f64,
    active: bool,
}

impl Gene for LinkGene {
    fn weight_distance(&self, other: &LinkGene) -> f64 {
        self.weight - other.weight
    }
}

// always take excess/disjoint genes if they appear on the fitter parent.
// if they appear on the less fit parent, take them only to a specified
// probability

struct Genome {
    link_genes: BTreeMap<Innovation, LinkGene>,
    node_genes: BTreeMap<Innovation, NodeGene>,
}

struct Coefficients {
    excess: f64,
    disjoint: f64,
    weight: f64,
}

fn genes_compatibility<T: Gene>(genes1: &BTreeMap<Innovation, T>,
                                genes2: &BTreeMap<Innovation, T>,
                                coeff: &Coefficients)
                                -> f64 {
    let max_len = cmp::max(genes1.len(), genes2.len());
    assert!(max_len > 0);

    let range1 = innovation::innovation_range(genes1);
    let range2 = innovation::innovation_range(genes2);

    // calculate the number of excess genes of
    let mut excess = 0;
    let mut disjoint = 0;
    let mut matching = 0;
    let mut weight_dist = 0.0;

    for (innov1, gene) in genes1.iter() {
        if innov1.is_within(&range2) {
            match genes2.get(innov1) {
                Some(other_gene) => {
                    matching += 1;
                    weight_dist += gene.weight_distance(other_gene);
                }
                None => {
                    disjoint += 1;
                }
            }
        } else {
            excess += 1;
        }
    }

    for innov2 in genes2.keys() {
        if innov2.is_within(&range1) {
            if !genes1.contains_key(innov2) {
                disjoint += 1;
            }
        } else {
            excess += 1;
        }
    }

    assert!(2 * matching + disjoint + excess == genes1.len() + genes2.len());

    coeff.excess * (excess as f64) / (max_len as f64) +
    coeff.disjoint * (disjoint as f64) / (max_len as f64) +
    coeff.weight *
    if matching > 0 {
        weight_dist / (matching as f64)
    } else {
        0.0
    }
}
<|endoftext|>


<commit_before>#![feature(vec_push_all)]

pub struct JsonEncoder {
    buffer: Vec<u8>
}

impl JsonEncoder {
    pub fn new() -> JsonEncoder {
        JsonEncoder{buffer: Vec::new()}
    }

    #[inline(always)]
    pub fn encode_raw(&mut self, raw: &[u8]) {
        self.buffer.push_all(raw);
    }

    pub fn into_vec(self) -> Vec<u8> {
        self.buffer
    }

    #[inline(always)]
    pub fn encode_raw_str(&mut self, raw_str: &str) {
        self.buffer.push_all(raw_str.as_bytes());
    }

    fn escape_bytes(&mut self, bytes: &[u8]) {
        let mut start = 0;

        for (i, byte) in bytes.iter().enumerate() {
            let escaped = match *byte {
                b'"' => b"\\\"",
                b'\\' => b"\\\\",
                b'\x08' => b"\\b",
                b'\x0c' => b"\\f",
                b'\n' => b"\\n",
                b'\r' => b"\\r",
                b'\t' => b"\\t",
                _ => {
                    continue;
                }
            };

            if start < i {
                self.encode_raw(&bytes[start..i]);
            }

            self.encode_raw(escaped);

            start = i + 1;
        }

        if start != bytes.len() {
            self.encode_raw(&bytes[start..]);
        }
    }

    pub fn encode_u64_decimal(&mut self, value: u64) {
        self.buffer.push(b'"');
        self._encode_u64_decimal(value);
        self.buffer.push(b'"');
    }

    // encodes as decimal string
    #[inline(always)]
    fn _encode_u64_decimal(&mut self, value: u64) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 20;

        if value == 0 {
            self.buffer.push(b'0');
            return;
        }

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    #[inline(always)]
    pub fn encode_str(&mut self, s: &str) {
        self.buffer.push(b'"');
        self.escape_bytes(s.as_bytes());
        self.buffer.push(b'"');
    }

    #[inline(always)]
    pub fn encode_i32(&mut self, value: i32) {
        if value == 0 {
            self.buffer.push(b'0');
        } else if value > 0 {
            self.encode_u31(value as u32);
        } else {
            self.buffer.push(b'-');
            self.encode_u31((-value) as u32);
        }
    }

    // encodes a 31-bit unsigned integer != 0
    fn encode_u31(&mut self, value: u32) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 10;
        debug_assert!(value != 0);

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    pub fn encode_obj<F>(&mut self, f: F) where F: Fn(JsonObjectEncoder) {
        self.buffer.push(b'{');
        {
            f(JsonObjectEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b'}');
    }

    pub fn encode_array<F>(&mut self, f: F) where F: Fn(JsonArrayEncoder) {
        self.buffer.push(b'[');
        {
            f(JsonArrayEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b']');
    }

}

pub struct JsonObjectEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonObjectEncoder<'a> {
    // XXX: name MAY NOT include escapable characters
    #[inline(always)]
    pub fn encode_field<F:Fn(&mut JsonEncoder)>(&mut self, name: &str, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        self.js.buffer.push(b'"');
        self.js.encode_raw_str(name);
        self.js.buffer.push(b'"');
        self.js.buffer.push(b':');

        f(self.js);
    }
}

pub struct JsonArrayEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonArrayEncoder<'a> {
    #[inline(always)]
    pub fn encode_elm<F:Fn(&mut JsonEncoder)>(&mut self, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        f(self.js);
    }
}

#[test]
fn test_json_obj_encoder() {
    use std::str;

    let mut js = JsonEncoder::new();
    js.encode_obj(|_|{});
    assert_eq!(b"{}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|mut jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
    });
    assert_eq!(b"{\"total\":31}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|mut jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
    });
    assert_eq!(b"{\"total\":31,\"next\":\"abc\"}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|mut jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
        jso.encode_field("tags", |js| {
                js.encode_array(|mut jsa| {
                        jsa.encode_elm(|js| js.encode_i32(1));
                        jsa.encode_elm(|js| js.encode_i32(2));
                });
        });
    });
    assert_eq!("{\"total\":31,\"next\":\"abc\",\"tags\":[1,2]}", str::from_utf8(&js.into_vec()[..]).unwrap());
}
<commit_msg>Get rid of some 'mut's<commit_after>#![feature(vec_push_all)]

pub struct JsonEncoder {
    buffer: Vec<u8>
}

impl JsonEncoder {
    pub fn new() -> JsonEncoder {
        JsonEncoder{buffer: Vec::new()}
    }

    #[inline(always)]
    pub fn encode_raw(&mut self, raw: &[u8]) {
        self.buffer.push_all(raw);
    }

    pub fn into_vec(self) -> Vec<u8> {
        self.buffer
    }

    #[inline(always)]
    pub fn encode_raw_str(&mut self, raw_str: &str) {
        self.buffer.push_all(raw_str.as_bytes());
    }

    fn escape_bytes(&mut self, bytes: &[u8]) {
        let mut start = 0;

        for (i, byte) in bytes.iter().enumerate() {
            let escaped = match *byte {
                b'"' => b"\\\"",
                b'\\' => b"\\\\",
                b'\x08' => b"\\b",
                b'\x0c' => b"\\f",
                b'\n' => b"\\n",
                b'\r' => b"\\r",
                b'\t' => b"\\t",
                _ => {
                    continue;
                }
            };

            if start < i {
                self.encode_raw(&bytes[start..i]);
            }

            self.encode_raw(escaped);

            start = i + 1;
        }

        if start != bytes.len() {
            self.encode_raw(&bytes[start..]);
        }
    }

    pub fn encode_u64_decimal(&mut self, value: u64) {
        self.buffer.push(b'"');
        self._encode_u64_decimal(value);
        self.buffer.push(b'"');
    }

    // encodes as decimal string
    #[inline(always)]
    fn _encode_u64_decimal(&mut self, value: u64) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 20;

        if value == 0 {
            self.buffer.push(b'0');
            return;
        }

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    #[inline(always)]
    pub fn encode_str(&mut self, s: &str) {
        self.buffer.push(b'"');
        self.escape_bytes(s.as_bytes());
        self.buffer.push(b'"');
    }

    #[inline(always)]
    pub fn encode_i32(&mut self, value: i32) {
        if value == 0 {
            self.buffer.push(b'0');
        } else if value > 0 {
            self.encode_u31(value as u32);
        } else {
            self.buffer.push(b'-');
            self.encode_u31((-value) as u32);
        }
    }

    // encodes a 31-bit unsigned integer != 0
    fn encode_u31(&mut self, value: u32) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 10;
        debug_assert!(value != 0);

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    pub fn encode_obj<F>(&mut self, f: F) where F: Fn(&mut JsonObjectEncoder) {
        self.buffer.push(b'{');
        {
            f(&mut JsonObjectEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b'}');
    }

    pub fn encode_array<F>(&mut self, f: F) where F: Fn(&mut JsonArrayEncoder) {
        self.buffer.push(b'[');
        {
            f(&mut JsonArrayEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b']');
    }

}

pub struct JsonObjectEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonObjectEncoder<'a> {
    // XXX: name MAY NOT include escapable characters
    #[inline(always)]
    pub fn encode_field<F:Fn(&mut JsonEncoder)>(&mut self, name: &str, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        self.js.buffer.push(b'"');
        self.js.encode_raw_str(name);
        self.js.buffer.push(b'"');
        self.js.buffer.push(b':');

        f(self.js);
    }
}

pub struct JsonArrayEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonArrayEncoder<'a> {
    #[inline(always)]
    pub fn encode_elm<F:Fn(&mut JsonEncoder)>(&mut self, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        f(self.js);
    }
}

#[test]
fn test_json_obj_encoder() {
    use std::str;

    let mut js = JsonEncoder::new();
    js.encode_obj(|_|{});
    assert_eq!(b"{}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
    });
    assert_eq!(b"{\"total\":31}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
    });
    assert_eq!(b"{\"total\":31,\"next\":\"abc\"}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
        jso.encode_field("tags", |js| {
                js.encode_array(|jsa| {
                        jsa.encode_elm(|js| js.encode_i32(1));
                        jsa.encode_elm(|js| js.encode_i32(2));
                });
        });
    });
    assert_eq!("{\"total\":31,\"next\":\"abc\",\"tags\":[1,2]}", str::from_utf8(&js.into_vec()[..]).unwrap());
}
<|endoftext|>


<commit_before>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: usize = 4096;
pub const DISPLAY_WIDTH: usize = 64;
pub const DISPLAY_HEIGHT: usize = 32;

static FONTSET: [u8; 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut f: fn(&[u8]) = dump_pixels;
///     let mut ch8 = VirtualMachine::new(&mut f);
///     // ...
/// ```
pub type DrawCallback<'a> = FnMut(&[u8]) + 'a;

struct KeypressWait {
    wait: bool,
    vx: usize
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8; MEM_SIZE],
    v: [u8; 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16; 16],
    display: [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: &'a mut DrawCallback<'a>,
    keys: [bool; 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: &'a mut DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0; MEM_SIZE],
            v: [0; 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0; 16],
            display: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false; 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(&mut ch8.ram[0us..5 * 0x10], &FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(&mut self.ram[START_ADDR as usize .. len], rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as usize),
            0x3 => ops::skip_next_vx_eq(self, x as usize, kk),
            0x4 => ops::skip_next_vx_ne(self, x as usize, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as usize, kk),
            0x7 => ops::add_vx_byte(self, x as usize, kk),
            0x8 => {
                let (x, y) = (x as usize, y as usize);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => panic!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as usize, kk),
            0xD => ops::display_sprite(self, x as usize, y as usize, n as usize),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as usize),
                0x9E => ops::skip_next_key_vx_pressed(self, x as usize),
                _ => panic!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as usize),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as usize),
                    0x15 => ops::set_delay_timer(self, x as usize),
                    0x18 => ops::set_sound_timer(self, x as usize),
                    0x1E => ops::add_vx_to_i(self, x as usize),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as usize),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as usize),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as usize),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as usize),
                    _ => panic!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => panic!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as usize];
        let b2 = self.ram[(self.pc + 1) as usize];
        self.pc += 2;
        (b1 as u16) << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<commit_msg>Remove unused [experimental] crate attribute<commit_after>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

use std::slice::bytes::copy_memory;

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: usize = 4096;
pub const DISPLAY_WIDTH: usize = 64;
pub const DISPLAY_HEIGHT: usize = 32;

static FONTSET: [u8; 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut f: fn(&[u8]) = dump_pixels;
///     let mut ch8 = VirtualMachine::new(&mut f);
///     // ...
/// ```
pub type DrawCallback<'a> = FnMut(&[u8]) + 'a;

struct KeypressWait {
    wait: bool,
    vx: usize
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8; MEM_SIZE],
    v: [u8; 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16; 16],
    display: [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: &'a mut DrawCallback<'a>,
    keys: [bool; 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: &'a mut DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0; MEM_SIZE],
            v: [0; 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0; 16],
            display: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false; 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(&mut ch8.ram[0us..5 * 0x10], &FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(&mut self.ram[START_ADDR as usize .. len], rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as usize),
            0x3 => ops::skip_next_vx_eq(self, x as usize, kk),
            0x4 => ops::skip_next_vx_ne(self, x as usize, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as usize, kk),
            0x7 => ops::add_vx_byte(self, x as usize, kk),
            0x8 => {
                let (x, y) = (x as usize, y as usize);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => panic!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as usize, kk),
            0xD => ops::display_sprite(self, x as usize, y as usize, n as usize),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as usize),
                0x9E => ops::skip_next_key_vx_pressed(self, x as usize),
                _ => panic!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as usize),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as usize),
                    0x15 => ops::set_delay_timer(self, x as usize),
                    0x18 => ops::set_sound_timer(self, x as usize),
                    0x1E => ops::add_vx_to_i(self, x as usize),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as usize),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as usize),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as usize),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as usize),
                    _ => panic!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => panic!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as usize];
        let b2 = self.ram[(self.pc + 1) as usize];
        self.pc += 2;
        (b1 as u16) << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<|endoftext|>


<commit_before>sruct DeepWalk {
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Work in progress<commit_after>struct DeepWalk {
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

<|endoftext|>


<commit_before>extern crate byteorder;
use byteorder::{LittleEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::{BufRead, Read};
use std::fs::File;

#[derive(Debug)]
pub struct BigArchive {
    pub format: Format,
    pub size: u32,

    _entries: HashMap<String, BigEntry>,
}

impl BigArchive {
    pub fn new(mut data: &mut BufRead) -> Result<BigArchive, std::io::Error> {
        let format = read_format(&mut data).expect("Failed to read format");
        let size = reverse(data.read_u32::<LittleEndian>().expect("Failed to read size"));
        let num_entries = reverse(data.read_u32::<LittleEndian>()
            .expect("Failed to read num_entries"));
        let _first = data.read_u32::<LittleEndian>();

        let mut entries = HashMap::new();

        for i in 0..num_entries {
            let entry_num = i + 1;
            let offset = reverse(data.read_u32::<LittleEndian>()
                .expect(&format!("Failed to read offset of entry {}", entry_num)));
            let size = reverse(data.read_u32::<LittleEndian>()
                .expect(&format!("Failed to read size of entry {}", entry_num)));

            let mut buf = Vec::new();
            data.read_until(b'\0', &mut buf)
                .expect(&format!("Failed to read name for entry {}", entry_num));

            let name = String::from_utf8_lossy(&buf[..buf.len() - 1]);

            let entry = BigEntry {
                offset: offset,
                size: size,
                name: name.to_string(),
            };

            entries.insert(entry.name.clone(), entry);
        }

        Ok(BigArchive {
            format: format,
            size: size,
            _entries: entries,
        })
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub size: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGf" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, std::io::Error> {
    Ok(Format::from(data))
}

fn reverse(v: u32) -> u32 {
    (v << 24) | (v << 8 & 0xff0000) | (v >> 8 & 0xff00) | (v >> 24)
}

#[cfg(test)]
mod tests {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");

    use super::{read_format, Format};

    #[test]
    fn is_big4() {
        assert_eq!(read_format(TEST_BYTES).expect("Failed to load file"),
                   Format::Big4);
    }
}
<commit_msg>Remove unused imports<commit_after>extern crate byteorder;
use byteorder::{LittleEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::BufRead;

#[derive(Debug)]
pub struct BigArchive {
    pub format: Format,
    pub size: u32,

    _entries: HashMap<String, BigEntry>,
}

impl BigArchive {
    pub fn new(mut data: &mut BufRead) -> Result<BigArchive, std::io::Error> {
        let format = read_format(&mut data).expect("Failed to read format");
        let size = reverse(data.read_u32::<LittleEndian>().expect("Failed to read size"));
        let num_entries = reverse(data.read_u32::<LittleEndian>()
            .expect("Failed to read num_entries"));
        let _first = data.read_u32::<LittleEndian>();

        let mut entries = HashMap::new();

        for i in 0..num_entries {
            let entry_num = i + 1;
            let offset = reverse(data.read_u32::<LittleEndian>()
                .expect(&format!("Failed to read offset of entry {}", entry_num)));
            let size = reverse(data.read_u32::<LittleEndian>()
                .expect(&format!("Failed to read size of entry {}", entry_num)));

            let mut buf = Vec::new();
            data.read_until(b'\0', &mut buf)
                .expect(&format!("Failed to read name for entry {}", entry_num));

            let name = String::from_utf8_lossy(&buf[..buf.len() - 1]);

            let entry = BigEntry {
                offset: offset,
                size: size,
                name: name.to_string(),
            };

            entries.insert(entry.name.clone(), entry);
        }

        Ok(BigArchive {
            format: format,
            size: size,
            _entries: entries,
        })
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub size: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGf" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, std::io::Error> {
    Ok(Format::from(data))
}

fn reverse(v: u32) -> u32 {
    (v << 24) | (v << 8 & 0xff0000) | (v >> 8 & 0xff00) | (v >> 24)
}

#[cfg(test)]
mod tests {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");

    use super::{read_format, Format};

    #[test]
    fn is_big4() {
        assert_eq!(read_format(TEST_BYTES).expect("Failed to load file"),
                   Format::Big4);
    }
}
<|endoftext|>


<commit_before>#[crate_id = "fragments#0.1-pre"];

#[comment = "A simple template library for Rust"];
#[license = "MIT"];
#[crate_type = "lib"];
#[crate_type = "rlib"];

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::BufReader;
use collections::hashmap::HashMap;

#[deriving(Eq, TotalEq)]
enum Token {
	String(~str),
	Placeholder(~str)
}

pub struct Template {
	content: ~HashMap<~str, ~fmt::Show>,
	priv tokens: ~[Token]
}

impl Template {
	pub fn from_buffer(b: &mut Buffer) -> Template {
		let mut tokens = ~[];
		let mut current_token = ~"";
		let mut is_placeholder = false;

		loop {
			match b.read_char() {
				Ok('\\') => {
					match b.read_char() {
						Ok(c) => {
							current_token.push_char(c);
						},
						_ => break
					}
				},
				Ok('[') => {
					if !is_placeholder {
						match b.read_char() {
							Ok('[') => {
								tokens.push(String(current_token));
								current_token = ~"";
								is_placeholder = true;
							},
							Ok(c) => {
								current_token.push_char('[');
								current_token.push_char(c);
							},
							Err(_) => current_token.push_char('[')
						}
					} else {
						current_token.push_char('[')
					}
				},
				Ok(']') => {
					if is_placeholder {
						match b.read_char() {
							Ok(']') => {
								tokens.push(Placeholder(current_token));
								current_token = ~"";
								is_placeholder = false;
							},
							Ok(c) => {
								current_token.push_char(']');
								current_token.push_char(c);
							},
							Err(_) => current_token.push_char(']')
						}
					} else {
						current_token.push_char(']')
					}
				},
				Ok(c) => current_token.push_char(c),
				Err(_) => break
			}
		}

		if is_placeholder {
			tokens.push(Placeholder(current_token));
		} else {
			tokens.push(String(current_token));
		}

		Template {
			content: ~HashMap::new(),
			tokens: tokens
		}
	}

	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show);
	}
}

impl FromStr for Template {
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		for token in self.tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[name]]! This is a [[something]] template.").unwrap();
		assert_eq!(template.tokens[0], String(~"Hello, "));
		assert_eq!(template.tokens[1], Placeholder(~"name"));
		assert_eq!(template.tokens[2], String(~"! This is a "));
		assert_eq!(template.tokens[3], Placeholder(~"something"));
		assert_eq!(template.tokens[4], String(~" template."));
	}

	#[test]
	fn strange_tokens() {
		let template: Template = from_str("Hello, [[[name]]]! This is a [[[[something]] template.").unwrap();
		assert_eq!(template.tokens[0], String(~"Hello, "));
		assert_eq!(template.tokens[1], Placeholder(~"[name"));
		assert_eq!(template.tokens[2], String(~"]! This is a "));
		assert_eq!(template.tokens[3], Placeholder(~"[[something"));
		assert_eq!(template.tokens[4], String(~" template."));
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[name]]! Write placeholders like \\[[this]] and escape them like \\\\\\[[this]]").unwrap();
		assert_eq!(template.tokens[0], String(~"Hello, "));
		assert_eq!(template.tokens[1], Placeholder(~"name"));
		assert_eq!(template.tokens[2], String(~"! Write placeholders like [[this]] and escape them like \\[[this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[name]]! This is a [[something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[name]]! This is a [[something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}
}<commit_msg>Token derives Show<commit_after>#[crate_id = "fragments#0.1-pre"];

#[comment = "A simple template library for Rust"];
#[license = "MIT"];
#[crate_type = "lib"];
#[crate_type = "rlib"];

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::BufReader;
use collections::hashmap::HashMap;

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str)
}

pub struct Template {
	content: ~HashMap<~str, ~fmt::Show>,
	priv tokens: ~[Token]
}

impl Template {
	pub fn from_buffer(b: &mut Buffer) -> Template {
		let mut tokens = ~[];
		let mut current_token = ~"";
		let mut is_placeholder = false;

		loop {
			match b.read_char() {
				Ok('\\') => {
					match b.read_char() {
						Ok(c) => {
							current_token.push_char(c);
						},
						_ => break
					}
				},
				Ok('[') => {
					if !is_placeholder {
						match b.read_char() {
							Ok('[') => {
								tokens.push(String(current_token));
								current_token = ~"";
								is_placeholder = true;
							},
							Ok(c) => {
								current_token.push_char('[');
								current_token.push_char(c);
							},
							Err(_) => current_token.push_char('[')
						}
					} else {
						current_token.push_char('[')
					}
				},
				Ok(']') => {
					if is_placeholder {
						match b.read_char() {
							Ok(']') => {
								tokens.push(Placeholder(current_token));
								current_token = ~"";
								is_placeholder = false;
							},
							Ok(c) => {
								current_token.push_char(']');
								current_token.push_char(c);
							},
							Err(_) => current_token.push_char(']')
						}
					} else {
						current_token.push_char(']')
					}
				},
				Ok(c) => current_token.push_char(c),
				Err(_) => break
			}
		}

		if is_placeholder {
			tokens.push(Placeholder(current_token));
		} else {
			tokens.push(String(current_token));
		}

		Template {
			content: ~HashMap::new(),
			tokens: tokens
		}
	}

	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show);
	}
}

impl FromStr for Template {
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		for token in self.tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[name]]! This is a [[something]] template.").unwrap();
		assert_eq!(template.tokens[0], String(~"Hello, "));
		assert_eq!(template.tokens[1], Placeholder(~"name"));
		assert_eq!(template.tokens[2], String(~"! This is a "));
		assert_eq!(template.tokens[3], Placeholder(~"something"));
		assert_eq!(template.tokens[4], String(~" template."));
	}

	#[test]
	fn strange_tokens() {
		let template: Template = from_str("Hello, [[[name]]]! This is a [[[[something]] template.").unwrap();
		assert_eq!(template.tokens[0], String(~"Hello, "));
		assert_eq!(template.tokens[1], Placeholder(~"[name"));
		assert_eq!(template.tokens[2], String(~"]! This is a "));
		assert_eq!(template.tokens[3], Placeholder(~"[[something"));
		assert_eq!(template.tokens[4], String(~" template."));
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[name]]! Write placeholders like \\[[this]] and escape them like \\\\\\[[this]]").unwrap();
		assert_eq!(template.tokens[0], String(~"Hello, "));
		assert_eq!(template.tokens[1], Placeholder(~"name"));
		assert_eq!(template.tokens[2], String(~"! Write placeholders like [[this]] and escape them like \\[[this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[name]]! This is a [[something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[name]]! This is a [[something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}
}<|endoftext|>


<commit_before>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```ignore
//! extern crate resize;
//! use resize::Pixel::Gray8;
//! use resize::Type::Triangle;
//! let mut src = vec![0;w1*h1];
//! let mut dst = vec![0;w2*h2];
//! let mut resizer = resize::new(w1, h1, w2, h2, Gray8, Triangle);
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::f32;

/// Resizing type to use.
pub enum Type {
    /// Point resizing.
    Point,
    /// Box (nearest) resizing.
    Nearest,
    /// Triangle (bilinear) resizing.
    Triangle,
    /// Catmull-Rom (bicubic) resizing.
    Catrom,
    /// Resize using sinc-windowed filter with radius of 2.
    Lanczos2,
    /// Sinc-windowed filter with radius of 3.
    Lanczos3,
    /// Resize using custom filter.
    Custom(Filter),
}

/// Resampling filter.
pub struct Filter {
    kernel: Box<Fn(f32) -> f32>,
    support: f32,
}

impl Filter {
    /// Create a new filter.
    ///
    /// # Examples
    ///
    /// ```
    /// use resize::Filter;
    /// fn kernel(x: f32) -> f32 { f32::round(x) }
    /// let filter = Filter::new(Box::new(kernel), 0.5);
    /// ```
    pub fn new(kernel: Box<Fn(f32) -> f32>, support: f32) -> Filter {
        Filter {kernel: kernel, support: support}
    }
}

#[inline]
fn point_kernel(_: f32) -> f32 {
    1.0
}

#[inline]
fn box_kernel(x: f32) -> f32 {
    if x.abs() <= 0.5 { 1.0 } else { 0.0 }
}

#[inline]
fn triangle_kernel(x: f32) -> f32 {
    f32::max(1.0 - x.abs(), 0.0)
}

// Taken from
// https://github.com/PistonDevelopers/image/blob/2921cd7/src/imageops/sample.rs#L68
// Probably may be optimized a bit, see e.g.
// https://github.com/sekrit-twc/zimg/blob/1a606c0/src/zimg/resize/filter.cpp#L149
#[inline]
fn bc_cubic_spline(b: f32, c: f32, x: f32) -> f32 {
    let a = x.abs();
    let k = if a < 1.0 {
        (12.0 - 9.0 * b - 6.0 * c) * a.powi(3) +
        (-18.0 + 12.0 * b + 6.0 * c) * a.powi(2) +
        (6.0 - 2.0 * b)
    } else if a < 2.0 {
        (-b - 6.0 * c) * a.powi(3) +
        (6.0 * b + 30.0 * c) * a.powi(2) +
        (-12.0 * b - 48.0 * c) * a +
        (8.0 * b + 24.0 * c)
    } else {
        0.0
    };
    k / 6.0
}

#[inline]
fn sinc(x: f32) -> f32 {
    if x == 0.0 {
        1.0
    } else {
        let a = x * f32::consts::PI;
        a.sin() / a
    }
}

#[inline]
fn lanczos_kernel(taps: f32, x: f32) -> f32 {
    if x.abs() < taps {
        sinc(x) * sinc(x / taps)
    } else {
        0.0
    }
}

/// Supported pixel formats.
// TODO(Kagami): >8-bit formats.
#[derive(Debug, Clone, Copy)]
pub enum Pixel {
    /// Grayscale, 8-bit.
    Gray8,
    /// RGB, 8-bit per component.
    RGB24,
    /// RGBA, 8-bit per component.
    RGBA,
}

impl Pixel {
    /// Size of one pixel in that format in bytes.
    #[inline]
    pub fn get_size(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }

    /// Return number of components of that format.
    #[inline]
    pub fn get_ncomponents(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }
}

/// Resampler with preallocated buffers and coeffecients for the given
/// dimensions and filter type.
#[derive(Debug)]
pub struct Resizer {
    // Source/target dimensions.
    w1: usize,
    h1: usize,
    w2: usize,
    h2: usize,
    pix_fmt: Pixel,
    // Temporary/preallocated stuff.
    tmp: Vec<f32>,
    accum: Vec<f32>,
    coeffs_w: Vec<CoeffsLine>,
    coeffs_h: Vec<CoeffsLine>,
}

#[derive(Debug)]
struct CoeffsLine {
    left: usize,
    data: Vec<f32>,
}

impl Resizer {
    /// Create a new resizer instance.
    pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
        let filter = match t {
            Type::Point     => Filter::new(Box::new(point_kernel),                     0.0),
            Type::Nearest   => Filter::new(Box::new(box_kernel),                       0.5),
            Type::Triangle  => Filter::new(Box::new(triangle_kernel),                  1.0),
            Type::Catrom    => Filter::new(Box::new(|x| bc_cubic_spline(0.0, 0.5, x)), 2.0),
            Type::Lanczos2  => Filter::new(Box::new(|x| lanczos_kernel(2.0, x)),       2.0),
            Type::Lanczos3  => Filter::new(Box::new(|x| lanczos_kernel(3.0, x)),       3.0),
            Type::Custom(f) => f,
        };
        Resizer {
            w1: w1,
            h1: h1,
            w2: w2,
            h2: h2,
            pix_fmt: p,
            tmp: vec![0.0;w1*h2*p.get_size()],
            accum: vec![0.0;p.get_ncomponents()],
            // TODO(Kagami): Use same coeffs if w1 = h1 = w2 = h2?
            coeffs_w: Self::calc_coeffs(w1, w2, &filter),
            coeffs_h: Self::calc_coeffs(h1, h2, &filter),
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = if ratio > 1.0 { ratio } else { 1.0 };
        let filter_radius = (f.support * filter_scale).ceil();
        let mut coeffs = Vec::with_capacity(s2);
        for x2 in 0..s2 {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let left = (x1 - filter_radius).ceil() as isize;
            let left = Self::clamp(left, 0, s1 as isize - 1) as usize;
            let right = (x1 + filter_radius).floor() as isize;
            let right = Self::clamp(right, 0, s1 as isize - 1) as usize;
            let mut data = Vec::with_capacity(right - left + 1);
            let mut sum = 0.0;
            for i in left..right+1 {
                sum += (f.kernel)((i as f32 - x1) / filter_scale);
            }
            for i in left..right+1 {
                let v = (f.kernel)((i as f32 - x1) / filter_scale);
                data.push(v / sum);
            }
            coeffs.push(CoeffsLine {left: left, data: data});
        }
        coeffs
    }

    #[inline]
    fn clamp<N: PartialOrd>(v: N, min: N, max: N) -> N {
        if v <= min {
            min
        } else if v >= max {
            max
        } else {
            v
        }
    }

    #[inline]
    fn pack_u8(mut v: f32) -> u8 {
        v = v.round();
        v = f32::min(f32::max(v, 0.0), 255.0);
        v as u8
    }

    #[inline]
    fn clear_accum(&mut self) {
        for v in self.accum.iter_mut() {
            *v = 0.0;
        }
    }

    // Resample W1xH1 to W1xH2.
    fn sample_rows(&mut self, src: &[u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for x1 in 0..self.w1 {
            for y2 in 0..self.h2 {
                self.clear_accum();
                let ref line = self.coeffs_h[y2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let y0 = line.left + i;
                    let base = (y0 * self.w1 + x1) * ncomp;
                    for n in 0..ncomp {
                        let p = src[base + n] as f32;
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    self.tmp[offset] = v;
                    offset += 1;
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for y2 in 0..self.h2 {
            for x2 in 0..self.w2 {
                self.clear_accum();
                let ref line = self.coeffs_w[x2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let x0 = line.left + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    for n in 0..ncomp {
                        let p = self.tmp[base + n];
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    dst[offset] = Self::pack_u8(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[u8], dst: &mut [u8]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert_eq!(src.len(), self.w1 * self.h1 * self.pix_fmt.get_size());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_size());
        self.sample_rows(src);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
    Resizer::new(w1, h1, w2, h2, p, t)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
pub fn resize(
    w1: usize, h1: usize, w2: usize, h2: usize,
    p: Pixel, t: Type,
    src: &[u8], dst: &mut [u8],
) {
    Resizer::new(w1, h1, w2, h2, p, t).resize(src, dst)
}
<commit_msg>Add Mitchell<commit_after>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```ignore
//! extern crate resize;
//! use resize::Pixel::Gray8;
//! use resize::Type::Triangle;
//! let mut src = vec![0;w1*h1];
//! let mut dst = vec![0;w2*h2];
//! let mut resizer = resize::new(w1, h1, w2, h2, Gray8, Triangle);
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::f32;

/// Resizing type to use.
pub enum Type {
    /// Point resizing.
    Point,
    /// Box (nearest) resizing.
    Nearest,
    /// Triangle (bilinear) resizing.
    Triangle,
    /// Catmull-Rom (bicubic) resizing.
    Catrom,
    /// Resize using Mitchell-Netravali filter.
    Mitchell,
    /// Resize using sinc-windowed filter with radius of 2.
    Lanczos2,
    /// Sinc-windowed filter with radius of 3.
    Lanczos3,
    /// Resize using custom filter.
    Custom(Filter),
}

/// Resampling filter.
pub struct Filter {
    kernel: Box<Fn(f32) -> f32>,
    support: f32,
}

impl Filter {
    /// Create a new filter.
    ///
    /// # Examples
    ///
    /// ```
    /// use resize::Filter;
    /// fn kernel(x: f32) -> f32 { f32::round(x) }
    /// let filter = Filter::new(Box::new(kernel), 0.5);
    /// ```
    pub fn new(kernel: Box<Fn(f32) -> f32>, support: f32) -> Filter {
        Filter {kernel: kernel, support: support}
    }
}

#[inline]
fn point_kernel(_: f32) -> f32 {
    1.0
}

#[inline]
fn box_kernel(x: f32) -> f32 {
    if x.abs() <= 0.5 { 1.0 } else { 0.0 }
}

#[inline]
fn triangle_kernel(x: f32) -> f32 {
    f32::max(1.0 - x.abs(), 0.0)
}

// Taken from
// https://github.com/PistonDevelopers/image/blob/2921cd7/src/imageops/sample.rs#L68
// Could be optimized for known B and C, see e.g.:
// https://github.com/sekrit-twc/zimg/blob/1a606c0/src/zimg/resize/filter.cpp#L149
#[inline]
fn cubic_bc(b: f32, c: f32, x: f32) -> f32 {
    let a = x.abs();
    let k = if a < 1.0 {
        (12.0 - 9.0 * b - 6.0 * c) * a.powi(3) +
        (-18.0 + 12.0 * b + 6.0 * c) * a.powi(2) +
        (6.0 - 2.0 * b)
    } else if a < 2.0 {
        (-b - 6.0 * c) * a.powi(3) +
        (6.0 * b + 30.0 * c) * a.powi(2) +
        (-12.0 * b - 48.0 * c) * a +
        (8.0 * b + 24.0 * c)
    } else {
        0.0
    };
    k / 6.0
}

#[inline]
fn sinc(x: f32) -> f32 {
    if x == 0.0 {
        1.0
    } else {
        let a = x * f32::consts::PI;
        a.sin() / a
    }
}

#[inline]
fn lanczos(taps: f32, x: f32) -> f32 {
    if x.abs() < taps {
        sinc(x) * sinc(x / taps)
    } else {
        0.0
    }
}

/// Supported pixel formats.
// TODO(Kagami): >8-bit formats.
#[derive(Debug, Clone, Copy)]
pub enum Pixel {
    /// Grayscale, 8-bit.
    Gray8,
    /// RGB, 8-bit per component.
    RGB24,
    /// RGBA, 8-bit per component.
    RGBA,
}

impl Pixel {
    /// Size of one pixel in that format in bytes.
    #[inline]
    pub fn get_size(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }

    /// Return number of components of that format.
    #[inline]
    pub fn get_ncomponents(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }
}

/// Resampler with preallocated buffers and coeffecients for the given
/// dimensions and filter type.
#[derive(Debug)]
pub struct Resizer {
    // Source/target dimensions.
    w1: usize,
    h1: usize,
    w2: usize,
    h2: usize,
    pix_fmt: Pixel,
    // Temporary/preallocated stuff.
    tmp: Vec<f32>,
    accum: Vec<f32>,
    coeffs_w: Vec<CoeffsLine>,
    coeffs_h: Vec<CoeffsLine>,
}

#[derive(Debug)]
struct CoeffsLine {
    left: usize,
    data: Vec<f32>,
}

impl Resizer {
    /// Create a new resizer instance.
    pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
        let filter = match t {
            Type::Point     => Filter::new(Box::new(point_kernel),                      0.0),
            Type::Nearest   => Filter::new(Box::new(box_kernel),                        0.5),
            Type::Triangle  => Filter::new(Box::new(triangle_kernel),                   1.0),
            Type::Catrom    => Filter::new(Box::new(|x| cubic_bc(0.0, 0.5, x)),         2.0),
            Type::Mitchell  => Filter::new(Box::new(|x| cubic_bc(1.0/3.0, 1.0/3.0, x)), 2.0),
            Type::Lanczos2  => Filter::new(Box::new(|x| lanczos(2.0, x)),               2.0),
            Type::Lanczos3  => Filter::new(Box::new(|x| lanczos(3.0, x)),               3.0),
            Type::Custom(f) => f,
        };
        Resizer {
            w1: w1,
            h1: h1,
            w2: w2,
            h2: h2,
            pix_fmt: p,
            tmp: vec![0.0;w1*h2*p.get_size()],
            accum: vec![0.0;p.get_ncomponents()],
            // TODO(Kagami): Use same coeffs if w1 = h1 = w2 = h2?
            coeffs_w: Self::calc_coeffs(w1, w2, &filter),
            coeffs_h: Self::calc_coeffs(h1, h2, &filter),
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = if ratio > 1.0 { ratio } else { 1.0 };
        let filter_radius = (f.support * filter_scale).ceil();
        let mut coeffs = Vec::with_capacity(s2);
        for x2 in 0..s2 {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let left = (x1 - filter_radius).ceil() as isize;
            let left = Self::clamp(left, 0, s1 as isize - 1) as usize;
            let right = (x1 + filter_radius).floor() as isize;
            let right = Self::clamp(right, 0, s1 as isize - 1) as usize;
            let mut data = Vec::with_capacity(right - left + 1);
            let mut sum = 0.0;
            for i in left..right+1 {
                sum += (f.kernel)((i as f32 - x1) / filter_scale);
            }
            for i in left..right+1 {
                let v = (f.kernel)((i as f32 - x1) / filter_scale);
                data.push(v / sum);
            }
            coeffs.push(CoeffsLine {left: left, data: data});
        }
        coeffs
    }

    #[inline]
    fn clamp<N: PartialOrd>(v: N, min: N, max: N) -> N {
        if v <= min {
            min
        } else if v >= max {
            max
        } else {
            v
        }
    }

    #[inline]
    fn pack_u8(mut v: f32) -> u8 {
        v = v.round();
        v = f32::min(f32::max(v, 0.0), 255.0);
        v as u8
    }

    #[inline]
    fn clear_accum(&mut self) {
        for v in self.accum.iter_mut() {
            *v = 0.0;
        }
    }

    // Resample W1xH1 to W1xH2.
    fn sample_rows(&mut self, src: &[u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for x1 in 0..self.w1 {
            for y2 in 0..self.h2 {
                self.clear_accum();
                let ref line = self.coeffs_h[y2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let y0 = line.left + i;
                    let base = (y0 * self.w1 + x1) * ncomp;
                    for n in 0..ncomp {
                        let p = src[base + n] as f32;
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    self.tmp[offset] = v;
                    offset += 1;
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for y2 in 0..self.h2 {
            for x2 in 0..self.w2 {
                self.clear_accum();
                let ref line = self.coeffs_w[x2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let x0 = line.left + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    for n in 0..ncomp {
                        let p = self.tmp[base + n];
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    dst[offset] = Self::pack_u8(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[u8], dst: &mut [u8]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert_eq!(src.len(), self.w1 * self.h1 * self.pix_fmt.get_size());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_size());
        self.sample_rows(src);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
    Resizer::new(w1, h1, w2, h2, p, t)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
pub fn resize(
    w1: usize, h1: usize, w2: usize, h2: usize,
    p: Pixel, t: Type,
    src: &[u8], dst: &mut [u8],
) {
    Resizer::new(w1, h1, w2, h2, p, t).resize(src, dst)
}
<|endoftext|>


<commit_before>extern crate cpython;
extern crate serde_json;

use cpython::*;
use serde_json::value::Value;
use std::collections::BTreeMap;

#[derive(Debug)]
pub enum JsonError {
    PythonError(PyErr),
    TypeError(String, Option<String>),
    DictKeyNotString(PyObject),
}

macro_rules! pytry {
    ($x:expr) => {
        match $x {
            Ok(val) => val,
            Err(err) => return Err(JsonError::PythonError(err)),
        }
    }
}

pub fn to_json(py: Python, obj: PyObject) -> Result<Value, JsonError> {
    macro_rules! cast {
        ($t:ty, $f:expr) => {
            if let Ok(val) = obj.cast_as::<$t>(py) {
                return $f(val);
            }
        }
    }

    macro_rules! extract {
        ($t:ty) => {
            if let Ok(val) = obj.extract::<$t>(py) {
                return Ok(serde_json::value::to_value(val));
            }
        }
    }

    cast!(PyDict, |x: &PyDict| {
        let mut map = BTreeMap::new();
        for (key_obj, value) in x.items(py) {
            let key = try!(if key_obj == py.None() {
                Ok("null".to_string())
            } else if let Ok(val) = key_obj.extract::<bool>(py) {
                Ok(if val {
                    "true".to_string()
                } else {
                    "false".to_string()
                })
            } else if let Ok(val) = key_obj.str(py) {
                Ok(pytry!(val.to_string(py)).into_owned())
            } else {
                Err(JsonError::DictKeyNotString(key_obj))
            });
            map.insert(key, try!(to_json(py, value)));
        }
        Ok(Value::Object(map))
    });

    macro_rules! to_vec {
        ($t:ty) => {
            |x: &$t| Ok(Value::Array(try!(x.iter(py).map(|x| to_json(py, x)).collect())));
        }
    }
    cast!(PyList, to_vec!(PyList));
    cast!(PyTuple, to_vec!(PyTuple));

    extract!(String);
    extract!(bool);

    cast!(PyFloat, |x: &PyFloat| Ok(Value::F64(x.value(py))));

    extract!(u64);
    extract!(i64);

    if obj == py.None() {
        return Ok(Value::Null);
    }

    // At this point we can't cast it, set up the error object
    let repr = match obj.repr(py) {
        Ok(val) => {
            match val.to_string(py) {
                Ok(val) => Some(val.into_owned()),
                _ => None,
            }
        }
        _ => None,
    };
    Err(JsonError::TypeError(obj.get_type(py).name(py).into_owned(), repr))
}

pub fn from_json(py: Python, json: Value) -> Result<PyObject, JsonError> {
    macro_rules! obj {
        ($x:ident) => {
            Ok($x.into_py_object(py).into_object())
        }
    }

    match json {
        Value::I64(x) => obj!(x),
        Value::U64(x) => obj!(x),
        Value::F64(x) => obj!(x),
        Value::String(x) => Ok(PyUnicode::new(py, &x).into_object()),
        Value::Bool(x) => obj!(x),
        Value::Array(vec) => {
            let mut elements = Vec::new();
            for item in vec {
                elements.push(try!(from_json(py, item)));
            }
            Ok(PyList::new(py, &elements[..]).into_object())
        }
        Value::Object(map) => {
            let dict = PyDict::new(py);
            for (key, value) in map {
                pytry!(dict.set_item(py, key, try!(from_json(py, value))));
            }
            Ok(dict.into_object())
        }
        Value::Null => Ok(py.None()),
    }
}

#[cfg(test)]
mod tests {
    use cpython::*;
    use serde_json;
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use super::{to_json, from_json};

    #[test]
    fn test_json() {
        let gil = Python::acquire_gil();
        let py = gil.python();

        // use operator.__eq__ to determine equality of PyObjects
        let operator = py.import("operator").unwrap();

        for line in BufReader::new(&File::open("testdata/to_json.txt").unwrap()).lines() {
            let line = line.unwrap();
            if line == "" || line.starts_with("#") {
                continue;
            }
            let mut line: Vec<_> = line.split("\t").collect();

            if line.len() == 2 {
                line.push("");
            }
            assert_eq!(line.len(), 3);

            // test to_json
            let json = serde_json::from_str(line[1]).unwrap();
            if !line[2].contains("skip_to") {
                let obj = py.eval(line[0], None, None).unwrap();
                assert_eq!(to_json(py, obj).unwrap(),
                           json,
                           "to_json: {} != {}",
                           line[0],
                           line[1]);
            }

            // test from_json
            if !line[2].contains("skip_from") {
                let obj = py.eval(line[0], None, None).unwrap();
                let eq = operator.call(py,
                          "__eq__",
                          PyTuple::new(py, &[from_json(py, json).unwrap(), obj]),
                          None)
                    .unwrap();
                assert!(eq.extract::<bool>(py).unwrap(),
                        "from_json: {} != {}",
                        line[0],
                        line[1]);
            }
        }
    }
}
<commit_msg>Add fn to_pyerr() to JsonError<commit_after>extern crate cpython;
extern crate serde_json;

use cpython::*;
use serde_json::value::Value;
use std::collections::BTreeMap;

#[derive(Debug)]
pub enum JsonError {
    PythonError(PyErr),
    TypeError(String, PyResult<String>),
    DictKeyNotString(PyObject),
}

impl JsonError {
    pub fn to_pyerr(&self, py: Python) -> PyErr {
        match *self {
            JsonError::PythonError(ref err) => err.clone_ref(py),
            JsonError::TypeError(_, ref repr) => {
                match *repr {
                    Ok(ref repr) => {
                        PyErr {
                            ptype: cpython::exc::TypeError::type_object(py).into_object(),
                            pvalue: Some(PyUnicode::new(py,
                                                        &format!("{} is not JSON serializable",
                                                                 repr))
                                .into_object()),
                            ptraceback: None,
                        }
                    }
                    Err(ref err) => err.clone_ref(py),
                }
            }
            JsonError::DictKeyNotString(_) => {
                PyErr {
                    ptype: cpython::exc::TypeError::type_object(py).into_object(),
                    pvalue: Some(PyString::new(py, "keys must be a string").into_object()),
                    ptraceback: None,
                }
            }
        }
    }
}

macro_rules! pytry {
    ($x:expr) => {
        match $x {
            Ok(val) => val,
            Err(err) => return Err(JsonError::PythonError(err)),
        }
    }
}

pub fn to_json(py: Python, obj: PyObject) -> Result<Value, JsonError> {
    macro_rules! cast {
        ($t:ty, $f:expr) => {
            if let Ok(val) = obj.cast_as::<$t>(py) {
                return $f(val);
            }
        }
    }

    macro_rules! extract {
        ($t:ty) => {
            if let Ok(val) = obj.extract::<$t>(py) {
                return Ok(serde_json::value::to_value(val));
            }
        }
    }

    cast!(PyDict, |x: &PyDict| {
        let mut map = BTreeMap::new();
        for (key_obj, value) in x.items(py) {
            let key = try!(if key_obj == py.None() {
                Ok("null".to_string())
            } else if let Ok(val) = key_obj.extract::<bool>(py) {
                Ok(if val {
                    "true".to_string()
                } else {
                    "false".to_string()
                })
            } else if let Ok(val) = key_obj.str(py) {
                Ok(pytry!(val.to_string(py)).into_owned())
            } else {
                Err(JsonError::DictKeyNotString(key_obj))
            });
            map.insert(key, try!(to_json(py, value)));
        }
        Ok(Value::Object(map))
    });

    macro_rules! to_vec {
        ($t:ty) => {
            |x: &$t| Ok(Value::Array(try!(x.iter(py).map(|x| to_json(py, x)).collect())));
        }
    }
    cast!(PyList, to_vec!(PyList));
    cast!(PyTuple, to_vec!(PyTuple));

    extract!(String);
    extract!(bool);

    cast!(PyFloat, |x: &PyFloat| Ok(Value::F64(x.value(py))));

    extract!(u64);
    extract!(i64);

    if obj == py.None() {
        return Ok(Value::Null);
    }

    // At this point we can't cast it, set up the error object
    let repr = obj.repr(py).and_then(|x| x.to_string(py).and_then(|y| Ok(y.into_owned())));
    Err(JsonError::TypeError(obj.get_type(py).name(py).into_owned(), repr))
}

pub fn from_json(py: Python, json: Value) -> Result<PyObject, JsonError> {
    macro_rules! obj {
        ($x:ident) => {
            Ok($x.into_py_object(py).into_object())
        }
    }

    match json {
        Value::I64(x) => obj!(x),
        Value::U64(x) => obj!(x),
        Value::F64(x) => obj!(x),
        Value::String(x) => Ok(PyUnicode::new(py, &x).into_object()),
        Value::Bool(x) => obj!(x),
        Value::Array(vec) => {
            let mut elements = Vec::new();
            for item in vec {
                elements.push(try!(from_json(py, item)));
            }
            Ok(PyList::new(py, &elements[..]).into_object())
        }
        Value::Object(map) => {
            let dict = PyDict::new(py);
            for (key, value) in map {
                pytry!(dict.set_item(py, key, try!(from_json(py, value))));
            }
            Ok(dict.into_object())
        }
        Value::Null => Ok(py.None()),
    }
}

#[cfg(test)]
mod tests {
    use cpython::*;
    use serde_json;
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use super::{to_json, from_json};

    #[test]
    fn test_json() {
        let gil = Python::acquire_gil();
        let py = gil.python();

        // use operator.__eq__ to determine equality of PyObjects
        let operator = py.import("operator").unwrap();

        for line in BufReader::new(&File::open("testdata/to_json.txt").unwrap()).lines() {
            let line = line.unwrap();
            if line == "" || line.starts_with("#") {
                continue;
            }
            let mut line: Vec<_> = line.split("\t").collect();

            if line.len() == 2 {
                line.push("");
            }
            assert_eq!(line.len(), 3);

            // test to_json
            let json = serde_json::from_str(line[1]).unwrap();
            if !line[2].contains("skip_to") {
                let obj = py.eval(line[0], None, None).unwrap();
                assert_eq!(to_json(py, obj).unwrap(),
                           json,
                           "to_json: {} != {}",
                           line[0],
                           line[1]);
            }

            // test from_json
            if !line[2].contains("skip_from") {
                let obj = py.eval(line[0], None, None).unwrap();
                let eq = operator.call(py,
                          "__eq__",
                          PyTuple::new(py, &[from_json(py, json).unwrap(), obj]),
                          None)
                    .unwrap();
                assert!(eq.extract::<bool>(py).unwrap(),
                        "from_json: {} != {}",
                        line[0],
                        line[1]);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Redis support for the `r2d2` connection pool.
#![doc(html_root_url = "https://docs.rs/r2d2_redis/0.8.0")]
#![warn(missing_docs)]

pub extern crate r2d2;
pub extern crate redis;

use std::error;
use std::error::Error as _StdError;
use std::fmt;

/// A unified enum of errors returned by redis::Client
#[derive(Debug)]
pub enum Error {
    /// A redis::RedisError
    Other(redis::RedisError),

    /// inner redis::Connection reports being closed
    ConnectionClosed,
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.cause() {
            Some(cause) => write!(fmt, "{}: {}", self.description(), cause),
            None => write!(fmt, "{}", self.description()),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Other(ref err) => err.description(),
            Error::ConnectionClosed => "inner redis::Connection reports being closed",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Other(ref err) => err.cause(),
            Error::ConnectionClosed => None,
        }
    }
}

/// An `r2d2::ConnectionManager` for `redis::Client`s.
///
/// ## Example
///

/// ```
/// extern crate r2d2_redis;
///
/// use std::ops::Deref;
/// use std::thread;
///
/// use r2d2_redis::{r2d2, redis, RedisConnectionManager};
///
/// fn main() {
///     let manager = RedisConnectionManager::new("redis://localhost").unwrap();
///     let pool = r2d2::Pool::builder()
///         .build(manager)
///         .unwrap();
///
///     let mut handles = vec![];
///
///     for _i in 0..10i32 {
///         let pool = pool.clone();
///         handles.push(thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             let reply = redis::cmd("PING").query::<String>(conn.deref()).unwrap();
///             // Alternatively, without deref():
///             // let reply = redis::cmd("PING").query::<String>(&*conn).unwrap();
///             assert_eq!("PONG", reply);
///         }));
///     }
///
///     for h in handles {
///         h.join().unwrap();
///     }
/// }
/// ```
#[derive(Debug)]
pub struct RedisConnectionManager {
    connection_info: redis::ConnectionInfo,
}

impl RedisConnectionManager {
    /// Creates a new `RedisConnectionManager`.
    ///
    /// See `redis::Client::open` for a description of the parameter
    /// types.
    pub fn new<T: redis::IntoConnectionInfo>(
        params: T,
    ) -> Result<RedisConnectionManager, redis::RedisError> {
        Ok(RedisConnectionManager {
            connection_info: try!(params.into_connection_info()),
        })
    }
}

impl r2d2::ManageConnection for RedisConnectionManager {
    type Connection = redis::Connection;
    type Error = Error;

    fn connect(&self) -> Result<redis::Connection, Error> {
        match redis::Client::open(self.connection_info.clone()) {
            Ok(client) => client.get_connection().map_err(Error::Other),
            Err(err) => Err(Error::Other(err)),
        }
    }

    fn is_valid(&self, conn: &mut redis::Connection) -> Result<(), Error> {
        if conn.is_open() {
            Ok(())
        } else {
            Err(Error::ConnectionClosed)
        }
    }

    fn has_broken(&self, conn: &mut redis::Connection) -> bool {
        !conn.is_open()
    }
}
<commit_msg>update valid/broken logic to hybrid approach - use PING for (optional) checkout validation - use the is_open() check for checking back into the pool<commit_after>//! Redis support for the `r2d2` connection pool.
#![doc(html_root_url = "https://docs.rs/r2d2_redis/0.8.0")]
#![warn(missing_docs)]

pub extern crate r2d2;
pub extern crate redis;

use std::error;
use std::error::Error as _StdError;
use std::fmt;

/// A unified enum of errors returned by redis::Client
#[derive(Debug)]
pub enum Error {
    /// A redis::RedisError
    Other(redis::RedisError),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.cause() {
            Some(cause) => write!(fmt, "{}: {}", self.description(), cause),
            None => write!(fmt, "{}", self.description()),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Other(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Other(ref err) => err.cause(),
        }
    }
}

/// An `r2d2::ConnectionManager` for `redis::Client`s.
///
/// ## Example
///

/// ```
/// extern crate r2d2_redis;
///
/// use std::ops::Deref;
/// use std::thread;
///
/// use r2d2_redis::{r2d2, redis, RedisConnectionManager};
///
/// fn main() {
///     let manager = RedisConnectionManager::new("redis://localhost").unwrap();
///     let pool = r2d2::Pool::builder()
///         .build(manager)
///         .unwrap();
///
///     let mut handles = vec![];
///
///     for _i in 0..10i32 {
///         let pool = pool.clone();
///         handles.push(thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             let reply = redis::cmd("PING").query::<String>(conn.deref()).unwrap();
///             // Alternatively, without deref():
///             // let reply = redis::cmd("PING").query::<String>(&*conn).unwrap();
///             assert_eq!("PONG", reply);
///         }));
///     }
///
///     for h in handles {
///         h.join().unwrap();
///     }
/// }
/// ```
#[derive(Debug)]
pub struct RedisConnectionManager {
    connection_info: redis::ConnectionInfo,
}

impl RedisConnectionManager {
    /// Creates a new `RedisConnectionManager`.
    ///
    /// See `redis::Client::open` for a description of the parameter
    /// types.
    pub fn new<T: redis::IntoConnectionInfo>(
        params: T,
    ) -> Result<RedisConnectionManager, redis::RedisError> {
        Ok(RedisConnectionManager {
            connection_info: try!(params.into_connection_info()),
        })
    }
}

impl r2d2::ManageConnection for RedisConnectionManager {
    type Connection = redis::Connection;
    type Error = Error;

    fn connect(&self) -> Result<redis::Connection, Error> {
        match redis::Client::open(self.connection_info.clone()) {
            Ok(client) => client.get_connection().map_err(Error::Other),
            Err(err) => Err(Error::Other(err)),
        }
    }

    fn is_valid(&self, conn: &mut redis::Connection) -> Result<(), Error> {
        redis::cmd("PING").query(conn).map_err(Error::Other)
    }

    fn has_broken(&self, conn: &mut redis::Connection) -> bool {
        !conn.is_open()
    }
}
<|endoftext|>