<commit_before>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Vector4;
use cgmath::Zero;
use cgmath::Matrix4;
use cgmath::SquareMatrix;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 800 * 800] = [-1.; 800 * 800];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color, ) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn viewport(x: f32, y: f32, w: f32, h: f32) -> Matrix4<f32> {
    let mut viewport = Matrix4::<f32>::identity();
    viewport[3][0] = x + w / 2.;
    viewport[3][1] = y + h / 2.;
    viewport[3][2] = 255. / 2.; //depth

    viewport[0][0] = w / 2.;
    viewport[1][1] = h / 2.;
    viewport[2][2] = 255. / 2.;
    return viewport;
}

fn lookat(eye: Vector3<f32>, center: Vector3<f32>, up: Vector3<f32>) -> Matrix4<f32> {
    let z = (eye - center).normalize();
    let x = up.cross(z).normalize();
    let y = z.cross(x).normalize();
    let mut res = Matrix4::<f32>::identity();

    for i in 0..3 {
        res[i][0] = x[i];
        res[i][1] = y[i];
        res[i][2] = z[i];
        res[3][i] = -center[i];
    }

    return res;
}

fn normal(v: Vector3<f32>) -> f32 {
    (v.x * v.x + v.y * v.y + v.z * v.z).sqrt()
}

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();
    // front: ( 0,  0,  3)
    // back:  ( 0,  0, -3)
    // left:  (-3,  0,  0)
    // right: ( 3,  0,  0)
    // top:   ( 0,  3,  0.1) ?
    // down:  ( 0, -3,  0.1) ?
    let eye = Vector3::new(1., 1., 3.);
    let center = Vector3::new(0., 0., 0.);

    let model_view = lookat(eye, center, Vector3::new(0., 1., 0.));
    let light_dir = Vector3::new(0., -1., -3.).normalize();
    let mut projection = Matrix4::<f32>::identity();
    let (x, y, w, h) = (WIDTH as f32 / 8., HEIGHT as f32 / 8., WIDTH as f32 * 3. / 4., HEIGHT as f32 * 3. / 4.);
    let viewport = viewport(x, y, w, h);

    projection[2][3] = -1. / normal(eye - center);

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut intensity: [f32; 3] = [0.; 3];

            for j in 0..3 {
                let v: Vector3<f32> = match mesh.get_vertex(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::new(0., 0., 0.)
                };

                let mesh_normal: Vector3<f32> = match mesh.get_normal(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::new(0., 0., 0.)
                };

                let m = viewport * projection * model_view * Vector4::<f32>::new(v.x, v.y, v.z, 1.);
                let result_vector = Vector3::new(m.x / m.w, HEIGHT as f32 - (m.y / m.w), m.z / m.w);

                screen_coords[j as usize] = result_vector;
                world_coords[j as usize] = v;
                intensity[j as usize] = mesh_normal.dot(light_dir);
            }

            renderer.triangle(
                screen_coords[0],
                screen_coords[1],
                screen_coords[2],
                Color::RGB(
                    (intensity[0] * 255.) as u8,
                    (intensity[1] * 255.) as u8,
                    (intensity[2] * 255.) as u8
                )
            );
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Implemented orbit camera moving by pressing the arrow keys<commit_after>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use assimp::Scene;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Vector4;
use cgmath::Zero;
use cgmath::Matrix4;
use cgmath::SquareMatrix;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 800 * 800] = [-1.; 800 * 800];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color, ) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn viewport(x: f32, y: f32, w: f32, h: f32) -> Matrix4<f32> {
    let mut viewport = Matrix4::<f32>::identity();
    viewport[3][0] = x + w / 2.;
    viewport[3][1] = y + h / 2.;
    viewport[3][2] = 255. / 2.; //depth

    viewport[0][0] = w / 2.;
    viewport[1][1] = h / 2.;
    viewport[2][2] = 255. / 2.;
    return viewport;
}

fn lookat(eye: Vector3<f32>, center: Vector3<f32>, up: Vector3<f32>) -> Matrix4<f32> {
    let z = (eye - center).normalize();
    let x = up.cross(z).normalize();
    let y = z.cross(x).normalize();
    let mut res = Matrix4::<f32>::identity();

    for i in 0..3 {
        res[i][0] = x[i];
        res[i][1] = y[i];
        res[i][2] = z[i];
        res[3][i] = -center[i];
    }

    return res;
}

fn normal(v: Vector3<f32>) -> f32 {
    (v.x * v.x + v.y * v.y + v.z * v.z).sqrt()
}

fn clear_z_buffer() {
    unsafe {
        Z_BUFFER = [-1.; 800 * 800];
    }
}

fn calc_eye_location(distance: f32, longitude: f32, latitude: f32) -> Vector3<f32> {
    let m_pi = std::f32::consts::PI;
    let l = distance * (m_pi * longitude / 180.0).cos();

    Vector3::new(
        l * -(m_pi * latitude / 180.0).sin(),
        distance * (m_pi * longitude / 180.0).sin(),
        l * (m_pi * latitude / 180.0).cos()
    )
}

fn render(renderer: &mut Renderer, scene: &Scene, dist: f32, long: f32, lat: f32) {
    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();
    clear_z_buffer();

    let eye = calc_eye_location(dist, long, lat);
    let center = Vector3::new(0., 0., 0.);

    let model_view = lookat(eye, center, Vector3::new(0., 1., 0.));
    let light_dir = Vector3::new(0., -1., -3.).normalize();
    let mut projection = Matrix4::<f32>::identity();
    let (x, y, w, h) = (WIDTH as f32 / 8., HEIGHT as f32 / 8., WIDTH as f32 * 3. / 4., HEIGHT as f32 * 3. / 4.);
    let viewport = viewport(x, y, w, h);

    projection[2][3] = -1. / normal(eye - center);

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut intensity: [f32; 3] = [0.; 3];

            for j in 0..3 {
                let v: Vector3<f32> = match mesh.get_vertex(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::new(0., 0., 0.)
                };

                let mesh_normal: Vector3<f32> = match mesh.get_normal(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::new(0., 0., 0.)
                };

                let m = viewport * projection * model_view * Vector4::<f32>::new(v.x, v.y, v.z, 1.);
                let result_vector = Vector3::new(m.x / m.w, HEIGHT as f32 - (m.y / m.w), m.z / m.w);

                screen_coords[j as usize] = result_vector;
                world_coords[j as usize] = v;
                intensity[j as usize] = mesh_normal.dot(light_dir);
            }

            renderer.triangle(
                screen_coords[0],
                screen_coords[1],
                screen_coords[2],
                Color::RGB(
                    (intensity[0] * 255.) as u8,
                    (intensity[1] * 255.) as u8,
                    (intensity[2] * 255.) as u8
                )
            );
        }
    }

    renderer.present();
}

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    let mut event_pump = sdl_context.event_pump().unwrap();

    let mut camera_longitude = 5.;
    let mut camera_latitude = 10.;
    let camera_distance = 10.;
    let velocity = 10.;

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                    camera_latitude -= 0.1 * velocity;
                },
                Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                    camera_latitude += 0.1 * velocity;
                },
                Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                    camera_longitude += 0.1 * velocity;
                },
                Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                    camera_longitude -= 0.1 * velocity;
                },
                _ => {}
            }
        }

        render(&mut renderer, &scene, camera_distance, camera_longitude, camera_latitude);
    }
}
<|endoftext|>


<commit_before>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    Rec { width : i32, height : i32, x : i32, y : i32 },
    /*VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },
    Character
    VWall
    HWall
    River
    Lava*/
    // TODO add color
    // TODO add background color
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

unsafe fn render_shape( s : &DrawMe ) {
    match s {
        &DrawMe::Rec { width, height, x, y } => render_rec( width, height, x, y ),
        _ => (),
    }
}

unsafe fn render_rec( w : i32, h : i32, x : i32, y : i32 ) {
    let dot = CString::new( "." ).unwrap();
    let h_line = CString::new( "-" ).unwrap();
    let v_line = CString::new( "|" ).unwrap();
    let plus = CString::new( "+" ).unwrap();

    let mut h2 = h + 2;
    while h2 > 0 {
        let d : &CString = if h2 == h + 2 {
            &h_line
        } else if h2 == 1 {
            &h_line
        } else {
            &dot
        };
        let mut w2 = w;

        let other_d : &CString = if h2 == h + 2 {
            &plus
        } else if h2 == 1 {
            &plus
        } else {
            &v_line
        };
        mvprintw( y + h2, x + w2 + 1, other_d.as_ptr() );
        while w2 > 0 {
            mvprintw( y + h2, x + w2, d.as_ptr() );
            w2 -= 1;
        }
        mvprintw( y + h2, x, other_d.as_ptr() );
        h2 -= 1;
    }
}

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();
        let mut shapes : Vec<DrawMe> = vec! [];

        // TODO need mode for entering rech, etc
        // TODO need mode for changing color

        while c as u8 as char != 'q' {
            let c2 = c as u8 as char;

            match c2 {
                /*'c' => {
                    shapes.push( DrawMe::Circle { radius: 5, x: x, y: y } );
                },*/
                'r' => {
                    shapes.push( DrawMe::Rec { width: 5, height: 8, x: x, y: y } );
                },
                'j' => {
                    y+=1;
                },
                'k' => {
                    y-=1;
                },
                'l' => {
                    x+=1;
                },
                'h' => {
                    x-=1;
                },
                _ => (),
            }

            for s in &shapes {
                render_shape( s );
            }

            cursor_move( y, x );
            refresh();

            c = getch();
        }

        endwin();
    }
}

