<commit_before>// Copyright 2014 Rich Lane.

// 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.

extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::hashmap::HashMap;
use std;

use gl::types::*;

use cgmath::vector::Vector;
use cgmath::vector::Vec3;

use noise::Perlin;

use CHUNK_SIZE;
use VISIBLE_RADIUS;
use GraphicsResources;

static MAX_CHUNKS : uint = (VISIBLE_RADIUS*2)*(VISIBLE_RADIUS*2)*2;

#[repr(u8)]
#[deriving(Eq)]
pub enum BlockType {
    BlockAir = 0,
    BlockGrass = 1,
    BlockStone = 2,
}

pub struct ChunkLoader {
    seed : u32,
    cache : HashMap<(i64, i64, uint), ~Chunk>
}

impl ChunkLoader {
    pub fn new(seed : u32) -> ChunkLoader {
        ChunkLoader {
            seed: seed,
            cache: HashMap::new(),
        }
    }

    pub fn load(&mut self, cx : i64, cz: i64, lod: uint) {
        println!("loading chunk ({}, {}) lod={}", cx, cz, lod);
        let chunk = chunk_gen(self.seed, cx, cz, lod);
        self.cache.insert((cx, cz, lod), chunk);

        while self.cache.len() > MAX_CHUNKS {
            let (&k, _) = self.cache.iter().min_by(|&(_, chunk)| chunk.used_time).unwrap();
            self.cache.remove(&k);
        }
    }
}

pub struct Chunk {
    x: i64,
    z: i64,
    map: ~Map,
    vertex_buffer: GLuint,
    normal_buffer: GLuint,
    blocktype_buffer: GLuint,
    element_buffer: GLuint,
    num_elements: uint,
    used_time: u64,
}

impl Chunk {
    pub fn touch(&mut self) {
        self.used_time = extra::time::precise_time_ns();
    }

    pub fn bind_arrays(&self, res: &GraphicsResources) {
        unsafe {
            let vert_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
            assert!(vert_attr as u32 != gl::INVALID_VALUE);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);
            gl::EnableVertexAttribArray(vert_attr as GLuint);
            gl::VertexAttribPointer(vert_attr as GLuint, 3, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());

            let normal_attr = "normal".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
            assert!(normal_attr as u32 != gl::INVALID_VALUE);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.normal_buffer);
            gl::EnableVertexAttribArray(normal_attr as GLuint);
            gl::VertexAttribPointer(normal_attr as GLuint, 3, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());

            let blocktype_attr = "blocktype".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
            assert!(blocktype_attr as u32 != gl::INVALID_VALUE);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.blocktype_buffer);
            gl::EnableVertexAttribArray(blocktype_attr as GLuint);
            gl::VertexAttribPointer(blocktype_attr as GLuint, 1, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.element_buffer);
        }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        unsafe {
            println!("unloading chunk ({}, {})", self.x, self.z);
            gl::DeleteBuffers(1, &self.vertex_buffer);
            gl::DeleteBuffers(1, &self.normal_buffer);
            gl::DeleteBuffers(1, &self.blocktype_buffer);
            gl::DeleteBuffers(1, &self.element_buffer);
        }
    }
}

struct Block {
    blocktype: BlockType,
}

struct Map {
    blocks: [[[Block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
}

struct Face {
    normal: Vec3<f32>,
    vertices: [Vec3<f32>, ..4],
}

pub fn chunk_gen(seed: u32, chunk_x: i64, chunk_z: i64, lod: uint) -> ~Chunk {
    let step = std::num::min(16u, 1 << lod);
    let def_block = Block { blocktype: BlockAir };
    let mut map = ~Map {
        blocks: [[[def_block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
    };

    let block_exists = |x: int, y: int, z: int| -> bool {
        if y < 0 {
            return true;
        }

        if x < 0 || x >= CHUNK_SIZE as int || y >= CHUNK_SIZE as int || z < 0 || z >= CHUNK_SIZE as int {
            return false;
        }

        map.blocks[x][y][z].blocktype != BlockAir
    };

    let start_time = extra::time::precise_time_ns();

    let perlin = Perlin::from_seed([seed as uint]);

    for block_x in std::iter::range_step(0, CHUNK_SIZE, step) {
        for block_z in std::iter::range_step(0, CHUNK_SIZE, step) {
            let noise = perlin.gen([
                (chunk_x + block_x as i64) as f64 * 0.07,
                (chunk_z + block_z as i64) as f64 * 0.04
            ]);
            let height = std::num::max(((noise + 1.0) * (CHUNK_SIZE as f64 / 4.0)), 1.0) as uint;
            for y in range(0, height) {
                if y > 20 { /* HACK */
                    map.blocks[block_x][y][block_z] = Block { blocktype: BlockStone };
                } else {
                    map.blocks[block_x][y][block_z] = Block { blocktype: BlockGrass };
                }
            }
        }
    }

    let after_noise_time = extra::time::precise_time_ns();

    let mut vertices : ~[Vec3<f32>] = ~[];
    let mut normals : ~[Vec3<f32>] = ~[];
    let mut blocktypes : ~[f32] = ~[];
    let mut elements : ~[GLuint] = ~[];

    static expected_vertices : uint = 70000;
    static expected_elements : uint = expected_vertices * 3 / 2;
    vertices.reserve(expected_vertices);
    normals.reserve(expected_vertices);
    blocktypes.reserve(expected_vertices);
    elements.reserve(expected_elements);

    let mut idx = 0;

    for x in std::iter::range_step(0, CHUNK_SIZE, step) {
        for y in std::iter::range_step(0, CHUNK_SIZE, step) {
            for z in std::iter::range_step(0, CHUNK_SIZE, step) {
                let block = &map.blocks[x][y][z];

                if (block.blocktype == BlockAir) {
                    continue;
                }

                let chunk_position = Vec3 {
                    x: chunk_x as f32,
                    y: 0.0f32,
                    z: chunk_z as f32,
                };

                let block_position = Vec3 {
                    x: x as f32,
                    y: y as f32,
                    z: z as f32,
                };

                for face in faces.iter() {
                    let neighbor_position = block_position.add_v(&face.normal.mul_s(step as f32));
                    if block_exists(neighbor_position.x as int, neighbor_position.y as int, neighbor_position.z as int) {
                        continue;
                    }

                    for v in face.vertices.iter() {
                        vertices.push(v.mul_s(step as f32).add_v(&block_position).add_v(&chunk_position));
                        normals.push(face.normal);
                        blocktypes.push(block.blocktype as f32);
                    }

                    for e in face_elements.iter() {
                        elements.push((idx * face.vertices.len()) as GLuint + *e);
                    }

                    idx += 1;
                }
            }
        }
    }

    let after_mesh_time = extra::time::precise_time_ns();

    let mut vertex_buffer = 0;
    let mut normal_buffer = 0;
    let mut blocktype_buffer = 0;
    let mut element_buffer = 0;

    unsafe {
        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vertex_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (vertices.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&vertices[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the normal data to it
        gl::GenBuffers(1, &mut normal_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (normals.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&normals[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the blocktype data to it
        gl::GenBuffers(1, &mut blocktype_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, blocktype_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (blocktypes.len() * std::mem::size_of::<f32>()) as GLsizeiptr,
                        cast::transmute(&blocktypes[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the element data to it
        gl::GenBuffers(1, &mut element_buffer);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, element_buffer);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                        (elements.len() * std::mem::size_of::<GLuint>()) as GLsizeiptr,
                        cast::transmute(&elements[0]),
                        gl::STATIC_DRAW);
    }

    let after_buffer_time = extra::time::precise_time_ns();

    println!("chunk load: noise={}us mesh={}us buffer={}us num_vertices={} num_elements={}",
             (after_noise_time - start_time)/1000,
             (after_mesh_time - after_noise_time)/1000,
             (after_buffer_time - after_mesh_time)/1000,
             vertices.len(), elements.len())

    return ~Chunk {
        x: chunk_x,
        z: chunk_z,
        map: map,
        vertex_buffer: vertex_buffer,
        normal_buffer: normal_buffer,
        blocktype_buffer: blocktype_buffer,
        element_buffer: element_buffer,
        num_elements: elements.len(),
        used_time: extra::time::precise_time_ns(),
    };
}

static face_elements : [GLuint, ..6] = [
    0, 1, 2, 3, 2, 1,
];

static faces : [Face, ..6] = [
    /* front */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 },  /* bottom right */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 },  /* top right */
        ],
    },

    /* back */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom right */
            Vec3 { x: 0.0, y: 0.0, z: 0.0 },  /* bottom left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 },  /* top left */
        ],
    },

    /* right */
    Face {
        normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* top front */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top back */
        ],
    },

    /* left */
    Face {
        normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* top back */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top front */
        ],
    },

    /* top */
    Face {
        normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* front right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* back right */
        ],
    },

    /* bottom */
    Face {
        normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* back right */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* front right */
        ],
    },
];
<commit_msg>generate stone mountaintops<commit_after>// Copyright 2014 Rich Lane.

// 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.

extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::hashmap::HashMap;
use std;

use gl::types::*;

use cgmath::vector::Vector;
use cgmath::vector::Vec3;

use noise::Perlin;

use CHUNK_SIZE;
use VISIBLE_RADIUS;
use GraphicsResources;

static MAX_CHUNKS : uint = (VISIBLE_RADIUS*2)*(VISIBLE_RADIUS*2)*2;

#[repr(u8)]
#[deriving(Eq)]
pub enum BlockType {
    BlockAir = 0,
    BlockGrass = 1,
    BlockStone = 2,
}

pub struct ChunkLoader {
    seed : u32,
    cache : HashMap<(i64, i64, uint), ~Chunk>
}

impl ChunkLoader {
    pub fn new(seed : u32) -> ChunkLoader {
        ChunkLoader {
            seed: seed,
            cache: HashMap::new(),
        }
    }

    pub fn load(&mut self, cx : i64, cz: i64, lod: uint) {
        println!("loading chunk ({}, {}) lod={}", cx, cz, lod);
        let chunk = chunk_gen(self.seed, cx, cz, lod);
        self.cache.insert((cx, cz, lod), chunk);

        while self.cache.len() > MAX_CHUNKS {
            let (&k, _) = self.cache.iter().min_by(|&(_, chunk)| chunk.used_time).unwrap();
            self.cache.remove(&k);
        }
    }
}

pub struct Chunk {
    x: i64,
    z: i64,
    map: ~Map,
    vertex_buffer: GLuint,
    normal_buffer: GLuint,
    blocktype_buffer: GLuint,
    element_buffer: GLuint,
    num_elements: uint,
    used_time: u64,
}

impl Chunk {
    pub fn touch(&mut self) {
        self.used_time = extra::time::precise_time_ns();
    }

    pub fn bind_arrays(&self, res: &GraphicsResources) {
        unsafe {
            let vert_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
            assert!(vert_attr as u32 != gl::INVALID_VALUE);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);
            gl::EnableVertexAttribArray(vert_attr as GLuint);
            gl::VertexAttribPointer(vert_attr as GLuint, 3, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());

            let normal_attr = "normal".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
            assert!(normal_attr as u32 != gl::INVALID_VALUE);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.normal_buffer);
            gl::EnableVertexAttribArray(normal_attr as GLuint);
            gl::VertexAttribPointer(normal_attr as GLuint, 3, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());

            let blocktype_attr = "blocktype".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
            assert!(blocktype_attr as u32 != gl::INVALID_VALUE);
            gl::BindBuffer(gl::ARRAY_BUFFER, self.blocktype_buffer);
            gl::EnableVertexAttribArray(blocktype_attr as GLuint);
            gl::VertexAttribPointer(blocktype_attr as GLuint, 1, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.element_buffer);
        }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        unsafe {
            println!("unloading chunk ({}, {})", self.x, self.z);
            gl::DeleteBuffers(1, &self.vertex_buffer);
            gl::DeleteBuffers(1, &self.normal_buffer);
            gl::DeleteBuffers(1, &self.blocktype_buffer);
            gl::DeleteBuffers(1, &self.element_buffer);
        }
    }
}