<commit_msg>move the screen<commit_after>
mod curses;

use std::ffi::CString;

use curses::*;

enum DrawMe {
    Rec { width : i32, height : i32, x : i32, y : i32 },
    /*VHall { length : i32, x : i32, y : i32 },
    HHall { length : i32, x : i32, y : i32 },
    Character
    VWall
    HWall
    River
    Lava*/
    // TODO add color
    // TODO add background color
    // TODO can probably have a struct represent common items (x,y, color, etc)
}

unsafe fn render_shape( s : &DrawMe ) {
    match s {
        &DrawMe::Rec { width, height, x, y } => render_rec( width, height, x, y ),
        _ => (),
    }
}

unsafe fn render_rec( w : i32, h : i32, x : i32, y : i32 ) {
    let dot = CString::new( "." ).unwrap();
    let h_line = CString::new( "-" ).unwrap();
    let v_line = CString::new( "|" ).unwrap();
    let plus = CString::new( "+" ).unwrap();

    let mut h2 = h + 2;
    while h2 > 0 {
        let d : &CString = if h2 == h + 2 {
            &h_line
        } else if h2 == 1 {
            &h_line
        } else {
            &dot
        };
        let mut w2 = w;

        let other_d : &CString = if h2 == h + 2 {
            &plus
        } else if h2 == 1 {
            &plus
        } else {
            &v_line
        };
        mvprintw( y + h2 + UserY, x + w2 + 1 + UserX, other_d.as_ptr() );
        while w2 > 0 {
            mvprintw( y + h2 + UserY, x + w2 + UserX, d.as_ptr() );
            w2 -= 1;
        }
        mvprintw( y + h2 + UserY, x + UserX, other_d.as_ptr() );
        h2 -= 1;
    }
}

static mut UserX : i32 = 0;
static mut UserY : i32 = 0;

fn main() {
    let mut x = 0;
    let mut y = 0;
    unsafe {
        initscr();
        cbreak();
        noecho();

        let mut c = getch();
        let mut shapes : Vec<DrawMe> = vec! [];

        // TODO need mode for entering rech, etc
        // TODO need mode for changing color

        while c as u8 as char != 'q' {
            let c2 = c as u8 as char;

            match c2 {
                /*'c' => {
                    shapes.push( DrawMe::Circle { radius: 5, x: x, y: y } );
                },*/
                'r' => {
                    shapes.push( DrawMe::Rec { width: 0, height: 0, x: x, y: y } );
                },
                'j' => {
                    y+=1;
                },
                'k' => {
                    y-=1;
                },
                'l' => {
                    x+=1;
                },
                'h' => {
                    x-=1;
                },
                'J' => {
                    UserY += 1;
                },
                'K' => {
                    UserY -= 1;
                },
                'L' => {
                    UserX += 1;
                },
                'H' => {
                    UserX -= 1;
                },
                _ => (),
            }

            clear();

            for s in &shapes {
                render_shape( s );
            }

            cursor_move( y, x );
            refresh();

            c = getch();
        }

        endwin();
    }
}

<|endoftext|>


<commit_before><commit_msg>stable state<commit_after><|endoftext|>


<commit_before><commit_msg>Verify that header sections are found even if not used<commit_after><|endoftext|>


<commit_before>use core::cmp::PartialEq;
use core::ops::{BitAnd, BitOr, Not};
use core::marker::PhantomData;

pub trait ReadWrite<T>
{
    fn read(&self) -> T;
    fn write(&self, value: T);
}

/// Generic PIO
#[derive(Copy, Clone)]
pub struct Pio<T> {
    port: u16,
    value: PhantomData<T>,
}

/// Read/Write for byte PIO
impl ReadWrite<u8> for Pio<u8> {
    /// Read
    fn read(&self) -> u8 {
        let value: u8;
        unsafe {
            asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
        return value;
    }

    /// Write
    fn write(&self, value: u8) {
        unsafe {
            asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
    }
}

/// Read/Write for word PIO
impl ReadWrite<u16> for Pio<u16> {
    /// Read
    fn read(&self) -> u16 {
        let value: u16;
        unsafe {
            asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
        return value;
    }

    /// Write
    fn write(&self, value: u16) {
        unsafe {
            asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
    }
}

/// Read/Write for doubleword PIO
impl ReadWrite<u32> for Pio<u32> {
    /// Read
    fn read(&self) -> u32 {
        let value: u32;
        unsafe {
            asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
        return value;
    }

    /// Write
    fn write(&self, value: u32) {
        unsafe {
            asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
    }
}

impl<T> Pio<T>
    where Pio<T>: ReadWrite<T>,
          T: BitAnd<Output = T> + BitOr<Output = T> + PartialEq<T> + Not<Output = T> + Copy
{
    /// Create a PIO from a given port
    pub fn new(port: u16) -> Self {
        return Pio::<T> {
            port: port,
            value: PhantomData,
        };
    }

    pub fn readf(&self, flags: T) -> bool {
        (self.read() & flags) as T == flags
    }

    pub fn writef(&mut self, flags: T, value: bool) {
        let tmp: T = match value {
            true => self.read() | flags,
            false => self.read() & !flags,
        };
        self.write(tmp);
    }
}

/// PIO8
#[derive(Copy, Clone)]
pub struct Pio8 {
    port: u16,
}

impl Pio8 {
    /// Create a PIO8 from a given port
    pub fn new(port: u16) -> Self {
        return Pio8 { port: port };
    }

    /// Read
    pub unsafe fn read(&self) -> u8 {
        let value: u8;
        asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        return value;
    }

    /// Write
    pub unsafe fn write(&mut self, value: u8) {
        asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
    }

    pub unsafe fn readf(&self, flags: u8) -> bool {
        self.read() & flags == flags
    }

    pub unsafe fn writef(&mut self, flags: u8, value: bool) {
        if value {
            let value = self.read() | flags;
            self.write(value);
        } else {
            let value = self.read() & !flags;
            self.write(value);
        }
    }
}

// TODO: Remove
pub unsafe fn inb(port: u16) -> u8 {
    return Pio8::new(port).read();
}

// TODO: Remove
pub unsafe fn outb(port: u16, value: u8) {
    Pio8::new(port).write(value);
}

/// PIO16
#[derive(Copy, Clone)]
pub struct Pio16 {
    port: u16,
}

impl Pio16 {
    /// Create a new PIO16 from a given port
    pub fn new(port: u16) -> Self {
        return Pio16 { port: port };
    }

    /// Read
    pub unsafe fn read(&self) -> u16 {
        let value: u16;
        asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        return value;
    }

    /// Write
    pub unsafe fn write(&mut self, value: u16) {
        asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
    }

    pub unsafe fn readf(&self, flags: u16) -> bool {
        self.read() & flags == flags
    }

    pub unsafe fn writef(&mut self, flags: u16, value: bool) {
        if value {
            let value = self.read() | flags;
            self.write(value);
        } else {
            let value = self.read() & !flags;
            self.write(value);
        }
    }
}

// TODO: Remove
pub unsafe fn inw(port: u16) -> u16 {
    return Pio16::new(port).read();
}

// TODO: Remove
pub unsafe fn outw(port: u16, value: u16) {
    Pio16::new(port).write(value);
}

/// PIO32
#[derive(Copy, Clone)]
pub struct Pio32 {
    port: u16,
}

impl Pio32 {
    /// Create a new PIO32 from a port
    pub fn new(port: u16) -> Self {
        return Pio32 { port: port };
    }

    /// Read
    pub unsafe fn read(&self) -> u32 {
        let value: u32;
        asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        return value;
    }

    /// Write
    pub unsafe fn write(&mut self, value: u32) {
        asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
    }

    pub unsafe fn readf(&self, flags: u32) -> bool {
        self.read() & flags == flags
    }

    pub unsafe fn writef(&mut self, flags: u32, value: bool) {
        if value {
            let value = self.read() | flags;
            self.write(value);
        } else {
            let value = self.read() & !flags;
            self.write(value);
        }
    }
}

// TODO: Remove
pub unsafe fn ind(port: u16) -> u32 {
    return Pio32::new(port).read();
}

// TODO: Remove
pub unsafe fn outd(port: u16, value: u32) {
    Pio32::new(port).write(value);
}
<commit_msg>Convert in[bwd] and out[bwd] function to Pio<T><commit_after>use core::cmp::PartialEq;
use core::ops::{BitAnd, BitOr, Not};
use core::marker::PhantomData;

pub trait ReadWrite<T>
{
    fn read(&self) -> T;
    fn write(&self, value: T);
}

/// Generic PIO
#[derive(Copy, Clone)]
pub struct Pio<T> {
    port: u16,
    value: PhantomData<T>,
}

/// Read/Write for byte PIO
impl ReadWrite<u8> for Pio<u8> {
    /// Read
    fn read(&self) -> u8 {
        let value: u8;
        unsafe {
            asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
        return value;
    }

    /// Write
    fn write(&self, value: u8) {
        unsafe {
            asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
    }
}

/// Read/Write for word PIO
impl ReadWrite<u16> for Pio<u16> {
    /// Read
    fn read(&self) -> u16 {
        let value: u16;
        unsafe {
            asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
        return value;
    }

    /// Write
    fn write(&self, value: u16) {
        unsafe {
            asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
    }
}

/// Read/Write for doubleword PIO
impl ReadWrite<u32> for Pio<u32> {
    /// Read
    fn read(&self) -> u32 {
        let value: u32;
        unsafe {
            asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
        return value;
    }

    /// Write
    fn write(&self, value: u32) {
        unsafe {
            asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
        }
    }
}

impl<T> Pio<T>
    where Pio<T>: ReadWrite<T>,
          T: BitAnd<Output = T> + BitOr<Output = T> + PartialEq<T> + Not<Output = T> + Copy
{
    /// Create a PIO from a given port
    pub fn new(port: u16) -> Self {
        return Pio::<T> {
            port: port,
            value: PhantomData,
        };
    }

    pub fn readf(&self, flags: T) -> bool {
        (self.read() & flags) as T == flags
    }

    pub fn writef(&mut self, flags: T, value: bool) {
        let tmp: T = match value {
            true => self.read() | flags,
            false => self.read() & !flags,
        };
        self.write(tmp);
    }
}

/// PIO8
#[derive(Copy, Clone)]
pub struct Pio8 {
    port: u16,
}

impl Pio8 {
    /// Create a PIO8 from a given port
    pub fn new(port: u16) -> Self {
        return Pio8 { port: port };
    }

    /// Read
    pub unsafe fn read(&self) -> u8 {
        let value: u8;
        asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        return value;
    }

    /// Write
    pub unsafe fn write(&mut self, value: u8) {
        asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
    }

    pub unsafe fn readf(&self, flags: u8) -> bool {
        self.read() & flags == flags
    }

    pub unsafe fn writef(&mut self, flags: u8, value: bool) {
        if value {
            let value = self.read() | flags;
            self.write(value);
        } else {
            let value = self.read() & !flags;
            self.write(value);
        }
    }
}

// TODO: Remove
pub unsafe fn inb(port: u16) -> u8 {
    Pio::<u8>::new(port).read()
}

// TODO: Remove
pub unsafe fn outb(port: u16, value: u8) {
    Pio::<u8>::new(port).write(value);
}

/// PIO16
#[derive(Copy, Clone)]
pub struct Pio16 {
    port: u16,
}

impl Pio16 {
    /// Create a new PIO16 from a given port
    pub fn new(port: u16) -> Self {
        return Pio16 { port: port };
    }

    /// Read
    pub unsafe fn read(&self) -> u16 {
        let value: u16;
        asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        return value;
    }

    /// Write
    pub unsafe fn write(&mut self, value: u16) {
        asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
    }

    pub unsafe fn readf(&self, flags: u16) -> bool {
        self.read() & flags == flags
    }

    pub unsafe fn writef(&mut self, flags: u16, value: bool) {
        if value {
            let value = self.read() | flags;
            self.write(value);
        } else {
            let value = self.read() & !flags;
            self.write(value);
        }
    }
}

// TODO: Remove
pub unsafe fn inw(port: u16) -> u16 {
    Pio::<u16>::new(port).read()
}

// TODO: Remove
pub unsafe fn outw(port: u16, value: u16) {
    Pio::<u16>::new(port).write(value);
}

/// PIO32
#[derive(Copy, Clone)]
pub struct Pio32 {
    port: u16,
}

impl Pio32 {
    /// Create a new PIO32 from a port
    pub fn new(port: u16) -> Self {
        return Pio32 { port: port };
    }

    /// Read
    pub unsafe fn read(&self) -> u32 {
        let value: u32;
        asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
        return value;
    }

    /// Write
    pub unsafe fn write(&mut self, value: u32) {
        asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
    }

    pub unsafe fn readf(&self, flags: u32) -> bool {
        self.read() & flags == flags
    }

    pub unsafe fn writef(&mut self, flags: u32, value: bool) {
        if value {
            let value = self.read() | flags;
            self.write(value);
        } else {
            let value = self.read() & !flags;
            self.write(value);
        }
    }
}

// TODO: Remove
pub unsafe fn ind(port: u16) -> u32 {
    Pio::<u32>::new(port).read()
}

// TODO: Remove
pub unsafe fn outd(port: u16, value: u32) {
    Pio::<u32>::new(port).write(value);
}
<|endoftext|>


<commit_before>//! way-cooler registry.

use std::ops::Deref;
use std::cmp::Eq;
use std::fmt::Display;
use std::hash::Hash;
use std::borrow::Borrow;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use rustc_serialize::Decodable;
use rustc_serialize::json::{Json, ToJson, Decoder, DecoderError};

mod types;
mod commands;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryField>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> = RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq)]
pub enum RegistryError {
    /// The registry key was not found
    KeyNotFound,
    /// The registry key was of the wrong type
    WrongKeyType,
    /// Attempting to set a readonly value
    InvalidOperation,
    /// The object couldn't be converted to/from Json
    DecoderError(DecoderError)
}

/// Result type of gets/sets to the registry
pub type RegistryResult<T> = Result<T, RegistryError>;

/// Initialize the registry (register default commands)
pub fn init() {
    commands::register_defaults();
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().expect("Unable to read from registry!")
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().expect("Unable to write to registry!")
}

/// Gets a RegistryField enum with the specified name
pub fn get_field<K>(name: &K) -> Option<RegistryField>
    where String: Borrow<K>, K: Hash + Eq + Display {
    // clone() will either clone an Arc or an Arc+AccessFlags
    let result = read_lock().get(name).map(|v| v.clone());
    trace!("get: {} => {:?}", name, &result);
    return result;
}

/// Attempts to get a command from the registry.
pub fn get_command<K>(name: &K) -> RegistryResult<CommandFn>
    where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
        RegistryField::Command(com) => Ok(com),
        _ => Err(RegistryError::WrongKeyType)
    })
}

/// Gets a data type from the registry, returning a reference to the property
/// method if the field is a property.
pub fn get_data<K>(name: &K) -> RegistryResult<RegistryGetData>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
            RegistryField::Object { flags, data } =>
                Ok(RegistryGetData::Object(flags, data)),
            RegistryField::Property { get: maybe_get, .. } =>
                match maybe_get {
                    Some(get) => Ok(RegistryGetData::Property(get)),
                    None => Err(RegistryError::InvalidOperation)
                },
            _ => Err(RegistryError::WrongKeyType)
        })
}

/// Get a Rust structure from the registry
#[allow(dead_code)]
pub fn get_struct<K, T>(name: &K) -> RegistryResult<(AccessFlags, T)>
where String: Borrow <K>, K: Hash + Eq + Display, T: Decodable {
    get_json(name).and_then(|(flags, json)|
        T::decode(&mut Decoder::new(json.deref().clone()))
                            .map_err(|e| RegistryError::DecoderError(e))
                            .map(|data| (flags, data)))
}

/// Get Json data from the registry, evaluating if a property was found.
pub fn get_json<K>(name: &K) -> RegistryResult<(AccessFlags, Arc<Json>)>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_data(name).map(|val| val.resolve())
}

/// Set a value to the given registry field.
pub fn set_field(key: String, value: RegistryField)
                 -> RegistryResult<Option<RegistryField>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type.can_set_from(value.get_type()) {
                Ok(Some(entry.insert(value)))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        },
        Entry::Vacant(vacancy) => {
            vacancy.insert(value);
            Ok(None)
        }
    }
}

/// Set a command to the given Command
#[allow(dead_code)]
pub fn set_command(key: String, command: CommandFn)
                   -> RegistryResult<Option<CommandFn>> {
    set_field(key, RegistryField::Command(command))
        .map(|maybe_field|
              maybe_field.and_then(|field|
                                    field.get_command()))
}

/// Set a value to the given JSON value.
#[allow(dead_code)]
pub fn set_json(key: String, flags: AccessFlags, json: Json)
                -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(vacancy) => {
            vacancy.insert(RegistryField::Object {
                flags: flags, data: Arc::new(json)
            });
            return Ok(None);
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type == FieldType::Object {
                return Ok(entry.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                }).as_object());
            }
            else if first_type == FieldType::Property {
                match entry.get().clone().as_property_set() {
                    Some(func) => {
                        func(json);
                        return;
                    }
                    None => return Err(RegistryError::InvalidOperation)
                }
            }
            else {
                return Err(RegistryError::WrongKeyType);
            }
        }
    }
    return Ok(None);
}

/// Set an object/property in the registry to a value using a ToJson.
#[allow(dead_code)]
pub fn set_struct<T: ToJson>(key: String, flags: AccessFlags, value: T)
                             -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    set_json(key, flags, value.to_json())
}