struct Block {
    blocktype: BlockType,
}

struct Map {
    blocks: [[[Block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
}

struct Face {
    normal: Vec3<f32>,
    vertices: [Vec3<f32>, ..4],
}

pub fn chunk_gen(seed: u32, chunk_x: i64, chunk_z: i64, lod: uint) -> ~Chunk {
    let step = std::num::min(16u, 1 << lod);
    let def_block = Block { blocktype: BlockAir };
    let mut map = ~Map {
        blocks: [[[def_block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
    };

    let block_exists = |x: int, y: int, z: int| -> bool {
        if y < 0 {
            return true;
        }

        if x < 0 || x >= CHUNK_SIZE as int || y >= CHUNK_SIZE as int || z < 0 || z >= CHUNK_SIZE as int {
            return false;
        }

        map.blocks[x][y][z].blocktype != BlockAir
    };

    let start_time = extra::time::precise_time_ns();

    let perlin = Perlin::from_seed([seed as uint]);
    let perlin2 = Perlin::from_seed([seed as uint * 7]);

    for block_x in std::iter::range_step(0, CHUNK_SIZE, step) {
        for block_z in std::iter::range_step(0, CHUNK_SIZE, step) {
            let noise = perlin.gen([
                (chunk_x + block_x as i64) as f64 * 0.07,
                (chunk_z + block_z as i64) as f64 * 0.04
            ]);
            let noise2 = perlin2.gen([
                (chunk_x + block_x as i64) as f64 * 0.05,
                (chunk_z + block_z as i64) as f64 * 0.05
            ]);
            let height = std::num::max(((noise + 1.0) * (CHUNK_SIZE as f64 / 4.0)), 1.0) as uint;
            for y in range(0, height) {
                if (1.0 + noise2) * y as f64 > 20.0 {
                    map.blocks[block_x][y][block_z] = Block { blocktype: BlockStone };
                } else {
                    map.blocks[block_x][y][block_z] = Block { blocktype: BlockGrass };
                }
            }
        }
    }

    let after_noise_time = extra::time::precise_time_ns();

    let mut vertices : ~[Vec3<f32>] = ~[];
    let mut normals : ~[Vec3<f32>] = ~[];
    let mut blocktypes : ~[f32] = ~[];
    let mut elements : ~[GLuint] = ~[];

    static expected_vertices : uint = 70000;
    static expected_elements : uint = expected_vertices * 3 / 2;
    vertices.reserve(expected_vertices);
    normals.reserve(expected_vertices);
    blocktypes.reserve(expected_vertices);
    elements.reserve(expected_elements);

    let mut idx = 0;

    for x in std::iter::range_step(0, CHUNK_SIZE, step) {
        for y in std::iter::range_step(0, CHUNK_SIZE, step) {
            for z in std::iter::range_step(0, CHUNK_SIZE, step) {
                let block = &map.blocks[x][y][z];

                if (block.blocktype == BlockAir) {
                    continue;
                }

                let chunk_position = Vec3 {
                    x: chunk_x as f32,
                    y: 0.0f32,
                    z: chunk_z as f32,
                };

                let block_position = Vec3 {
                    x: x as f32,
                    y: y as f32,
                    z: z as f32,
                };

                for face in faces.iter() {
                    let neighbor_position = block_position.add_v(&face.normal.mul_s(step as f32));
                    if block_exists(neighbor_position.x as int, neighbor_position.y as int, neighbor_position.z as int) {
                        continue;
                    }

                    for v in face.vertices.iter() {
                        vertices.push(v.mul_s(step as f32).add_v(&block_position).add_v(&chunk_position));
                        normals.push(face.normal);
                        blocktypes.push(block.blocktype as f32);
                    }

                    for e in face_elements.iter() {
                        elements.push((idx * face.vertices.len()) as GLuint + *e);
                    }

                    idx += 1;
                }
            }
        }
    }

    let after_mesh_time = extra::time::precise_time_ns();

    let mut vertex_buffer = 0;
    let mut normal_buffer = 0;
    let mut blocktype_buffer = 0;
    let mut element_buffer = 0;

    unsafe {
        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vertex_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (vertices.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&vertices[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the normal data to it
        gl::GenBuffers(1, &mut normal_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (normals.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&normals[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the blocktype data to it
        gl::GenBuffers(1, &mut blocktype_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, blocktype_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (blocktypes.len() * std::mem::size_of::<f32>()) as GLsizeiptr,
                        cast::transmute(&blocktypes[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the element data to it
        gl::GenBuffers(1, &mut element_buffer);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, element_buffer);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                        (elements.len() * std::mem::size_of::<GLuint>()) as GLsizeiptr,
                        cast::transmute(&elements[0]),
                        gl::STATIC_DRAW);
    }

    let after_buffer_time = extra::time::precise_time_ns();

    println!("chunk load: noise={}us mesh={}us buffer={}us num_vertices={} num_elements={}",
             (after_noise_time - start_time)/1000,
             (after_mesh_time - after_noise_time)/1000,
             (after_buffer_time - after_mesh_time)/1000,
             vertices.len(), elements.len())

    return ~Chunk {
        x: chunk_x,
        z: chunk_z,
        map: map,
        vertex_buffer: vertex_buffer,
        normal_buffer: normal_buffer,
        blocktype_buffer: blocktype_buffer,
        element_buffer: element_buffer,
        num_elements: elements.len(),
        used_time: extra::time::precise_time_ns(),
    };
}

static face_elements : [GLuint, ..6] = [
    0, 1, 2, 3, 2, 1,
];

static faces : [Face, ..6] = [
    /* front */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 },  /* bottom right */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 },  /* top right */
        ],
    },

    /* back */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom right */
            Vec3 { x: 0.0, y: 0.0, z: 0.0 },  /* bottom left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 },  /* top left */
        ],
    },

    /* right */
    Face {
        normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* top front */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top back */
        ],
    },

    /* left */
    Face {
        normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* top back */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top front */
        ],
    },

    /* top */
    Face {
        normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* front right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* back right */
        ],
    },

    /* bottom */
    Face {
        normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* back right */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* front right */
        ],
    },
];
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::str::Words;
use std::io::{BufferedReader, File};
use cgmath::vector::{Vec3, Vec2};
use core::types::{MBool, MInt};
use visualizer::types::{VertexCoord, TextureCoord, Normal};

struct Face {
    vertex: [MInt, ..3],
    texture: [MInt, ..3],
    normal: [MInt, ..3],
}

pub struct Model {
    coords: ~[VertexCoord],
    normals: ~[Normal],
    texture_coords: ~[TextureCoord],
    faces: ~[Face],
}

// TODO: unwrap() -> ...
impl Model {
    pub fn new(filename: &str) -> Model {
        let mut obj = Model {
            coords: ~[],
            normals: ~[],
            texture_coords: ~[],
            faces: ~[],
        };
        obj.read(filename);
        obj
    }

    fn read_v_or_vn(words: &mut Words) -> VertexCoord {
        Vec3 {
            x: from_str(words.next().unwrap()).unwrap(),
            y: from_str(words.next().unwrap()).unwrap(),
            z: from_str(words.next().unwrap()).unwrap(),
        }
    }

    fn read_vt(words: &mut Words) -> TextureCoord {
        Vec2 {
            x: from_str(words.next().unwrap()).unwrap(),
            y: 1.0 - from_str(words.next().unwrap()).unwrap(), // flip
        }
    }

    fn read_f(words: &mut Words) -> Face {
        let mut face = Face {
            vertex: [0, 0, 0],
            texture: [0, 0, 0],
            normal: [0, 0, 0],
        };
        let mut i = 0;
        for group in *words {
            let mut w = group.split('/');
            face.vertex[i] = from_str(w.next().unwrap()).unwrap();
            face.texture[i] = from_str(w.next().unwrap()).unwrap();
            face.normal[i] = from_str(w.next().unwrap()).unwrap();
            i += 1;
        }
        face
    }

    fn read_line(&mut self, line: &str) {
        let mut words = line.words();
        fn is_correct_tag(tag: &str) -> MBool {
            tag.len() != 0 && tag[0] != ('#' as u8)
        }
        match words.next() {
            Some(tag) if is_correct_tag(tag) => {
                let w = &mut words;
                match tag {
                    &"v" => self.coords.push(Model::read_v_or_vn(w)),
                    &"vn" => self.normals.push(Model::read_v_or_vn(w)),
                    &"vt" => self.texture_coords.push(Model::read_vt(w)),
                    &"f" => self.faces.push(Model::read_f(w)),
                    _ => {},
                }
            }
            _ => {},
        };
    }

    fn read(&mut self, filename: &str) {
        let path = Path::new(filename);
        let mut file = BufferedReader::new(File::open(&path));
        for line in file.lines() {
            self.read_line(line);
        }
    }

    pub fn build(&self) -> ~[VertexCoord] {
        let mut mesh = ~[];
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let vertex_id = face.vertex[i] - 1;
                mesh.push(self.coords[vertex_id]);
            }
        }
        mesh
    }