/// Sets a value for a given Json value, optionally returning the associated property.
#[allow(dead_code)]
pub fn set_with_property(key: String, flags: AccessFlags, json: Json)
                         -> RegistryResult<Option<(Json, SetFn)>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(vacancy) => {
            vacancy.insert(RegistryField::Object {
                flags: flags, data: Arc::new(json)
            });
            Ok(None)
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type == FieldType::Object {
                entry.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                });
                Ok(None)
            }
            else if first_type == FieldType::Property {
                Ok(Some((json, entry.get().clone().as_property_set()
                   .expect("set_json_property: checked value of field type"))))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        }
    }
}

/// Binds properties to a field of the registry
#[allow(dead_code)]
pub fn set_property_field(key: String, get_fn: Option<GetFn>, set_fn: Option<SetFn>)
                          -> RegistryResult<Option<RegistryField>> {
    set_field(key, RegistryField::Property { get: get_fn, set: set_fn })
}

/// Whether this map contains a key of any type
#[allow(dead_code)]
pub fn contains_key<K>(key: &K) -> bool
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("contains_key: {}", *key);
    let read_reg = read_lock();
    read_reg.contains_key(key)
}

/// Whether the registry contains a key of some type:
/// None: no key
/// true: same type key
/// false: different type key
#[allow(dead_code)]
pub fn contains_key_of<K>(key: &K, field_type: FieldType) -> Option<bool>
where String: Borrow<K>, K: Hash + Eq + Display {
    let read_reg = read_lock();
    read_reg.get(key).map(|field| field.get_type() == field_type)
}
<commit_msg>Fixed return statement<commit_after>//! way-cooler registry.

use std::ops::Deref;
use std::cmp::Eq;
use std::fmt::Display;
use std::hash::Hash;
use std::borrow::Borrow;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use rustc_serialize::Decodable;
use rustc_serialize::json::{Json, ToJson, Decoder, DecoderError};

mod types;
mod commands;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryField>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> = RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq)]
pub enum RegistryError {
    /// The registry key was not found
    KeyNotFound,
    /// The registry key was of the wrong type
    WrongKeyType,
    /// Attempting to set a readonly value
    InvalidOperation,
    /// The object couldn't be converted to/from Json
    DecoderError(DecoderError)
}

/// Result type of gets/sets to the registry
pub type RegistryResult<T> = Result<T, RegistryError>;

/// Initialize the registry (register default commands)
pub fn init() {
    commands::register_defaults();
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().expect("Unable to read from registry!")
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().expect("Unable to write to registry!")
}

/// Gets a RegistryField enum with the specified name
pub fn get_field<K>(name: &K) -> Option<RegistryField>
    where String: Borrow<K>, K: Hash + Eq + Display {
    // clone() will either clone an Arc or an Arc+AccessFlags
    let result = read_lock().get(name).map(|v| v.clone());
    trace!("get: {} => {:?}", name, &result);
    return result;
}

/// Attempts to get a command from the registry.
pub fn get_command<K>(name: &K) -> RegistryResult<CommandFn>
    where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
        RegistryField::Command(com) => Ok(com),
        _ => Err(RegistryError::WrongKeyType)
    })
}

/// Gets a data type from the registry, returning a reference to the property
/// method if the field is a property.
pub fn get_data<K>(name: &K) -> RegistryResult<RegistryGetData>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
            RegistryField::Object { flags, data } =>
                Ok(RegistryGetData::Object(flags, data)),
            RegistryField::Property { get: maybe_get, .. } =>
                match maybe_get {
                    Some(get) => Ok(RegistryGetData::Property(get)),
                    None => Err(RegistryError::InvalidOperation)
                },
            _ => Err(RegistryError::WrongKeyType)
        })
}

/// Get a Rust structure from the registry
#[allow(dead_code)]
pub fn get_struct<K, T>(name: &K) -> RegistryResult<(AccessFlags, T)>
where String: Borrow <K>, K: Hash + Eq + Display, T: Decodable {
    get_json(name).and_then(|(flags, json)|
        T::decode(&mut Decoder::new(json.deref().clone()))
                            .map_err(|e| RegistryError::DecoderError(e))
                            .map(|data| (flags, data)))
}

/// Get Json data from the registry, evaluating if a property was found.
pub fn get_json<K>(name: &K) -> RegistryResult<(AccessFlags, Arc<Json>)>
where String: Borrow<K>, K: Hash + Eq + Display {
    get_data(name).map(|val| val.resolve())
}

/// Set a value to the given registry field.
pub fn set_field(key: String, value: RegistryField)
                 -> RegistryResult<Option<RegistryField>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type.can_set_from(value.get_type()) {
                Ok(Some(entry.insert(value)))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        },
        Entry::Vacant(vacancy) => {
            vacancy.insert(value);
            Ok(None)
        }
    }
}

/// Set a command to the given Command
#[allow(dead_code)]
pub fn set_command(key: String, command: CommandFn)
                   -> RegistryResult<Option<CommandFn>> {
    set_field(key, RegistryField::Command(command))
        .map(|maybe_field|
              maybe_field.and_then(|field|
                                    field.get_command()))
}

/// Set a value to the given JSON value.
#[allow(dead_code)]
pub fn set_json(key: String, flags: AccessFlags, json: Json)
                -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(vacancy) => {
            vacancy.insert(RegistryField::Object {
                flags: flags, data: Arc::new(json)
            });
            return Ok(None);
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type == FieldType::Object {
                return Ok(entry.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                }).as_object());
            }
            else if first_type == FieldType::Property {
                match entry.get().clone().as_property_set() {
                    Some(func) => {
                        func(json);
                        return Ok(None);
                    }
                    None => return Err(RegistryError::InvalidOperation)
                }
            }
            else {
                return Err(RegistryError::WrongKeyType);
            }
        }
    }
    return Ok(None);
}

/// Set an object/property in the registry to a value using a ToJson.
#[allow(dead_code)]
pub fn set_struct<T: ToJson>(key: String, flags: AccessFlags, value: T)
                             -> RegistryResult<Option<(AccessFlags, Arc<Json>)>> {
    set_json(key, flags, value.to_json())
}

/// Sets a value for a given Json value, optionally returning the associated property.
#[allow(dead_code)]
pub fn set_with_property(key: String, flags: AccessFlags, json: Json)
                         -> RegistryResult<Option<(Json, SetFn)>> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(vacancy) => {
            vacancy.insert(RegistryField::Object {
                flags: flags, data: Arc::new(json)
            });
            Ok(None)
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            if first_type == FieldType::Object {
                entry.insert(RegistryField::Object {
                    flags: flags, data: Arc::new(json)
                });
                Ok(None)
            }
            else if first_type == FieldType::Property {
                Ok(Some((json, entry.get().clone().as_property_set()
                   .expect("set_json_property: checked value of field type"))))
            }
            else {
                Err(RegistryError::WrongKeyType)
            }
        }
    }
}

/// Binds properties to a field of the registry
#[allow(dead_code)]
pub fn set_property_field(key: String, get_fn: Option<GetFn>, set_fn: Option<SetFn>)
                          -> RegistryResult<Option<RegistryField>> {
    set_field(key, RegistryField::Property { get: get_fn, set: set_fn })
}

/// Whether this map contains a key of any type
#[allow(dead_code)]
pub fn contains_key<K>(key: &K) -> bool
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("contains_key: {}", *key);
    let read_reg = read_lock();
    read_reg.contains_key(key)
}

/// Whether the registry contains a key of some type:
/// None: no key
/// true: same type key
/// false: different type key
#[allow(dead_code)]
pub fn contains_key_of<K>(key: &K, field_type: FieldType) -> Option<bool>
where String: Borrow<K>, K: Hash + Eq + Display {
    let read_reg = read_lock();
    read_reg.get(key).map(|field| field.get_type() == field_type)
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Batches are structures containing all the data required for the draw call,
//! except for the target frame. Here we define the `Batch` trait as well as
//! `RefBatch` and `OwnedBatch` implementations.

use std::fmt;
use std::num::from_uint;
use std::cmp::Ordering;
use std::marker::PhantomData;
use device::{Resources, PrimitiveType, ProgramHandle};
use render::mesh;
use render::mesh::ToSlice;
use shade::{ParameterError, ShaderParam};
use render::state::DrawState;

/// An error occurring at batch creation
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
    /// Error connecting mesh attributes
    Mesh(mesh::Error),
    /// Error connecting shader parameters
    Parameters(ParameterError),
    /// Error context is full
    ContextFull,
}

/// Return type for `Batch::get_data()``
pub type BatchData<'a, R: Resources> = (&'a mesh::Mesh<R>, mesh::AttributeIter,
                                        &'a mesh::Slice<R>, &'a DrawState);

/// Abstract batch trait
#[allow(missing_docs)]
pub trait Batch {
    type Resources: Resources;
    /// Possible errors occurring at batch access
    type Error: fmt::Debug;
    /// Obtain information about the mesh, program, and state
    fn get_data(&self) -> Result<BatchData<Self::Resources>, Self::Error>;
    /// Fill shader parameter values
    fn fill_params(&self, ::shade::ParamValues<Self::Resources>)
                   -> Result<&ProgramHandle<Self::Resources>, Self::Error>;
}

/// A batch that is constructed on the fly when rendering.
/// Meant to be a struct, blocked by #614
pub type ImplicitBatch<'a, T: ShaderParam> = (
    &'a mesh::Mesh<T::Resources>,
    mesh::Slice<T::Resources>,
    &'a ProgramHandle<T::Resources>,
    &'a T,
    &'a DrawState
);

impl DrawState {
    /// Create an implicit batch
    pub fn bind<'a, T: ShaderParam>(&'a self,
                 mesh: &'a mesh::Mesh<T::Resources>,
                 slice: mesh::Slice<T::Resources>,
                 program: &'a ProgramHandle<T::Resources>,
                 data: &'a T) -> ImplicitBatch<'a, T> {
        (mesh, slice, program, data, self)
    }
}

impl<'a, T: ShaderParam> Batch for ImplicitBatch<'a, T> {
    type Resources = T::Resources;
    type Error = Error;

    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        let (mesh, ref slice, program, _, state) = *self;
        match mesh::Link::new(mesh, &program.get_info()) {
            Ok(link) => Ok((mesh, link.to_iter(), &slice, state)),
            Err(e) => Err(Error::Mesh(e)),
        }
    }

    fn fill_params(&self, values: ::shade::ParamValues<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        let (_, _, program, params, _) = *self;
        match ShaderParam::create_link(None::<&T>, &program.get_info()) {
            Ok(link) => {
                params.fill_params(&link, values);
                Ok(program)
            },
            Err(e) => return Err(Error::Parameters(e)),
        }
    }
}

/// Owned batch - self-contained, but has heap-allocated data
pub struct OwnedBatch<T: ShaderParam> {
    mesh: mesh::Mesh<T::Resources>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice<T::Resources>,
    /// Parameter data.
    pub param: T,
    program: ProgramHandle<T::Resources>,
    param_link: T::Link,
    /// Draw state
    pub state: DrawState,
}

impl<T: ShaderParam> OwnedBatch<T> {
    /// Create a new owned batch
    pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>, param: T)
           -> Result<OwnedBatch<T>, Error> {
        let slice = mesh.to_slice(PrimitiveType::TriangleList);
        let mesh_link = match mesh::Link::new(&mesh, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let param_link = match ShaderParam::create_link(None::<&T>, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e)),
        };
        Ok(OwnedBatch {
            mesh: mesh,
            mesh_link: mesh_link,
            slice: slice,
            program: program,
            param: param,
            param_link: param_link,
            state: DrawState::new(),
        })
    }
}

impl<T: ShaderParam> Batch for OwnedBatch<T> {
    type Resources = T::Resources;
    type Error = ();

    fn get_data(&self) -> Result<BatchData<T::Resources>, ()> {
        Ok((&self.mesh, self.mesh_link.to_iter(), &self.slice, &self.state))
    }

    fn fill_params(&self, values: ::shade::ParamValues<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, ()> {
        self.param.fill_params(&self.param_link, values);
        Ok(&self.program)
    }
}

type Index = u16;

//#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
struct Id<T>(Index, PhantomData<T>);

impl<T> Copy for Id<T> {}

impl<T> Id<T> {
    fn unwrap(&self) -> Index {
        let Id(i, _) = *self;
        i
    }
}

impl<T> fmt::Debug for Id<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Id(i, _) = *self;
        write!(f, "Id({})", i)
    }
}

impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Id<T>) -> bool {
        self.unwrap() == other.unwrap()
    }
}

impl<T> Eq for Id<T> {}

impl<T> PartialOrd for Id<T> {
    fn partial_cmp(&self, other: &Id<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T> Ord for Id<T> {
    fn cmp(&self, other: &Id<T>) -> Ordering {
        self.unwrap().cmp(&other.unwrap())
    }
}

struct Array<T> {
    data: Vec<T>,
    //generation: u16,
}

/// Error accessing outside of the array
#[derive(Debug)]
pub struct OutOfBounds(pub usize);

impl<T> Array<T> {
    fn new() -> Array<T> {
        Array {
            data: Vec::new(),
            //generation: 0,
        }
    }

    fn get(&self, id: Id<T>) -> Result<&T, OutOfBounds> {
        let Id(i, _) = id;
        if (i as usize) < self.data.len() {
            Ok(&self.data[i as usize])
        }else {
            Err(OutOfBounds(i as usize))
        }
    }
}

impl<T: Clone + PartialEq> Array<T> {
    fn find_or_insert(&mut self, value: &T) -> Option<Id<T>> {
        match self.data.iter().position(|v| v == value) {
            Some(i) => from_uint::<Index>(i).map(|id| Id(id, PhantomData)),
            None => {
                from_uint::<Index>(self.data.len()).map(|id| {
                    self.data.push(value.clone());
                    Id(id, PhantomData)
                })
            },
        }
    }
}

/// Ref batch - copyable and smaller, but depends on the `Context`.
/// It has references to the resources (mesh, program, state), that are held
/// by the context that created the batch, so these have to be used together.
pub struct RefBatch<T: ShaderParam> {
    mesh_id: Id<mesh::Mesh<T::Resources>>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice<T::Resources>,
    program_id: Id<ProgramHandle<T::Resources>>,
    param_link: T::Link,
    state_id: Id<DrawState>,
}

impl<T: ShaderParam> Copy for RefBatch<T> where T::Link: Copy {}

impl<T: ShaderParam> fmt::Debug for RefBatch<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "RefBatch(mesh: {:?}, slice: {:?}, program: {:?}, state: {:?})",
            self.mesh_id, self.slice, self.program_id, self.state_id)
    }
}

impl<T: ShaderParam> PartialEq for RefBatch<T> {
    fn eq(&self, other: &RefBatch<T>) -> bool {
        self.program_id == other.program_id &&
        self.state_id == other.state_id &&
        self.mesh_id == other.mesh_id
    }
}

impl<T: ShaderParam> Eq for RefBatch<T> {}

impl<T: ShaderParam> PartialOrd for RefBatch<T> {
    fn partial_cmp(&self, other: &RefBatch<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: ShaderParam> Ord for RefBatch<T> {
    fn cmp(&self, other: &RefBatch<T>) -> Ordering {
        (&self.program_id, &self.state_id, &self.mesh_id).cmp(
        &(&other.program_id, &other.state_id, &other.mesh_id))
    }
}

impl<T: ShaderParam> RefBatch<T> {
    /// Compare meshes by Id
    pub fn cmp_mesh(&self, other: &RefBatch<T>) -> Ordering {
        self.mesh_id.cmp(&other.mesh_id)
    }
    /// Compare programs by Id
    pub fn cmp_program(&self, other: &RefBatch<T>) -> Ordering {
        self.program_id.cmp(&other.program_id)
    }
    /// Compare draw states by Id
    pub fn cmp_state(&self, other: &RefBatch<T>) -> Ordering {
        self.state_id.cmp(&other.state_id)
    }
}

/// Factory of ref batches, required to always be used with them.
pub struct Context<R: Resources> {
    meshes: Array<mesh::Mesh<R>>,
    programs: Array<ProgramHandle<R>>,
    states: Array<DrawState>,
}

/// A RefBatch completed by the shader parameters and a context
/// Implements `Batch` thus can be drawn.
/// It is meant to be a struct, but we have lots of lifetime issues
/// with associated resources, binding which looks nasty (#614)
pub type RefBatchFull<'a, T: ShaderParam> = (
    &'a RefBatch<T>,
    &'a T,
    &'a Context<T::Resources>
);

impl<R: Resources> Context<R> {
    /// Create a new empty `Context`
    pub fn new() -> Context<R> {
        Context {
            meshes: Array::new(),
            programs: Array::new(),
            states: Array::new(),
        }
    }
}

impl<R: Resources> Context<R> {
    /// Produce a new ref batch
    pub fn make_batch<T: ShaderParam<Resources = R>>(&mut self,
                      program: &ProgramHandle<R>,
                      mesh: &mesh::Mesh<R>,
                      slice: mesh::Slice<R>,
                      state: &DrawState)
                      -> Result<RefBatch<T>, Error> {
        let mesh_link = match mesh::Link::new(mesh, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let link = match ShaderParam::create_link(None::<&T>, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e))
        };
        let mesh_id = match self.meshes.find_or_insert(mesh) {
            Some(id) => id,
            None => return Err(Error::ContextFull),
        };
        let program_id = match self.programs.find_or_insert(program) {
            Some(id) => id,
            None => return Err(Error::ContextFull),
        };
        let state_id = match self.states.find_or_insert(state) {
            Some(id) => id,
            None => return Err(Error::ContextFull),
        };

        Ok(RefBatch {
            mesh_id: mesh_id,
            mesh_link: mesh_link,
            slice: slice,
            program_id: program_id,
            param_link: link,
            state_id: state_id,
        })
    }

    /// Complete a RefBatch temporarily by turning it into RefBatchFull
    pub fn bind<'a, T: ShaderParam<Resources = R> + 'a>(&'a self,
                 batch: &'a RefBatch<T>, data: &'a T) -> RefBatchFull<'a, T> {
        (batch, data, self)
    }
}