    pub fn build_tex_coord(&self) -> ~[TextureCoord] {
        let mut tex_coords = ~[];
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let texture_coord_id = face.texture[i] - 1;
                tex_coords.push(self.texture_coords[texture_coord_id]);
            }
        }
        tex_coords
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Updated to latest Rust: ioResults<commit_after>// See LICENSE file for copyright and license details.

use std::str::Words;
use std::io::{BufferedReader, File};
use cgmath::vector::{Vec3, Vec2};
use core::types::{MBool, MInt};
use visualizer::types::{VertexCoord, TextureCoord, Normal};

struct Face {
    vertex: [MInt, ..3],
    texture: [MInt, ..3],
    normal: [MInt, ..3],
}

pub struct Model {
    coords: ~[VertexCoord],
    normals: ~[Normal],
    texture_coords: ~[TextureCoord],
    faces: ~[Face],
}

// TODO: unwrap() -> ...
impl Model {
    pub fn new(filename: &str) -> Model {
        let mut obj = Model {
            coords: ~[],
            normals: ~[],
            texture_coords: ~[],
            faces: ~[],
        };
        obj.read(filename);
        obj
    }

    fn read_v_or_vn(words: &mut Words) -> VertexCoord {
        Vec3 {
            x: from_str(words.next().unwrap()).unwrap(),
            y: from_str(words.next().unwrap()).unwrap(),
            z: from_str(words.next().unwrap()).unwrap(),
        }
    }

    fn read_vt(words: &mut Words) -> TextureCoord {
        Vec2 {
            x: from_str(words.next().unwrap()).unwrap(),
            y: 1.0 - from_str(words.next().unwrap()).unwrap(), // flip
        }
    }

    fn read_f(words: &mut Words) -> Face {
        let mut face = Face {
            vertex: [0, 0, 0],
            texture: [0, 0, 0],
            normal: [0, 0, 0],
        };
        let mut i = 0;
        for group in *words {
            let mut w = group.split('/');
            face.vertex[i] = from_str(w.next().unwrap()).unwrap();
            face.texture[i] = from_str(w.next().unwrap()).unwrap();
            face.normal[i] = from_str(w.next().unwrap()).unwrap();
            i += 1;
        }
        face
    }

    fn read_line(&mut self, line: &str) {
        let mut words = line.words();
        fn is_correct_tag(tag: &str) -> MBool {
            tag.len() != 0 && tag[0] != ('#' as u8)
        }
        match words.next() {
            Some(tag) if is_correct_tag(tag) => {
                let w = &mut words;
                match tag {
                    &"v" => self.coords.push(Model::read_v_or_vn(w)),
                    &"vn" => self.normals.push(Model::read_v_or_vn(w)),
                    &"vt" => self.texture_coords.push(Model::read_vt(w)),
                    &"f" => self.faces.push(Model::read_f(w)),
                    _ => {},
                }
            }
            _ => {},
        };
    }

    fn read(&mut self, filename: &str) {
        let path = Path::new(filename);
        let mut file = BufferedReader::new(File::open(&path));
        for line in file.lines() {
            self.read_line(line.unwrap());
        }
    }

    pub fn build(&self) -> ~[VertexCoord] {
        let mut mesh = ~[];
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let vertex_id = face.vertex[i] - 1;
                mesh.push(self.coords[vertex_id]);
            }
        }
        mesh
    }

    pub fn build_tex_coord(&self) -> ~[TextureCoord] {
        let mut tex_coords = ~[];
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let texture_coord_id = face.texture[i] - 1;
                tex_coords.push(self.texture_coords[texture_coord_id]);
            }
        }
        tex_coords
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>
#[doc(hidden)]
#[macro_export]
macro_rules! primitive_cast {
    (0, $name: expr) => { $name as fn () -> _ };
    (1, $name: expr) => { $name as fn (_) -> _ };
    (2, $name: expr) => { $name as fn (_, _) -> _ };
    (3, $name: expr) => { $name as fn (_, _, _) -> _ };
    (4, $name: expr) => { $name as fn (_, _, _, _) -> _ };
    (5, $name: expr) => { $name as fn (_, _, _, _, _) -> _ };
    (6, $name: expr) => { $name as fn (_, _, _, _, _, _) -> _ };
    (7, $name: expr) => { $name as fn (_, _, _, _, _, _, _) -> _ };
}

/// Creates a `GluonFunction` from a function implementing `VMFunction`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn test(_x: i32, _y: String) -> f64 {
///     panic!()
/// }
///
/// fn main() {
///     primitive!(2 test);
/// }
/// ```
#[macro_export]
macro_rules! primitive {
    (0 $name: expr) => { named_primitive!(0, stringify!($name), $name) };
    (1 $name: expr) => { named_primitive!(1, stringify!($name), $name) };
    (2 $name: expr) => { named_primitive!(2, stringify!($name), $name) };
    (3 $name: expr) => { named_primitive!(3, stringify!($name), $name) };
    (4 $name: expr) => { named_primitive!(4, stringify!($name), $name) };
    (5 $name: expr) => { named_primitive!(5, stringify!($name), $name) };
    (6 $name: expr) => { named_primitive!(6, stringify!($name), $name) };
    (7 $name: expr) => { named_primitive!(7, stringify!($name), $name) };
}

#[macro_export]
macro_rules! named_primitive {
    ($count: tt, $name: expr, $func: expr) => {
        unsafe {
            extern "C" fn wrapper(thread: &$crate::thread::Thread) -> $crate::thread::Status {
                 $crate::api::VmFunction::unpack_and_call(
                     &primitive_cast!($count, $func), thread)
            }
            $crate::api::primitive_f($name, wrapper, primitive_cast!($count, $func))
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! field_decl_inner {
    ($($field: ident),*) => {
        $(
        #[allow(non_camel_case_types)]
        #[derive(Default)]
        pub struct $field;
        impl $crate::api::record::Field for $field {
            fn name() -> &'static str {
                stringify!($field)
            }
        }
        )*
    }
}

/// Declares fields useable by the record macros
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
///
/// field_decl! {x, y}
/// ```
#[macro_export]
macro_rules! field_decl {
    ($($field: ident),*) => {
        mod _field { field_decl_inner!($($field),*); }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_no_decl_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: expr) => {
        $crate::frunk_core::hlist::h_cons((_field::$field, $value), record_no_decl_inner!())
    };
    ($field: ident => $value: expr, $($field_tail: ident => $value_tail: expr),*) => {
        $crate::frunk_core::hlist::h_cons((_field::$field, $value),
                                   record_no_decl_inner!($($field_tail => $value_tail),*))
    };
}

/// Macro that creates a record that can be passed to gluon. Reuses already declared fields
/// instead of generating unique ones.
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
///
/// field_decl! {x, y, name}
///
/// fn main() {
///     record_no_decl!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export]
macro_rules! record_no_decl {
    ($($field: ident => $value: expr),*) => {
        {
            $crate::api::Record {
                fields: record_no_decl_inner!($($field => $value),*)
            }
        }
    }
}

/// Macro that creates a record that can be passed to gluon
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     record!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export]
macro_rules! record {
    ($($field: ident => $value: expr),*) => {
        {
            field_decl!($($field),*);
            record_no_decl!($($field => $value),*)
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_type_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: ty) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value), record_type_inner!()>
    };
    ($field: ident => $value: ty, $($field_tail: ident => $value_tail: ty),*) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value),
                                record_type_inner!( $($field_tail => $value_tail),*)>
    }
}

/// Creates a Rust type compatible with the type of `record_no_decl!`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
/// // Fields used in `record_type!` needs to be forward declared
/// field_decl! {x, y}
/// fn new_vec(x: f64, y: f64) -> record_type!(x => f64, y => f64) {
///     record_no_decl!(x => y, y => y)
/// }
/// ```
#[macro_export]
macro_rules! record_type {
    ($($field: ident => $value: ty),*) => {
        $crate::api::Record<
            record_type_inner!($($field => $value),*)
            >
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_p_impl {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: pat) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field), tail: record_p_impl!() }
    };
    ($field: pat, $($field_tail: pat),*) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field),
                                           tail: record_p_impl!($($field_tail),*) }
    }
}

/// Creates a pattern which matches on marshalled gluon records
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     match record!(x => 1, y => "y") {
///         record_p!(a, "y") => assert_eq!(a, 1),
///         _ => assert!(false),
///     }
/// }
/// ```
#[macro_export]
macro_rules! record_p {
    ($($field: pat),*) => {
        $crate::api::Record {
            fields: record_p_impl!($($field),*)
        }
    }
}
<commit_msg>feat(vm): Let the record macros have non-rust identifiers for field names<commit_after>
#[doc(hidden)]
#[macro_export]
macro_rules! primitive_cast {
    (0, $name: expr) => { $name as fn () -> _ };
    (1, $name: expr) => { $name as fn (_) -> _ };
    (2, $name: expr) => { $name as fn (_, _) -> _ };
    (3, $name: expr) => { $name as fn (_, _, _) -> _ };
    (4, $name: expr) => { $name as fn (_, _, _, _) -> _ };
    (5, $name: expr) => { $name as fn (_, _, _, _, _) -> _ };
    (6, $name: expr) => { $name as fn (_, _, _, _, _, _) -> _ };
    (7, $name: expr) => { $name as fn (_, _, _, _, _, _, _) -> _ };
}

/// Creates a `GluonFunction` from a function implementing `VMFunction`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn test(_x: i32, _y: String) -> f64 {
///     panic!()
/// }
///
/// fn main() {
///     primitive!(2 test);
/// }
/// ```
#[macro_export]
macro_rules! primitive {
    (0 $name: expr) => { named_primitive!(0, stringify!($name), $name) };
    (1 $name: expr) => { named_primitive!(1, stringify!($name), $name) };
    (2 $name: expr) => { named_primitive!(2, stringify!($name), $name) };
    (3 $name: expr) => { named_primitive!(3, stringify!($name), $name) };
    (4 $name: expr) => { named_primitive!(4, stringify!($name), $name) };
    (5 $name: expr) => { named_primitive!(5, stringify!($name), $name) };
    (6 $name: expr) => { named_primitive!(6, stringify!($name), $name) };
    (7 $name: expr) => { named_primitive!(7, stringify!($name), $name) };
}

#[macro_export]
macro_rules! named_primitive {
    ($count: tt, $name: expr, $func: expr) => {
        unsafe {
            extern "C" fn wrapper(thread: &$crate::thread::Thread) -> $crate::thread::Status {
                 $crate::api::VmFunction::unpack_and_call(
                     &primitive_cast!($count, $func), thread)
            }
            $crate::api::primitive_f($name, wrapper, primitive_cast!($count, $func))
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! field_decl_inner {
    () => {
    };

    ($field: ident) => {
        field_decl_inner!{
            ($field stringify!($field))
        }
    };
    (($alias: ident $field: expr)) => {
        #[allow(non_camel_case_types)]
        #[derive(Default)]
        pub struct $alias;
        impl $crate::api::record::Field for $alias {
            fn name() -> &'static str {
                $field
            }
        }
    };

    ($field: ident, $($rest: tt)*) => {
        field_decl_inner!{
            ($field stringify!($field)),
            $($rest)*
        }
    };
    (($alias: ident $field: expr), $($rest: tt)*) => {
        field_decl_inner!{ ($alias $field) }
        field_decl_inner!{$($rest)*}
    }
}

/// Declares fields useable by the record macros
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
///
/// field_decl! {x, y}
/// ```
#[macro_export]
macro_rules! field_decl {
    ($($tt: tt)*) => {
        mod _field { field_decl_inner!($($tt)*); }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! field_decl_record {
    ([$($acc: tt)*]) => {
        field_decl!($($acc)*);
    };

    ([ $($acc: tt)* ] $field: ident => $ignore: expr) => {
        field_decl_record!{
            [$($acc)* ($field stringify!($field)),]
        }
    };
    ([ $($acc: tt)* ] ($alias: ident $field: expr) => $ignore: expr) => {
        field_decl_record!{
            [$($acc)* ($alias $field),]
        }
    };

    ([ $($acc: tt)* ] $field: ident => $ignore: expr, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* ($field stringify!($field)),]
            $($rest)*
        }
    };
    ([ $($acc: tt)* ] ($alias: ident $field: expr) => $ignore: expr, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* ($alias $field),]
            $($rest)*
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_no_decl_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: expr) => {
        $crate::frunk_core::hlist::h_cons((_field::$field, $value), record_no_decl_inner!())
    };
    ( ($field: ident $ignore: expr) => $value: expr) => {
        record_no_decl_inner!($field => $value)
    };
    ($field: ident => $value: expr, $($rest: tt)*) => {
        $crate::frunk_core::hlist::h_cons(
            (_field::$field, $value),
            record_no_decl_inner!($($rest)*)
        )
    };
    ( ($field: ident $ignore: expr) => $value: expr, $($rest: tt)*) => {
        record_no_decl_inner!($field => $value, $($rest)*)
    };
}

/// Macro that creates a record that can be passed to gluon. Reuses already declared fields
/// instead of generating unique ones.
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
///
/// field_decl! {x, y, name}
///
/// fn main() {
///     record_no_decl!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export]
macro_rules! record_no_decl {
    ($($tt: tt)*) => {
        {
            $crate::api::Record {
                fields: record_no_decl_inner!($($tt)*)
            }
        }
    }
}

/// Macro that creates a record that can be passed to gluon
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     record!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export]
macro_rules! record {
    ($($tt: tt)*) => {{
        field_decl_record!([] $($tt)*);
        record_no_decl!($($tt)*)
    }}
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_type_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: ty) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value), record_type_inner!()>
    };
    ($field: ident => $value: ty, $($field_tail: ident => $value_tail: ty),*) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value),
                                record_type_inner!( $($field_tail => $value_tail),*)>
    }
}

/// Creates a Rust type compatible with the type of `record_no_decl!`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
/// // Fields used in `record_type!` needs to be forward declared
/// field_decl! {x, y}
/// fn new_vec(x: f64, y: f64) -> record_type!(x => f64, y => f64) {
///     record_no_decl!(x => y, y => y)
/// }
/// ```
#[macro_export]
macro_rules! record_type {
    ($($field: ident => $value: ty),*) => {
        $crate::api::Record<
            record_type_inner!($($field => $value),*)
            >
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_p_impl {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: pat) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field), tail: record_p_impl!() }
    };
    ($field: pat, $($field_tail: pat),*) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field),
                                           tail: record_p_impl!($($field_tail),*) }
    }
}