impl<'a, T: ShaderParam + 'a> Batch for RefBatchFull<'a, T> {
    type Resources = T::Resources;
    type Error = OutOfBounds;

    fn get_data(&self) -> Result<BatchData<T::Resources>, OutOfBounds> {
        let (b, _, ctx) = *self;
        Ok((try!(ctx.meshes.get(b.mesh_id)),
            b.mesh_link.to_iter(),
            &b.slice,
            try!(ctx.states.get(b.state_id))
        ))
    }

    fn fill_params(&self, values: ::shade::ParamValues<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, OutOfBounds> {
        let (b, data, ctx) = *self;
        data.fill_params(&b.param_link, values);
        ctx.programs.get(b.program_id)
    }
}
<commit_msg>Fixed unnecessary borrow<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Batches are structures containing all the data required for the draw call,
//! except for the target frame. Here we define the `Batch` trait as well as
//! `RefBatch` and `OwnedBatch` implementations.

use std::fmt;
use std::num::from_uint;
use std::cmp::Ordering;
use std::marker::PhantomData;
use device::{Resources, PrimitiveType, ProgramHandle};
use render::mesh;
use render::mesh::ToSlice;
use shade::{ParameterError, ShaderParam};
use render::state::DrawState;

/// An error occurring at batch creation
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
    /// Error connecting mesh attributes
    Mesh(mesh::Error),
    /// Error connecting shader parameters
    Parameters(ParameterError),
    /// Error context is full
    ContextFull,
}

/// Return type for `Batch::get_data()``
pub type BatchData<'a, R: Resources> = (&'a mesh::Mesh<R>, mesh::AttributeIter,
                                        &'a mesh::Slice<R>, &'a DrawState);

/// Abstract batch trait
#[allow(missing_docs)]
pub trait Batch {
    type Resources: Resources;
    /// Possible errors occurring at batch access
    type Error: fmt::Debug;
    /// Obtain information about the mesh, program, and state
    fn get_data(&self) -> Result<BatchData<Self::Resources>, Self::Error>;
    /// Fill shader parameter values
    fn fill_params(&self, ::shade::ParamValues<Self::Resources>)
                   -> Result<&ProgramHandle<Self::Resources>, Self::Error>;
}

/// A batch that is constructed on the fly when rendering.
/// Meant to be a struct, blocked by #614
pub type ImplicitBatch<'a, T: ShaderParam> = (
    &'a mesh::Mesh<T::Resources>,
    mesh::Slice<T::Resources>,
    &'a ProgramHandle<T::Resources>,
    &'a T,
    &'a DrawState
);

impl DrawState {
    /// Create an implicit batch
    pub fn bind<'a, T: ShaderParam>(&'a self,
                 mesh: &'a mesh::Mesh<T::Resources>,
                 slice: mesh::Slice<T::Resources>,
                 program: &'a ProgramHandle<T::Resources>,
                 data: &'a T) -> ImplicitBatch<'a, T> {
        (mesh, slice, program, data, self)
    }
}

impl<'a, T: ShaderParam> Batch for ImplicitBatch<'a, T> {
    type Resources = T::Resources;
    type Error = Error;

    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        let (mesh, ref slice, program, _, state) = *self;
        match mesh::Link::new(mesh, program.get_info()) {
            Ok(link) => Ok((mesh, link.to_iter(), &slice, state)),
            Err(e) => Err(Error::Mesh(e)),
        }
    }

    fn fill_params(&self, values: ::shade::ParamValues<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        let (_, _, program, params, _) = *self;
        match ShaderParam::create_link(None::<&T>, &program.get_info()) {
            Ok(link) => {
                params.fill_params(&link, values);
                Ok(program)
            },
            Err(e) => return Err(Error::Parameters(e)),
        }
    }
}

/// Owned batch - self-contained, but has heap-allocated data
pub struct OwnedBatch<T: ShaderParam> {
    mesh: mesh::Mesh<T::Resources>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice<T::Resources>,
    /// Parameter data.
    pub param: T,
    program: ProgramHandle<T::Resources>,
    param_link: T::Link,
    /// Draw state
    pub state: DrawState,
}

impl<T: ShaderParam> OwnedBatch<T> {
    /// Create a new owned batch
    pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>, param: T)
           -> Result<OwnedBatch<T>, Error> {
        let slice = mesh.to_slice(PrimitiveType::TriangleList);
        let mesh_link = match mesh::Link::new(&mesh, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let param_link = match ShaderParam::create_link(None::<&T>, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e)),
        };
        Ok(OwnedBatch {
            mesh: mesh,
            mesh_link: mesh_link,
            slice: slice,
            program: program,
            param: param,
            param_link: param_link,
            state: DrawState::new(),
        })
    }
}

impl<T: ShaderParam> Batch for OwnedBatch<T> {
    type Resources = T::Resources;
    type Error = ();

    fn get_data(&self) -> Result<BatchData<T::Resources>, ()> {
        Ok((&self.mesh, self.mesh_link.to_iter(), &self.slice, &self.state))
    }

    fn fill_params(&self, values: ::shade::ParamValues<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, ()> {
        self.param.fill_params(&self.param_link, values);
        Ok(&self.program)
    }
}

type Index = u16;

//#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
struct Id<T>(Index, PhantomData<T>);

impl<T> Copy for Id<T> {}

impl<T> Id<T> {
    fn unwrap(&self) -> Index {
        let Id(i, _) = *self;
        i
    }
}

impl<T> fmt::Debug for Id<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Id(i, _) = *self;
        write!(f, "Id({})", i)
    }
}

impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Id<T>) -> bool {
        self.unwrap() == other.unwrap()
    }
}

impl<T> Eq for Id<T> {}

impl<T> PartialOrd for Id<T> {
    fn partial_cmp(&self, other: &Id<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T> Ord for Id<T> {
    fn cmp(&self, other: &Id<T>) -> Ordering {
        self.unwrap().cmp(&other.unwrap())
    }
}

struct Array<T> {
    data: Vec<T>,
    //generation: u16,
}

/// Error accessing outside of the array
#[derive(Debug)]
pub struct OutOfBounds(pub usize);

impl<T> Array<T> {
    fn new() -> Array<T> {
        Array {
            data: Vec::new(),
            //generation: 0,
        }
    }

    fn get(&self, id: Id<T>) -> Result<&T, OutOfBounds> {
        let Id(i, _) = id;
        if (i as usize) < self.data.len() {
            Ok(&self.data[i as usize])
        }else {
            Err(OutOfBounds(i as usize))
        }
    }
}

impl<T: Clone + PartialEq> Array<T> {
    fn find_or_insert(&mut self, value: &T) -> Option<Id<T>> {
        match self.data.iter().position(|v| v == value) {
            Some(i) => from_uint::<Index>(i).map(|id| Id(id, PhantomData)),
            None => {
                from_uint::<Index>(self.data.len()).map(|id| {
                    self.data.push(value.clone());
                    Id(id, PhantomData)
                })
            },
        }
    }
}

/// Ref batch - copyable and smaller, but depends on the `Context`.
/// It has references to the resources (mesh, program, state), that are held
/// by the context that created the batch, so these have to be used together.
pub struct RefBatch<T: ShaderParam> {
    mesh_id: Id<mesh::Mesh<T::Resources>>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice<T::Resources>,
    program_id: Id<ProgramHandle<T::Resources>>,
    param_link: T::Link,
    state_id: Id<DrawState>,
}

impl<T: ShaderParam> Copy for RefBatch<T> where T::Link: Copy {}

impl<T: ShaderParam> fmt::Debug for RefBatch<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "RefBatch(mesh: {:?}, slice: {:?}, program: {:?}, state: {:?})",
            self.mesh_id, self.slice, self.program_id, self.state_id)
    }
}

impl<T: ShaderParam> PartialEq for RefBatch<T> {
    fn eq(&self, other: &RefBatch<T>) -> bool {
        self.program_id == other.program_id &&
        self.state_id == other.state_id &&
        self.mesh_id == other.mesh_id
    }
}

impl<T: ShaderParam> Eq for RefBatch<T> {}