/// Creates a pattern which matches on marshalled gluon records
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     match record!(x => 1, y => "y") {
///         record_p!(a, "y") => assert_eq!(a, 1),
///         _ => assert!(false),
///     }
/// }
/// ```
#[macro_export]
macro_rules! record_p {
    ($($field: pat),*) => {
        $crate::api::Record {
            fields: record_p_impl!($($field),*)
        }
    }
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]

#[cfg(feature = "bytes")]
extern crate bytes;

pub use unknown::UnknownFields;
pub use unknown::UnknownFieldsIter;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValues;
pub use unknown::UnknownValuesIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::MessageStatic;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
#[cfg(feature = "bytes")]
pub use core::parse_from_carllerche_bytes;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;
pub use cached_size::CachedSize;
#[cfg(feature = "bytes")]
pub use chars::Chars;

// generated
pub mod descriptor;
pub mod plugin;
mod rustproto;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod code_writer;
pub mod codegen;
pub mod compiler_plugin;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;
pub mod types;
pub mod well_known_types;
pub mod ext;

// used by test
pub mod hex;

// used by rust-grpc
pub mod descriptorx;

mod zigzag;
mod paginate;
mod unknown;
mod strx;
mod rust;
mod cached_size;
mod varint;
#[cfg(feature = "bytes")]
pub mod chars; // TODO: make private

mod misc;

mod buf_read_iter;

// so `use protobuf::*` could work in mod descriptor and well_known_types
mod protobuf {
    pub use descriptor;
    pub use descriptorx;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use text_format;
    pub use types;
    pub use lazy;
    pub use well_known_types;
    pub use ext;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownFieldsIter;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValuesIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
    pub use cached_size::CachedSize;
}
<commit_msg>Remove now unnecessary prehistoric instruction<commit_after>#[cfg(feature = "bytes")]
extern crate bytes;

pub use unknown::UnknownFields;
pub use unknown::UnknownFieldsIter;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValues;
pub use unknown::UnknownValuesIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::MessageStatic;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
#[cfg(feature = "bytes")]
pub use core::parse_from_carllerche_bytes;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;
pub use cached_size::CachedSize;
#[cfg(feature = "bytes")]
pub use chars::Chars;

// generated
pub mod descriptor;
pub mod plugin;
mod rustproto;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod code_writer;
pub mod codegen;
pub mod compiler_plugin;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;
pub mod types;
pub mod well_known_types;
pub mod ext;

// used by test
pub mod hex;

// used by rust-grpc
pub mod descriptorx;

mod zigzag;
mod paginate;
mod unknown;
mod strx;
mod rust;
mod cached_size;
mod varint;
#[cfg(feature = "bytes")]
pub mod chars; // TODO: make private

mod misc;

mod buf_read_iter;

// so `use protobuf::*` could work in mod descriptor and well_known_types
mod protobuf {
    pub use descriptor;
    pub use descriptorx;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use text_format;
    pub use types;
    pub use lazy;
    pub use well_known_types;
    pub use ext;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownFieldsIter;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValuesIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
    pub use cached_size::CachedSize;
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Intterupt handling on x86 machines.
//!
//! This module provides support for interrupt handling on both `x86` and
//! `x86_64` as a black box. Code that depends on this can use the same API
//! regardless of system word size.
use arch::cpu::dtable::DTable;

pub mod idt;
pub mod pics;
pub mod handlers;

use self::idt::Idt;

/// State stored when handling an interrupt.
#[repr(C, packed)]
// pub struct InterruptContext { /// callee-saved registers
//                               pub registers: Registers
//                             , /// interrupt ID number
//                               pub int_id: usize
//                             , _pad_1: u32
//                             , /// error number
//                               pub error_code:  u32
//                             , _pad_2: u32
//                             }

//impl InterruptContext {
//    /// Fetches the corresponding CPU exception for this interrupt, if this
//    /// interrupt is a CPU exception.
//    #[inline]
//
//}

#[derive(Debug)]
pub struct ExceptionInfo { pub name: &'static str
                         , pub mnemonic: &'static str
                         , pub irq_type: &'static str
                         , pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; 20]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction \
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an \
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection \
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

/// Macro for making Interrupt Service Routines
macro_rules! isr {
   (error: $handler:ident) => {{
       #[inline(never)] #[naked]
       unsafe extern "C" fn isr() -> ! {
            use $crate::arch::cpu::Registers;
            use $crate::arch::cpu::interrupts::handlers::ErrorCodeHandler;

            Registers::push();

            asm!( "mov rsi, [rsp + 9*8)]  // pop error code into rsi
                   mov rdi, rsp
                   add rdi, 10*8
                   sub rsp, 8   // align stack pointer

                   cli
                   call $0
                   sti

                   add rsp, 8   // un-align stack pointer"
                :: "s"($handler as ErrorCodeHandler)
                //  , "i"(size_of::<context::Registers>())
                : "rsi", "rdi"
                : "volatile", "intel");

            Registers::pop();

            asm!( "add rsp, 8     // remove error code from stack
                   iretq" :::: "volatile", "intel");
            unreachable!();
       }
       isr
   }};
   (interrupt: $handler:ident) => {{
        #[inline(never)] #[naked]
        unsafe extern "C" fn isr() -> ! {
            use $crate::arch::cpu::Registers;
            use $crate::arch::cpu::interrupts::handlers::InterruptHandler;
            Registers::push();
            // Idt::disable_interrupts();

           asm!(  "mov rdi, rsp
                   add rdi, 9*8

                   cli
                   call $0
                   sti"
               :: "s"($handler as InterruptHandler)
                // , "i"(size_of::<context::Registers>())
               : "rdi" : "volatile", "intel");

            // Idt::enable_interrupts();
            Registers::pop();

            asm!("iretq" :::: "volatile", "intel");
            unreachable!();
       }
       isr
   }};
}

//==--------------------------------------------------------------------------==
// Top-level interrupt handling
lazy_static! {
    static ref IDT: Idt = {
        let mut idt = Idt::new();
        use self::handlers::*;

        // fill the IDT with empty ISRs so we don't throw faults
        for i in 0..idt::ENTRIES {
            idt.add_handler(i, isr!(interrupt: empty_handler) );
        }

        idt .add_handler(0, isr!(interrupt: ex0))
            .add_handler(1, isr!(interrupt: ex1))
            .add_handler(2, isr!(interrupt: ex2))
            // ISR 3 reserved for breakpoints
            .add_handler(4, isr!(interrupt: ex4))
            .add_handler(5, isr!(interrupt: ex5))
            .add_handler(6, isr!(interrupt: ex6))
            .add_handler(7, isr!(interrupt: ex7))
            .add_handler(8, isr!(error: ex8))
             // ISR 9 is reserved in x86_64
            .add_handler(10, isr!(error: ex10))
            .add_handler(11, isr!(error: ex11))
            .add_handler(12, isr!(error: ex12))
            .add_handler(13, isr!(error: ex13))
            .add_handler(14, isr!(error: page_fault))
             // ISR 15: reserved
            .add_handler(16,  isr!(interrupt: ex16))
            .add_handler(17,  isr!(error: ex17))
            .add_handler(18,  isr!(interrupt: ex18))
            .add_handler(19,  isr!(interrupt: ex19))
            .add_handler(0x21, isr!(interrupt: keyboard))
            .add_handler(0xff, isr!(interrupt: test));

        println!("{:<38}{:>40}", " . . Adding interrupt handlers to IDT"
             , "[ OKAY ]");
        idt
    };
}

// /// Kernel interrupt-handling function.
// ///
// /// Assembly ISRs call into this, and it dispatches interrupts to
// /// the appropriate consumers.
// //  TODO: should this be #[cold]?
// #[no_mangle] #[inline(never)]
// pub fn handle_interrupt(state: &InterruptFrame) {
//     let id = state.int_id;
//     match id {
//         // System timer
//         0x20 => { /* TODO: make this work
//                     TODO: should this IRQ get its own handler?
//                   */
//                  println!("timer!");
//                  }
//         // Loonix syscall vector
//       , 0x80 => { // TODO: currently, we do nothing here, do we want
//                   // our syscalls on this vector as well?
//         }
//       , _ =>  {
//           // unknown interrupt. silently do nothing?
//           println!("Unknown interrupt: #{} Sorry!", id);
//       }
//     }
//     // send the PICs the end interrupt signal
//     unsafe {
//         pics::end_pic_interrupt(id as u8);
//         Idt::enable_interrupts();
//     }
// }

/// Initialize interrupt handling.
///
/// This function initializes the PICs, populates the IDT with interrupt
/// handlers, loads the IDT pointer, and enables interrupts.
///
/// This is called from the kernel during the init process.
pub unsafe fn initialize() {
   // println!(" . Enabling interrupts:" );
   // println!( " . . Initialising PICs {:>40}"
   //         , pics::initialize().unwrap_or("[ FAIL ]") );
    pics::initialize();
   // TODO: consider loading double-fault handler before anything else in case
   //       a double fault occurs during init?
    IDT.load();         // Load the IDT pointer

    print!(" . . Testing interrupt handling");
    asm!("int $0" :: "N" (0xff));

    Idt::enable_interrupts(); // enable interrupts

}
<commit_msg>[x86_all] remove dead code & commented out stuff from interrupts<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Intterupt handling on x86 machines.
//!
//! This module provides support for interrupt handling on both `x86` and
//! `x86_64` as a black box. Code that depends on this can use the same API
//! regardless of system word size.
use arch::cpu::dtable::DTable;

pub mod idt;
pub mod pics;
pub mod handlers;

use self::idt::Idt;

/// Macro for making Interrupt Service Routines
macro_rules! isr {
   (error: $handler:ident) => {{
       #[inline(never)] #[naked]
       unsafe extern "C" fn isr() -> ! {
            use $crate::arch::cpu::Registers;
            use $crate::arch::cpu::interrupts::handlers::ErrorCodeHandler;

            Registers::push();

            asm!( "mov rsi, [rsp + 9*8)]  // pop error code into rsi
                   mov rdi, rsp
                   add rdi, 10*8
                   sub rsp, 8   // align stack pointer

                   cli
                   call $0
                   sti

                   add rsp, 8   // un-align stack pointer"
                :: "s"($handler as ErrorCodeHandler)
                //  , "i"(size_of::<context::Registers>())
                : "rsi", "rdi"
                : "volatile", "intel");

            Registers::pop();

            asm!( "add rsp, 8     // remove error code from stack
                   iretq" :::: "volatile", "intel");
            unreachable!();
       }
       isr
   }};
   (interrupt: $handler:ident) => {{
        #[inline(never)] #[naked]
        unsafe extern "C" fn isr() -> ! {
            use $crate::arch::cpu::Registers;
            use $crate::arch::cpu::interrupts::handlers::InterruptHandler;
            Registers::push();
            // Idt::disable_interrupts();

           asm!(  "mov rdi, rsp
                   add rdi, 9*8

                   cli
                   call $0
                   sti"
               :: "s"($handler as InterruptHandler)
                // , "i"(size_of::<context::Registers>())
               : "rdi" : "volatile", "intel");

            // Idt::enable_interrupts();
            Registers::pop();

            asm!("iretq" :::: "volatile", "intel");
            unreachable!();
       }
       isr
   }};
}

//==--------------------------------------------------------------------------==
// Top-level interrupt handling
lazy_static! {
    static ref IDT: Idt = {
        let mut idt = Idt::new();
        use self::handlers::*;

        // fill the IDT with empty ISRs so we don't throw faults
        for i in 0..idt::ENTRIES {
            idt.add_handler(i, isr!(interrupt: empty_handler) );
        }

        idt .add_handler(0, isr!(interrupt: ex0))
            .add_handler(1, isr!(interrupt: ex1))
            .add_handler(2, isr!(interrupt: ex2))
            // ISR 3 reserved for breakpoints
            .add_handler(4, isr!(interrupt: ex4))
            .add_handler(5, isr!(interrupt: ex5))
            .add_handler(6, isr!(interrupt: ex6))
            .add_handler(7, isr!(interrupt: ex7))
            .add_handler(8, isr!(error: ex8))
             // ISR 9 is reserved in x86_64
            .add_handler(10, isr!(error: ex10))
            .add_handler(11, isr!(error: ex11))
            .add_handler(12, isr!(error: ex12))
            .add_handler(13, isr!(error: ex13))
            .add_handler(14, isr!(error: page_fault))
             // ISR 15: reserved
            .add_handler(16,  isr!(interrupt: ex16))
            .add_handler(17,  isr!(error: ex17))
            .add_handler(18,  isr!(interrupt: ex18))
            .add_handler(19,  isr!(interrupt: ex19))
            .add_handler(0x20, isr!(interrupt: timer))
            .add_handler(0x21, isr!(interrupt: keyboard))
            .add_handler(0xff, isr!(interrupt: test));

        println!("{:<38}{:>40}", " . . Adding interrupt handlers to IDT"
             , "[ OKAY ]");
        idt
    };
}

/// Initialize interrupt handling.
///
/// This function initializes the PICs, populates the IDT with interrupt
/// handlers, loads the IDT pointer, and enables interrupts.
///
/// This is called from the kernel during the init process.
pub unsafe fn initialize() {

    pics::initialize();
   // TODO: consider loading double-fault handler before anything else in case
   //       a double fault occurs during init?
    IDT.load();         // Load the IDT pointer

    print!(" . . Testing interrupt handling");
    asm!("int $0" :: "N" (0xff));

    Idt::enable_interrupts(); // enable interrupts

}
<|endoftext|>


<commit_before>//! Implementation of Rust panics via process aborts
//!
//! When compared to the implementation via unwinding, this crate is *much*
//! simpler! That being said, it's not quite as versatile, but here goes!

#![no_std]
#![unstable(feature = "panic_abort", issue = "32837")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
)]
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
#![feature(libc)]
#![feature(nll)]
#![feature(panic_runtime)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![feature(asm)]

use core::any::Any;

#[rustc_std_internal_symbol]
#[allow(improper_ctypes_definitions)]
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
    unreachable!()
}

// "Leak" the payload and shim to the relevant abort on the platform in question.
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
    abort();

    cfg_if::cfg_if! {
        if #[cfg(any(unix, target_os = "cloudabi"))] {
            unsafe fn abort() -> ! {
                libc::abort();
            }
        } else if #[cfg(any(target_os = "hermit",
                            all(target_vendor = "fortanix", target_env = "sgx")
        ))] {
            unsafe fn abort() -> ! {
                // call std::sys::abort_internal
                extern "C" {
                    pub fn __rust_abort() -> !;
                }
                __rust_abort();
            }
        } else if #[cfg(windows)] {
            // On Windows, use the processor-specific __fastfail mechanism. In Windows 8
            // and later, this will terminate the process immediately without running any
            // in-process exception handlers. In earlier versions of Windows, this
            // sequence of instructions will be treated as an access violation,
            // terminating the process but without necessarily bypassing all exception
            // handlers.
            //
            // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
            //
            // Note: this is the same implementation as in libstd's `abort_internal`
            unsafe fn abort() -> ! {
                const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
                cfg_if::cfg_if! {
                    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
                        asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
                    } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
                        asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
                    } else if #[cfg(target_arch = "aarch64")] {
                        asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
                    } else {
                        core::intrinsics::abort();
                    }
                }
                core::intrinsics::unreachable();
            }
        } else {
            unsafe fn abort() -> ! {
                core::intrinsics::abort();
            }
        }
    }
}

// This... is a bit of an oddity. The tl;dr; is that this is required to link
// correctly, the longer explanation is below.
//
// Right now the binaries of libcore/libstd that we ship are all compiled with
// `-C panic=unwind`. This is done to ensure that the binaries are maximally
// compatible with as many situations as possible. The compiler, however,
// requires a "personality function" for all functions compiled with `-C
// panic=unwind`. This personality function is hardcoded to the symbol
// `rust_eh_personality` and is defined by the `eh_personality` lang item.
//
// So... why not just define that lang item here? Good question! The way that
// panic runtimes are linked in is actually a little subtle in that they're
// "sort of" in the compiler's crate store, but only actually linked if another
// isn't actually linked. This ends up meaning that both this crate and the
// panic_unwind crate can appear in the compiler's crate store, and if both
// define the `eh_personality` lang item then that'll hit an error.
//
// To handle this the compiler only requires the `eh_personality` is defined if
// the panic runtime being linked in is the unwinding runtime, and otherwise
// it's not required to be defined (rightfully so). In this case, however, this
// library just defines this symbol so there's at least some personality
// somewhere.
//
// Essentially this symbol is just defined to get wired up to libcore/libstd
// binaries, but it should never be called as we don't link in an unwinding
// runtime at all.
pub mod personalities {
    #[rustc_std_internal_symbol]
    #[cfg(not(any(
        all(target_arch = "wasm32", not(target_os = "emscripten"),),
        all(target_os = "windows", target_env = "gnu", target_arch = "x86_64",),
    )))]
    pub extern "C" fn rust_eh_personality() {}

    // On x86_64-pc-windows-gnu we use our own personality function that needs
    // to return `ExceptionContinueSearch` as we're passing on all our frames.
    #[rustc_std_internal_symbol]
    #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86_64"))]
    pub extern "C" fn rust_eh_personality(
        _record: usize,
        _frame: usize,
        _context: usize,
        _dispatcher: usize,
    ) -> u32 {
        1 // `ExceptionContinueSearch`
    }

    // Similar to above, this corresponds to the `eh_catch_typeinfo` lang item
    // that's only used on Emscripten currently.
    //
    // Since panics don't generate exceptions and foreign exceptions are
    // currently UB with -C panic=abort (although this may be subject to
    // change), any catch_unwind calls will never use this typeinfo.
    #[rustc_std_internal_symbol]
    #[allow(non_upper_case_globals)]
    #[cfg(target_os = "emscripten")]
    static rust_eh_catch_typeinfo: [usize; 2] = [0; 2];

    // These two are called by our startup objects on i686-pc-windows-gnu, but
    // they don't need to do anything so the bodies are nops.
    #[rustc_std_internal_symbol]
    #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
    pub extern "C" fn rust_eh_register_frames() {}
    #[rustc_std_internal_symbol]
    #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
    pub extern "C" fn rust_eh_unregister_frames() {}
}
<commit_msg>support panic=abort in Miri<commit_after>//! Implementation of Rust panics via process aborts
//!
//! When compared to the implementation via unwinding, this crate is *much*
//! simpler! That being said, it's not quite as versatile, but here goes!

#![no_std]
#![unstable(feature = "panic_abort", issue = "32837")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
)]
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
#![feature(libc)]
#![feature(nll)]
#![feature(panic_runtime)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![feature(asm)]

use core::any::Any;

#[rustc_std_internal_symbol]
#[allow(improper_ctypes_definitions)]
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
    unreachable!()
}

// "Leak" the payload and shim to the relevant abort on the platform in question.
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
    abort();

    cfg_if::cfg_if! {
        if #[cfg(any(unix, target_os = "cloudabi"))] {
            unsafe fn abort() -> ! {
                libc::abort();
            }
        } else if #[cfg(any(target_os = "hermit",
                            all(target_vendor = "fortanix", target_env = "sgx")
        ))] {
            unsafe fn abort() -> ! {
                // call std::sys::abort_internal
                extern "C" {
                    pub fn __rust_abort() -> !;
                }
                __rust_abort();
            }
        } else if #[cfg(all(windows, not(miri)))] {
            // On Windows, use the processor-specific __fastfail mechanism. In Windows 8
            // and later, this will terminate the process immediately without running any
            // in-process exception handlers. In earlier versions of Windows, this
            // sequence of instructions will be treated as an access violation,
            // terminating the process but without necessarily bypassing all exception
            // handlers.
            //
            // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
            //
            // Note: this is the same implementation as in libstd's `abort_internal`
            unsafe fn abort() -> ! {
                const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
                cfg_if::cfg_if! {
                    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
                        asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
                    } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
                        asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
                    } else if #[cfg(target_arch = "aarch64")] {
                        asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
                    } else {
                        core::intrinsics::abort();
                    }
                }
                core::intrinsics::unreachable();
            }
        } else {
            unsafe fn abort() -> ! {
                core::intrinsics::abort();
            }
        }
    }
}