impl<T: ShaderParam> PartialOrd for RefBatch<T> {
    fn partial_cmp(&self, other: &RefBatch<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: ShaderParam> Ord for RefBatch<T> {
    fn cmp(&self, other: &RefBatch<T>) -> Ordering {
        (&self.program_id, &self.state_id, &self.mesh_id).cmp(
        &(&other.program_id, &other.state_id, &other.mesh_id))
    }
}

impl<T: ShaderParam> RefBatch<T> {
    /// Compare meshes by Id
    pub fn cmp_mesh(&self, other: &RefBatch<T>) -> Ordering {
        self.mesh_id.cmp(&other.mesh_id)
    }
    /// Compare programs by Id
    pub fn cmp_program(&self, other: &RefBatch<T>) -> Ordering {
        self.program_id.cmp(&other.program_id)
    }
    /// Compare draw states by Id
    pub fn cmp_state(&self, other: &RefBatch<T>) -> Ordering {
        self.state_id.cmp(&other.state_id)
    }
}

/// Factory of ref batches, required to always be used with them.
pub struct Context<R: Resources> {
    meshes: Array<mesh::Mesh<R>>,
    programs: Array<ProgramHandle<R>>,
    states: Array<DrawState>,
}

/// A RefBatch completed by the shader parameters and a context
/// Implements `Batch` thus can be drawn.
/// It is meant to be a struct, but we have lots of lifetime issues
/// with associated resources, binding which looks nasty (#614)
pub type RefBatchFull<'a, T: ShaderParam> = (
    &'a RefBatch<T>,
    &'a T,
    &'a Context<T::Resources>
);

impl<R: Resources> Context<R> {
    /// Create a new empty `Context`
    pub fn new() -> Context<R> {
        Context {
            meshes: Array::new(),
            programs: Array::new(),
            states: Array::new(),
        }
    }
}

impl<R: Resources> Context<R> {
    /// Produce a new ref batch
    pub fn make_batch<T: ShaderParam<Resources = R>>(&mut self,
                      program: &ProgramHandle<R>,
                      mesh: &mesh::Mesh<R>,
                      slice: mesh::Slice<R>,
                      state: &DrawState)
                      -> Result<RefBatch<T>, Error> {
        let mesh_link = match mesh::Link::new(mesh, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let link = match ShaderParam::create_link(None::<&T>, &program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e))
        };
        let mesh_id = match self.meshes.find_or_insert(mesh) {
            Some(id) => id,
            None => return Err(Error::ContextFull),
        };
        let program_id = match self.programs.find_or_insert(program) {
            Some(id) => id,
            None => return Err(Error::ContextFull),
        };
        let state_id = match self.states.find_or_insert(state) {
            Some(id) => id,
            None => return Err(Error::ContextFull),
        };

        Ok(RefBatch {
            mesh_id: mesh_id,
            mesh_link: mesh_link,
            slice: slice,
            program_id: program_id,
            param_link: link,
            state_id: state_id,
        })
    }

    /// Complete a RefBatch temporarily by turning it into RefBatchFull
    pub fn bind<'a, T: ShaderParam<Resources = R> + 'a>(&'a self,
                 batch: &'a RefBatch<T>, data: &'a T) -> RefBatchFull<'a, T> {
        (batch, data, self)
    }
}

impl<'a, T: ShaderParam + 'a> Batch for RefBatchFull<'a, T> {
    type Resources = T::Resources;
    type Error = OutOfBounds;

    fn get_data(&self) -> Result<BatchData<T::Resources>, OutOfBounds> {
        let (b, _, ctx) = *self;
        Ok((try!(ctx.meshes.get(b.mesh_id)),
            b.mesh_link.to_iter(),
            &b.slice,
            try!(ctx.states.get(b.state_id))
        ))
    }

    fn fill_params(&self, values: ::shade::ParamValues<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, OutOfBounds> {
        let (b, data, ctx) = *self;
        data.fill_params(&b.param_link, values);
        ctx.programs.get(b.program_id)
    }
}
<|endoftext|>


<commit_before>//! # Simple 4-function calculator
//!
//! This demonstrates usage of Peresil, and also shows how you can
//! write a recursive-descent parser that handles left-associative
//! operators.
//!
//! For an extra wrinkle, input numbers must be integers in the range
//! [0, 31]. This allows an opportunity to show how errors outside the
//! grammar can be generated at parsing time.
//!
//! ## Grammar
//!
//! Expr := Add
//! Add  := Add '+' Mul
//!      := Add '-' Mul
//!      := Mul
//! Mul  := Mul '*' Num
//!      := Mul '/' Num
//!      := Num
//! Num  := [0-9]+

#[macro_use]
extern crate peresil;

use peresil::{ParseMaster, Recoverable, StringPoint};

// It's recommended to make type aliases to clean up signatures
type CalcMaster<'a> = ParseMaster<StringPoint<'a>, Error>;
type CalcProgress<'a, T> = peresil::Progress<StringPoint<'a>, T, Error>;

#[derive(Debug, Clone, PartialEq)]
enum Expression {
    Add(Box<Expression>, Box<Expression>),
    Sub(Box<Expression>, Box<Expression>),
    Mul(Box<Expression>, Box<Expression>),
    Div(Box<Expression>, Box<Expression>),
    Num(u8),
}