// This... is a bit of an oddity. The tl;dr; is that this is required to link
// correctly, the longer explanation is below.
//
// Right now the binaries of libcore/libstd that we ship are all compiled with
// `-C panic=unwind`. This is done to ensure that the binaries are maximally
// compatible with as many situations as possible. The compiler, however,
// requires a "personality function" for all functions compiled with `-C
// panic=unwind`. This personality function is hardcoded to the symbol
// `rust_eh_personality` and is defined by the `eh_personality` lang item.
//
// So... why not just define that lang item here? Good question! The way that
// panic runtimes are linked in is actually a little subtle in that they're
// "sort of" in the compiler's crate store, but only actually linked if another
// isn't actually linked. This ends up meaning that both this crate and the
// panic_unwind crate can appear in the compiler's crate store, and if both
// define the `eh_personality` lang item then that'll hit an error.
//
// To handle this the compiler only requires the `eh_personality` is defined if
// the panic runtime being linked in is the unwinding runtime, and otherwise
// it's not required to be defined (rightfully so). In this case, however, this
// library just defines this symbol so there's at least some personality
// somewhere.
//
// Essentially this symbol is just defined to get wired up to libcore/libstd
// binaries, but it should never be called as we don't link in an unwinding
// runtime at all.
pub mod personalities {
    #[rustc_std_internal_symbol]
    #[cfg(not(any(
        all(target_arch = "wasm32", not(target_os = "emscripten"),),
        all(target_os = "windows", target_env = "gnu", target_arch = "x86_64",),
    )))]
    pub extern "C" fn rust_eh_personality() {}

    // On x86_64-pc-windows-gnu we use our own personality function that needs
    // to return `ExceptionContinueSearch` as we're passing on all our frames.
    #[rustc_std_internal_symbol]
    #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86_64"))]
    pub extern "C" fn rust_eh_personality(
        _record: usize,
        _frame: usize,
        _context: usize,
        _dispatcher: usize,
    ) -> u32 {
        1 // `ExceptionContinueSearch`
    }

    // Similar to above, this corresponds to the `eh_catch_typeinfo` lang item
    // that's only used on Emscripten currently.
    //
    // Since panics don't generate exceptions and foreign exceptions are
    // currently UB with -C panic=abort (although this may be subject to
    // change), any catch_unwind calls will never use this typeinfo.
    #[rustc_std_internal_symbol]
    #[allow(non_upper_case_globals)]
    #[cfg(target_os = "emscripten")]
    static rust_eh_catch_typeinfo: [usize; 2] = [0; 2];

    // These two are called by our startup objects on i686-pc-windows-gnu, but
    // they don't need to do anything so the bodies are nops.
    #[rustc_std_internal_symbol]
    #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
    pub extern "C" fn rust_eh_register_frames() {}
    #[rustc_std_internal_symbol]
    #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
    pub extern "C" fn rust_eh_unregister_frames() {}
}
<|endoftext|>


<commit_before>use nom::*;
use std::str;

#[derive(Debug)]
pub struct Paragraph<'a> {
    parts: Vec<Text<'a>>,
}

#[derive(Debug, PartialEq)]
pub enum Text<'a> {
    Plain(&'a str),
    Italics(&'a str),
}

impl<'a> Paragraph<'a> {
    pub fn to_html(&self) -> String {
        self.parts.iter()
            .map(|text| match *text {
                Text::Plain(ref s) => s.to_string(),
                Text::Italics(ref s) => ["", &s[..], ""].concat(),
            })
            .collect::<Vec<_>>()
            .concat()
    }
}

named!(italics<Text>,
    delimited!(
        char!('*'),
        chain!(
            bytes: is_not!("*") ~
            s:     expr_res!(str::from_utf8(bytes)),
            || { Text::Italics(s) }
        ),
        char!('*')
    )
);

#[test]
fn test_html1() {
    let p = Paragraph {
        parts: vec![Text::Plain("plaintext "),
                    Text::Italics("italics text")],
    };

    assert!(p.to_html() == "plaintext italics text".to_owned());
}

#[test]
fn test_italics_parse() {
    if let IResult::Done(input, output) = italics(b"*Hello* World") {
        assert_eq!(input, b" World");
        assert_eq!(output, Text::Italics("Hello"));
    } else {
        panic!(r#" Italics failed with "*Hello* World" "#);
    }

    match italics(b"Hello World") {
        IResult::Error(_) => (),
        _ => panic!(r#" Italics failed with "Hello World" "#),
    };

    match italics(b"*Hello World") {
        IResult::Incomplete(_) => (),
        _ => panic!(r#" Italics failed with "*Hello World" "#),
    }
}

#[test]
#[should_panic]                 // TODO: Fix
fn test_italics_escaped() {
    if let IResult::Done(input, output) = italics(br"*Hell\*o* World") {
        assert_eq!(output, Text::Italics("Hell*o"));
        assert_eq!(input, b" World");
    } else {
        panic!("Italics failed with \"*Hell\\*o* World");
    }
}
<commit_msg>Basic paragraph parsing<commit_after>use nom::*;
use std::str;

#[derive(Debug)]
pub struct Paragraph<'a> {
    parts: Vec<Text<'a>>,
}

#[derive(Debug, PartialEq)]
pub enum Text<'a> {
    Plain(&'a str),
    Italics(&'a str),
}

impl<'a> Paragraph<'a> {
    pub fn to_html(&self) -> String {
        self.parts.iter()
            .map(|text| match *text {
                Text::Plain(ref s) => s.to_string(),
                Text::Italics(ref s) => ["", &s[..], ""].concat(),
            })
            .collect::<Vec<_>>()
            .concat()
    }
}

named!(paragraph<Paragraph>,
    chain!(
        vec: many1!(alt!(plain | italics)),
        || { Paragraph { parts: vec } }
    )
);

named!(plain<Text>,
    chain!(
        bytes: is_not!("*") ~
        s:     expr_res!(str::from_utf8(bytes)),
        || { Text::Plain(s) }
    )
);

named!(italics<Text>,
    delimited!(
        char!('*'),
        chain!(
            bytes: is_not!("*") ~
            s:     expr_res!(str::from_utf8(bytes)),
            || { Text::Italics(s) }
        ),
        char!('*')
    )
);

#[test]
fn test_paragraph_parse() {
    if let IResult::Done(input, output) = paragraph(b"Hello *World*") {
        assert_eq!(input, b"");
        assert_eq!(output.parts, vec![Text::Plain("Hello "),
                                      Text::Italics("World")]);
    } else {
        panic!(r#" Paragraph parse failed with "Hello *World*" "#);
    }

    if let IResult::Done(input, output) = paragraph(b"*This* is *a test*") {
        assert_eq!(input, b"");
        assert_eq!(output.parts, vec![Text::Italics("This"),
                                      Text::Plain(" is "),
                                      Text::Italics("a test")]);
    } else {
        panic!(r#" Paragraph parse failed with "Hello *World*" "#);
    }
}

#[test]
fn test_plain_parse() {
    if let IResult::Done(input, output) = plain(b"Hello *World*") {
        assert_eq!(input, b"*World*");
        assert_eq!(output, Text::Plain("Hello "));
    } else {
        panic!(r#" Plain parse failed with "Hello *World*" "#);
    }

    match plain(b"*Hello World*") {
        IResult::Error(_) => (),
        _ => panic!(r#" Plain failed with "*Hello World*" "#),
    }
}

#[test]
fn test_html1() {
    let p = Paragraph {
        parts: vec![Text::Plain("plaintext "),
                    Text::Italics("italics text")],
    };

    assert!(p.to_html() == "plaintext italics text".to_owned());
}

#[test]
fn test_italics_parse() {
    if let IResult::Done(input, output) = italics(b"*Hello* World") {
        assert_eq!(input, b" World");
        assert_eq!(output, Text::Italics("Hello"));
    } else {
        panic!(r#" Italics failed with "*Hello* World" "#);
    }

    match italics(b"Hello World") {
        IResult::Error(_) => (),
        _ => panic!(r#" Italics failed with "Hello World" "#),
    };

    match italics(b"*Hello World") {
        IResult::Incomplete(_) => (),
        _ => panic!(r#" Italics failed with "*Hello World" "#),
    }
}

#[test]
#[should_panic]                 // TODO: Fix
fn test_italics_escaped() {
    if let IResult::Done(input, output) = italics(br"*Hell\*o* World") {
        assert_eq!(output, Text::Italics("Hell*o"));
        assert_eq!(input, b" World");
    } else {
        panic!("Italics failed with \"*Hell\\*o* World");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::io;
use std::mem;

use encoding::Type;

/// A `Primitive` represents the primitive data types which make up all records. This is the format
/// used to communicate data between `Encodable`/`Decodable` types and an `Encoder`/`Decoder`.
#[allow(missing_docs)]
pub enum Primitive {
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),

    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),

    Fixed32(u32),
    Fixed64(u64),

    Float32(f32),
    Float64(f64),

    Bool(bool),

    Bytes(Vec<u8>),
    String(String),

    Enum(i64),
}

impl Primitive {
    /// The `has_type` simply that the type of `self` is `t`.
    pub fn has_type(&self, t: Type) -> bool {
        use encoding::Type::*;

        match (self, t) {
            (&Primitive::UInt8(..),  UInt8)  => true,
            (&Primitive::UInt16(..), UInt8)  => true,
            (&Primitive::UInt32(..), UInt32) => true,
            (&Primitive::UInt64(..), UInt64) => true,

            (&Primitive::Int8(..),  Int8)  => true,
            (&Primitive::Int16(..), Int8)  => true,
            (&Primitive::Int32(..), Int32) => true,
            (&Primitive::Int64(..), Int64) => true,

            (&Primitive::Fixed32(..), Fixed32) => true,
            (&Primitive::Fixed64(..), Fixed64) => true,

            (&Primitive::Float32(..), Float32) => true,
            (&Primitive::Float64(..), Float64) => true,

            (&Primitive::Bool(..), Bool) => true,

            (&Primitive::Bytes(..), Bytes)   => true,
            (&Primitive::String(..), String) => true,

            (&Primitive::Enum(..), Enum) => true,

            _ => false,
        }
    }
}

/// `uvarint_size` returns the number of bytes required to encode `x` as a varint.
pub fn uvarint_size(x: u64) -> usize {
    if x < 0x80 {
        1
    } else if x < 0x80 << 7 {
        2
    } else if x < 0x80 << 14 {
        3
    } else if x < 0x80 << 21 {
        4
    } else if x < 0x80 << 28 {
        5
    } else if x < 0x80 << 35 {
        6
    } else if x < 0x80 << 42 {
        7
    } else if x < 0x80 << 49 {
        8
    } else if x < 0x80 << 56 {
        9
    } else {
        10
    }
}

/// `varint_size` returns the number of bytes required to encode `x` as a zig-zag encoded signed
/// varint.
pub fn varint_size(x: i64) -> usize {
    let ux = (x as u64) << 1;

    uvarint_size(if x < 0 { !ux } else { ux })
}

/// `write_uvarint` writes 'x' to 'w' encoded as a varint.
pub fn write_uvarint<W>(w: &mut W, mut x: u64) -> io::Result<usize>
    where W: io::Write {

    // A 64-bit varint can be at most 10 bytes long.
    let mut buf = [0u8; 10];
    let mut idx = 0;

    while x > 0x7F {
        buf[idx] = 0x80 | (x & 0x7F) as u8;
        x = x >> 7;
        idx += 1;
    }

    buf[idx] = x as u8;

    try!(w.write_all(&buf[idx..]));

    Ok((idx + 1) as usize)
}

/// `write_varint` writes 'x' to 'w' as a zig-zag encoded signed varint.
pub fn write_varint<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    let ux = (x as u64) << 1;

    write_uvarint(w, if x < 0 { !ux } else { ux })
}

/// `write_le_u8` writes `x` to `w` as a single byte.
pub fn write_le_u8<W>(w: &mut W, x: u8) -> io::Result<usize>
    where W: io::Write {

    let buf = [x];
    try!(w.write_all(&buf));
    Ok(1)
}

/// `write_le_u16` writes `x` to `w` as 2 bytes in little-endian byte order.
pub fn write_le_u16<W>(w: &mut W, x: u16) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >> 0) & 0xFF) as u8,
        ((x >> 8) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(2)
}

/// `write_le_u32` writes `x` to `w` as 4 bytes in little-endian byte order.
pub fn write_le_u32<W>(w: &mut W, x: u32) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(4)
}

/// `write_le_u64` writes `x` to `w` as 8 bytes in little-endian byte order.
pub fn write_le_u64<W>(w: &mut W, x: u64) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
        ((x >> 32) & 0xFF) as u8,
        ((x >> 40) & 0xFF) as u8,
        ((x >> 48) & 0xFF) as u8,
        ((x >> 56) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(8)
}

/// `write_le_i8` writes `x` to `w` as a single, 2's complement encoded byte.
pub fn write_le_i8<W>(w: &mut W, x: i8) -> io::Result<usize>
    where W: io::Write {

    write_le_u8(w, x as u8)
}

/// `write_le_i16` writes `x` to `w` as 2 bytes, 2's complement encoded in little-endian byte order.
pub fn write_le_i16<W>(w: &mut W, x: i16) -> io::Result<usize>
    where W: io::Write {

    write_le_u16(w, x as u16)
}

/// `write_le_i32` writes `x` to `w` as 4 bytes, 2's complement encoded in little-endian byte order.
pub fn write_le_i32<W>(w: &mut W, x: i32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, x as u32)
}

/// `write_le_i64` writes `x` to `w` as 8 bytes, 2's complement encoded in little-endian byte order.
pub fn write_le_i64<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, x as u64)
}

/// `write_le_f32` writes `x` to `w` as 4 bytes, ieee-754 binary32 encoded in little-endian byte
/// order.
pub fn write_le_f32<W>(w: &mut W, x: f32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, unsafe { mem::transmute(x) })
}

/// `write_le_f64` writes `x` to `w` as 8 bytes, ieee-754 binary64 encoded in little-endian byte
/// order.
pub fn write_le_f64<W>(w: &mut W, x: f64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, unsafe { mem::transmute(x) })
}
<commit_msg>Renamed write_le_[ui]8 to write_[ui]8.<commit_after>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::io;
use std::mem;

use encoding::Type;

/// A `Primitive` represents the primitive data types which make up all records. This is the format
/// used to communicate data between `Encodable`/`Decodable` types and an `Encoder`/`Decoder`.
#[allow(missing_docs)]
pub enum Primitive {
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),

    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),

    Fixed32(u32),
    Fixed64(u64),

    Float32(f32),
    Float64(f64),

    Bool(bool),

    Bytes(Vec<u8>),
    String(String),

    Enum(i64),
}

impl Primitive {
    /// The `has_type` simply that the type of `self` is `t`.
    pub fn has_type(&self, t: Type) -> bool {
        use encoding::Type::*;

        match (self, t) {
            (&Primitive::UInt8(..),  UInt8)  => true,
            (&Primitive::UInt16(..), UInt8)  => true,
            (&Primitive::UInt32(..), UInt32) => true,
            (&Primitive::UInt64(..), UInt64) => true,

            (&Primitive::Int8(..),  Int8)  => true,
            (&Primitive::Int16(..), Int8)  => true,
            (&Primitive::Int32(..), Int32) => true,
            (&Primitive::Int64(..), Int64) => true,

            (&Primitive::Fixed32(..), Fixed32) => true,
            (&Primitive::Fixed64(..), Fixed64) => true,

            (&Primitive::Float32(..), Float32) => true,
            (&Primitive::Float64(..), Float64) => true,

            (&Primitive::Bool(..), Bool) => true,

            (&Primitive::Bytes(..), Bytes)   => true,
            (&Primitive::String(..), String) => true,

            (&Primitive::Enum(..), Enum) => true,

            _ => false,
        }
    }
}

/// `uvarint_size` returns the number of bytes required to encode `x` as a varint.
pub fn uvarint_size(x: u64) -> usize {
    if x < 0x80 {
        1
    } else if x < 0x80 << 7 {
        2
    } else if x < 0x80 << 14 {
        3
    } else if x < 0x80 << 21 {
        4
    } else if x < 0x80 << 28 {
        5
    } else if x < 0x80 << 35 {
        6
    } else if x < 0x80 << 42 {
        7
    } else if x < 0x80 << 49 {
        8
    } else if x < 0x80 << 56 {
        9
    } else {
        10
    }
}

/// `varint_size` returns the number of bytes required to encode `x` as a zig-zag encoded signed
/// varint.
pub fn varint_size(x: i64) -> usize {
    let ux = (x as u64) << 1;

    uvarint_size(if x < 0 { !ux } else { ux })
}

/// `write_uvarint` writes 'x' to 'w' encoded as a varint.
pub fn write_uvarint<W>(w: &mut W, mut x: u64) -> io::Result<usize>
    where W: io::Write {

    // A 64-bit varint can be at most 10 bytes long.
    let mut buf = [0u8; 10];
    let mut idx = 0;

    while x > 0x7F {
        buf[idx] = 0x80 | (x & 0x7F) as u8;
        x = x >> 7;
        idx += 1;
    }

    buf[idx] = x as u8;

    try!(w.write_all(&buf[idx..]));

    Ok((idx + 1) as usize)
}

/// `write_varint` writes 'x' to 'w' as a zig-zag encoded signed varint.
pub fn write_varint<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    let ux = (x as u64) << 1;

    write_uvarint(w, if x < 0 { !ux } else { ux })
}

/// `write_u8` writes `x` to `w` as a single byte.
pub fn write_u8<W>(w: &mut W, x: u8) -> io::Result<usize>
    where W: io::Write {

    let buf = [x];
    try!(w.write_all(&buf));
    Ok(1)
}

/// `write_le_u16` writes `x` to `w` as 2 bytes in little-endian byte order.
pub fn write_le_u16<W>(w: &mut W, x: u16) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >> 0) & 0xFF) as u8,
        ((x >> 8) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(2)
}

/// `write_le_u32` writes `x` to `w` as 4 bytes in little-endian byte order.
pub fn write_le_u32<W>(w: &mut W, x: u32) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(4)
}

/// `write_le_u64` writes `x` to `w` as 8 bytes in little-endian byte order.
pub fn write_le_u64<W>(w: &mut W, x: u64) -> io::Result<usize>
    where W: io::Write {

    let buf = [
        ((x >>  0) & 0xFF) as u8,
        ((x >>  8) & 0xFF) as u8,
        ((x >> 16) & 0xFF) as u8,
        ((x >> 24) & 0xFF) as u8,
        ((x >> 32) & 0xFF) as u8,
        ((x >> 40) & 0xFF) as u8,
        ((x >> 48) & 0xFF) as u8,
        ((x >> 56) & 0xFF) as u8,
    ];

    try!(w.write_all(&buf));
    Ok(8)
}

/// `write_i8` writes `x` to `w` as a single, 2's complement encoded byte.
pub fn write_i8<W>(w: &mut W, x: i8) -> io::Result<usize>
    where W: io::Write {

    write_u8(w, x as u8)
}

/// `write_le_i16` writes `x` to `w` as 2 bytes, 2's complement encoded in little-endian byte order.
pub fn write_le_i16<W>(w: &mut W, x: i16) -> io::Result<usize>
    where W: io::Write {

    write_le_u16(w, x as u16)
}

/// `write_le_i32` writes `x` to `w` as 4 bytes, 2's complement encoded in little-endian byte order.
pub fn write_le_i32<W>(w: &mut W, x: i32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, x as u32)
}

/// `write_le_i64` writes `x` to `w` as 8 bytes, 2's complement encoded in little-endian byte order.
pub fn write_le_i64<W>(w: &mut W, x: i64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, x as u64)
}

/// `write_le_f32` writes `x` to `w` as 4 bytes, ieee-754 binary32 encoded in little-endian byte
/// order.
pub fn write_le_f32<W>(w: &mut W, x: f32) -> io::Result<usize>
    where W: io::Write {

    write_le_u32(w, unsafe { mem::transmute(x) })
}

/// `write_le_f64` writes `x` to `w` as 8 bytes, ieee-754 binary64 encoded in little-endian byte
/// order.
pub fn write_le_f64<W>(w: &mut W, x: f64) -> io::Result<usize>
    where W: io::Write {

    write_le_u64(w, unsafe { mem::transmute(x) })
}
<|endoftext|>