impl Expression {
    fn evaluate(&self) -> i32 {
        use Expression::*;

        match *self {
            Add(ref l, ref r) => l.evaluate() + r.evaluate(),
            Sub(ref l, ref r) => l.evaluate() - r.evaluate(),
            Mul(ref l, ref r) => l.evaluate() * r.evaluate(),
            Div(ref l, ref r) => l.evaluate() / r.evaluate(),
            Num(v) => v as i32,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Error {
    ExpectedNumber,
    InvalidNumber(u8),
}

impl Recoverable for Error {
    fn recoverable(&self) -> bool {
        use Error::*;

        match *self {
            ExpectedNumber => true,
            InvalidNumber(..) => false,
        }
    }
}

/// Maps an operator to a function that builds the corresponding Expression
type LeftAssociativeRule<'a> = (&'static str, &'a Fn(Expression, Expression) -> Expression);

/// Iteratively parses left-associative operators, avoiding infinite
/// recursion. Provide a `child_parser` that corresponds to each side
/// of the operator, as well as a rule for each operator.
fn parse_left_associative_operator<'a, P>(
    pm: &mut CalcMaster<'a>,
    pt: StringPoint<'a>,
    child_parser: P,
    rules: &[LeftAssociativeRule],
) -> CalcProgress<'a, Expression>
where
    P: for<'b> Fn(&mut CalcMaster<'b>, StringPoint<'b>) -> CalcProgress<'b, Expression>,
{
    let (pt, mut a) = try_parse!(child_parser(pm, pt));
    let mut start = pt;

    loop {
        let mut matched = false;

        for &(ref operator, ref builder) in rules {
            let (pt, op) = start.consume_literal(operator).optional(start);
            if op.is_none() {
                continue;
            }

            let (pt, b) = try_parse!(child_parser(pm, pt));

            a = builder(a, b);
            start = pt;

            matched = true;
            break;
        }

        if !matched {
            break;
        }
    }

    peresil::Progress::success(pt, a)
}

/// Parse a sequence of one-or-more ASCII digits
fn parse_num<'a>(_: &mut CalcMaster<'a>, pt: StringPoint<'a>) -> CalcProgress<'a, Expression> {
    let original_pt = pt;

    // We can cheat and know that ASCII 0-9 only takes one byte each
    let digits = pt.s.chars().take_while(|&c| c >= '0' && c <= '9').count();
    let r = if digits == 0 {
        pt.consume_to(None)
    } else {
        pt.consume_to(Some(digits))
    };

    let (pt, v) = try_parse!(r.map_err(|_| Error::ExpectedNumber));

    let num = v.parse().unwrap();

    // Here's where we can raise our own parsing errors. Note that we
    // kept the point where the number started, in order to give an
    // accurate error position.
    if num > 31 {
        peresil::Progress::failure(original_pt, Error::InvalidNumber(num))
    } else {
        peresil::Progress::success(pt, Expression::Num(num))
    }
}

fn parse_muldiv<'a>(pm: &mut CalcMaster<'a>, pt: StringPoint<'a>) -> CalcProgress<'a, Expression> {
    parse_left_associative_operator(
        pm,
        pt,
        parse_num,
        &[
            ("*", &|a, b| Expression::Mul(Box::new(a), Box::new(b))),
            ("/", &|a, b| Expression::Div(Box::new(a), Box::new(b))),
        ],
    )
}

fn parse_addsub<'a>(pm: &mut CalcMaster<'a>, pt: StringPoint<'a>) -> CalcProgress<'a, Expression> {
    parse_left_associative_operator(
        pm,
        pt,
        parse_muldiv,
        &[
            ("+", &|a, b| Expression::Add(Box::new(a), Box::new(b))),
            ("-", &|a, b| Expression::Sub(Box::new(a), Box::new(b))),
        ],
    )
}

fn parse(s: &str) -> Result<Expression, (usize, Vec<Error>)> {
    let mut pm = ParseMaster::new();
    let pt = StringPoint::new(s);

    let result = parse_addsub(&mut pm, pt);
    match pm.finish(result) {
        peresil::Progress {
            status: peresil::Status::Success(v),
            ..
        } => Ok(v),
        peresil::Progress {
            status: peresil::Status::Failure(f),
            point,
        } => Err((point.offset, f)),
    }
}

fn n(n: u8) -> Box<Expression> {
    Box::new(Expression::Num(n))
}

#[test]
fn single_number() {
    use Expression::*;
    assert_eq!(parse("1"), Ok(Num(1)));
}

#[test]
fn add_two_numbers() {
    use Expression::*;
    assert_eq!(parse("1+2"), Ok(Add(n(1), n(2))));
}

#[test]
fn add_three_numbers() {
    use Expression::*;
    assert_eq!(parse("3+4+5"), Ok(Add(Box::new(Add(n(3), n(4))), n(5))));
}

#[test]
fn subtract_two_numbers() {
    use Expression::*;
    assert_eq!(parse("9-8"), Ok(Sub(n(9), n(8))));
}

#[test]
fn multiply_two_numbers() {
    use Expression::*;
    assert_eq!(parse("5*6"), Ok(Mul(n(5), n(6))));
}

#[test]
fn multiply_three_numbers() {
    use Expression::*;
    assert_eq!(parse("3*6*9"), Ok(Mul(Box::new(Mul(n(3), n(6))), n(9))));
}

#[test]
fn divide_two_numbers() {
    use Expression::*;
    assert_eq!(parse("9/3"), Ok(Div(n(9), n(3))));
}

#[test]
fn addition_adds() {
    assert_eq!(parse("1+2+3").unwrap().evaluate(), 6);
}

#[test]
fn subtraction_subtracts() {
    assert_eq!(parse("1-2-3").unwrap().evaluate(), -4);
}

#[test]
fn multiplication_multiplies() {
    assert_eq!(parse("2*3*4").unwrap().evaluate(), 24);
}

#[test]
fn division_divides() {
    assert_eq!(parse("9/3/3").unwrap().evaluate(), 1);
}

#[test]
fn all_operators_together() {
    assert_eq!(parse("3+2-2*9/3").unwrap().evaluate(), -1);
}

#[test]
fn failure_not_a_number() {
    assert_eq!(parse("cow"), Err((0, vec![Error::ExpectedNumber])));
}

#[test]
fn failure_invalid_number() {
    assert_eq!(parse("32"), Err((0, vec![Error::InvalidNumber(32)])));
}

#[test]
fn failure_invalid_number_in_other_position() {
    assert_eq!(parse("1+99"), Err((2, vec![Error::InvalidNumber(99)])));
}
<commit_msg>Use dyn keyword<commit_after>//! # Simple 4-function calculator
//!
//! This demonstrates usage of Peresil, and also shows how you can
//! write a recursive-descent parser that handles left-associative
//! operators.
//!
//! For an extra wrinkle, input numbers must be integers in the range
//! [0, 31]. This allows an opportunity to show how errors outside the
//! grammar can be generated at parsing time.
//!
//! ## Grammar
//!
//! Expr := Add
//! Add  := Add '+' Mul
//!      := Add '-' Mul
//!      := Mul
//! Mul  := Mul '*' Num
//!      := Mul '/' Num
//!      := Num
//! Num  := [0-9]+

#[macro_use]
extern crate peresil;

use peresil::{ParseMaster, Recoverable, StringPoint};

// It's recommended to make type aliases to clean up signatures
type CalcMaster<'a> = ParseMaster<StringPoint<'a>, Error>;
type CalcProgress<'a, T> = peresil::Progress<StringPoint<'a>, T, Error>;

#[derive(Debug, Clone, PartialEq)]
enum Expression {
    Add(Box<Expression>, Box<Expression>),
    Sub(Box<Expression>, Box<Expression>),
    Mul(Box<Expression>, Box<Expression>),
    Div(Box<Expression>, Box<Expression>),
    Num(u8),
}

impl Expression {
    fn evaluate(&self) -> i32 {
        use Expression::*;

        match *self {
            Add(ref l, ref r) => l.evaluate() + r.evaluate(),
            Sub(ref l, ref r) => l.evaluate() - r.evaluate(),
            Mul(ref l, ref r) => l.evaluate() * r.evaluate(),
            Div(ref l, ref r) => l.evaluate() / r.evaluate(),
            Num(v) => v as i32,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Error {
    ExpectedNumber,
    InvalidNumber(u8),
}

impl Recoverable for Error {
    fn recoverable(&self) -> bool {
        use Error::*;

        match *self {
            ExpectedNumber => true,
            InvalidNumber(..) => false,
        }
    }
}

/// Maps an operator to a function that builds the corresponding Expression
type LeftAssociativeRule<'a> = (
    &'static str,
    &'a dyn Fn(Expression, Expression) -> Expression,
);

/// Iteratively parses left-associative operators, avoiding infinite
/// recursion. Provide a `child_parser` that corresponds to each side
/// of the operator, as well as a rule for each operator.
fn parse_left_associative_operator<'a, P>(
    pm: &mut CalcMaster<'a>,
    pt: StringPoint<'a>,
    child_parser: P,
    rules: &[LeftAssociativeRule],
) -> CalcProgress<'a, Expression>
where
    P: for<'b> Fn(&mut CalcMaster<'b>, StringPoint<'b>) -> CalcProgress<'b, Expression>,
{
    let (pt, mut a) = try_parse!(child_parser(pm, pt));
    let mut start = pt;

    loop {
        let mut matched = false;

        for &(ref operator, ref builder) in rules {
            let (pt, op) = start.consume_literal(operator).optional(start);
            if op.is_none() {
                continue;
            }

            let (pt, b) = try_parse!(child_parser(pm, pt));

            a = builder(a, b);
            start = pt;

            matched = true;
            break;
        }

        if !matched {
            break;
        }
    }

    peresil::Progress::success(pt, a)
}

/// Parse a sequence of one-or-more ASCII digits
fn parse_num<'a>(_: &mut CalcMaster<'a>, pt: StringPoint<'a>) -> CalcProgress<'a, Expression> {
    let original_pt = pt;

    // We can cheat and know that ASCII 0-9 only takes one byte each
    let digits = pt.s.chars().take_while(|&c| c >= '0' && c <= '9').count();
    let r = if digits == 0 {
        pt.consume_to(None)
    } else {
        pt.consume_to(Some(digits))
    };

    let (pt, v) = try_parse!(r.map_err(|_| Error::ExpectedNumber));

    let num = v.parse().unwrap();

    // Here's where we can raise our own parsing errors. Note that we
    // kept the point where the number started, in order to give an
    // accurate error position.
    if num > 31 {
        peresil::Progress::failure(original_pt, Error::InvalidNumber(num))
    } else {
        peresil::Progress::success(pt, Expression::Num(num))
    }
}

fn parse_muldiv<'a>(pm: &mut CalcMaster<'a>, pt: StringPoint<'a>) -> CalcProgress<'a, Expression> {
    parse_left_associative_operator(
        pm,
        pt,
        parse_num,
        &[
            ("*", &|a, b| Expression::Mul(Box::new(a), Box::new(b))),
            ("/", &|a, b| Expression::Div(Box::new(a), Box::new(b))),
        ],
    )
}

fn parse_addsub<'a>(pm: &mut CalcMaster<'a>, pt: StringPoint<'a>) -> CalcProgress<'a, Expression> {
    parse_left_associative_operator(
        pm,
        pt,
        parse_muldiv,
        &[
            ("+", &|a, b| Expression::Add(Box::new(a), Box::new(b))),
            ("-", &|a, b| Expression::Sub(Box::new(a), Box::new(b))),
        ],
    )
}

fn parse(s: &str) -> Result<Expression, (usize, Vec<Error>)> {
    let mut pm = ParseMaster::new();
    let pt = StringPoint::new(s);

    let result = parse_addsub(&mut pm, pt);
    match pm.finish(result) {
        peresil::Progress {
            status: peresil::Status::Success(v),
            ..
        } => Ok(v),
        peresil::Progress {
            status: peresil::Status::Failure(f),
            point,
        } => Err((point.offset, f)),
    }
}

fn n(n: u8) -> Box<Expression> {
    Box::new(Expression::Num(n))
}

#[test]
fn single_number() {
    use Expression::*;
    assert_eq!(parse("1"), Ok(Num(1)));
}

#[test]
fn add_two_numbers() {
    use Expression::*;
    assert_eq!(parse("1+2"), Ok(Add(n(1), n(2))));
}

#[test]
fn add_three_numbers() {
    use Expression::*;
    assert_eq!(parse("3+4+5"), Ok(Add(Box::new(Add(n(3), n(4))), n(5))));
}

#[test]
fn subtract_two_numbers() {
    use Expression::*;
    assert_eq!(parse("9-8"), Ok(Sub(n(9), n(8))));
}

#[test]
fn multiply_two_numbers() {
    use Expression::*;
    assert_eq!(parse("5*6"), Ok(Mul(n(5), n(6))));
}

#[test]
fn multiply_three_numbers() {
    use Expression::*;
    assert_eq!(parse("3*6*9"), Ok(Mul(Box::new(Mul(n(3), n(6))), n(9))));
}

#[test]
fn divide_two_numbers() {
    use Expression::*;
    assert_eq!(parse("9/3"), Ok(Div(n(9), n(3))));
}

#[test]
fn addition_adds() {
    assert_eq!(parse("1+2+3").unwrap().evaluate(), 6);
}

#[test]
fn subtraction_subtracts() {
    assert_eq!(parse("1-2-3").unwrap().evaluate(), -4);
}

#[test]
fn multiplication_multiplies() {
    assert_eq!(parse("2*3*4").unwrap().evaluate(), 24);
}

#[test]
fn division_divides() {
    assert_eq!(parse("9/3/3").unwrap().evaluate(), 1);
}

#[test]
fn all_operators_together() {
    assert_eq!(parse("3+2-2*9/3").unwrap().evaluate(), -1);
}

#[test]
fn failure_not_a_number() {
    assert_eq!(parse("cow"), Err((0, vec![Error::ExpectedNumber])));
}

#[test]
fn failure_invalid_number() {
    assert_eq!(parse("32"), Err((0, vec![Error::InvalidNumber(32)])));
}

#[test]
fn failure_invalid_number_in_other_position() {
    assert_eq!(parse("1+99"), Err((2, vec![Error::InvalidNumber(99)])));
}
<|endoftext|>