<commit_before>// Copyright © 2018 Cormac O'Brien
//
// 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.

pub mod alias;
pub mod bitmap;
pub mod brush;
pub mod hud;
pub mod world;

use std::collections::HashMap;

use client::Client;
use client::ClientEntity;
use common::model::Model;
use common::model::ModelKind;
use common::net::ItemFlags;
use common::net::MAX_ITEMS;
use common::pak::Pak;
use common::wad::Wad;

use cgmath::Deg;
use cgmath::Euler;
use cgmath::Matrix4;
use cgmath::Vector3;
use cgmath::Zero;
use chrono::Duration;
use failure::Error;
use flame;
use gfx;
use gfx::handle::ShaderResourceView;
use gfx::handle::Texture;
use gfx::format::R8_G8_B8_A8;
use gfx::pso::PipelineData;
use gfx::pso::PipelineState;
use gfx_device_gl::Factory;
use gfx_device_gl::Resources;

pub use gfx::format::Srgba8 as ColorFormat;
pub use gfx::format::DepthStencil as DepthFormat;

use self::alias::AliasRenderer;
use self::brush::BrushRenderer;
use self::hud::HudRenderer;
use self::world::WorldRenderer;

const PALETTE_SIZE: usize = 768;

// TODO: per-API coordinate system conversions
pub static VERTEX_SHADER_GLSL: &[u8] = br#"
#version 430

layout (location = 0) in vec3 a_Pos;
layout (location = 1) in vec2 a_Texcoord;

out vec2 f_texcoord;

uniform mat4 u_Transform;

void main() {
    f_texcoord = a_Texcoord;
    gl_Position = u_Transform * vec4(-a_Pos.y, a_Pos.z, -a_Pos.x, 1.0);
}
"#;

pub static FRAGMENT_SHADER_GLSL: &[u8] = br#"
#version 430

in vec2 f_texcoord;

uniform sampler2D u_Texture;

out vec4 Target0;

void main() {
    vec4 color = texture(u_Texture, f_texcoord);
    if (color.a == 0) {
        discard;
    } else {
        Target0 = color;
    }
}"#;

// TODO: per-API coordinate system conversions
pub static VERTEX_SHADER_2D_GLSL: &[u8] = br#"
#version 430

layout (location = 0) in vec2 a_Pos;
layout (location = 1) in vec2 a_Texcoord;

out vec2 f_texcoord;

uniform mat4 u_Transform;

void main() {
    f_texcoord = a_Texcoord;
    gl_Position = u_Transform * vec4(a_Pos.x, a_Pos.y, 0.0, 1.0);
}
"#;

pub static FRAGMENT_SHADER_2D_GLSL: &[u8] = br#"
#version 430

in vec2 f_texcoord;

uniform sampler2D u_Texture;

out vec4 Target0;

void main() {
    vec4 color = texture(u_Texture, f_texcoord);
    if (color.a == 0) {
        discard;
    } else {
        Target0 = color;
    }
}
"#;

gfx_defines! {
    vertex Vertex {
        pos: [f32; 3] = "a_Pos",
        texcoord: [f32; 2] = "a_Texcoord",
    }

    constant Locals {
        transform: [[f32; 4]; 4] = "u_Transform",
    }

    pipeline pipe {
        vertex_buffer: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        sampler: gfx::TextureSampler<[f32; 4]> = "u_Texture",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

gfx_defines! {
    vertex Vertex2d {
        pos: [f32; 2] = "a_Pos",
        texcoord: [f32; 2] = "a_Texcoord",
    }

    constant Locals2d {
        transform: [[f32; 4]; 4] = "u_Transform",
    }

    pipeline pipeline2d {
        vertex_buffer: gfx::VertexBuffer<Vertex2d> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        sampler: gfx::TextureSampler<[f32; 4]> = "u_Texture",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> = gfx::preset::depth::PASS_TEST,
    }
}

pub struct Camera {
    origin: Vector3<f32>,
    angles: Vector3<Deg<f32>>,
    projection: Matrix4<f32>,

    transform: Matrix4<f32>,
}

impl Camera {
    pub fn new(
        origin: Vector3<f32>,
        angles: Vector3<Deg<f32>>,
        projection: Matrix4<f32>,
    ) -> Camera {
        // negate the camera origin and angles
        // TODO: the OpenGL coordinate conversion is hardcoded here! XXX
        let converted_origin = Vector3::new(-origin.y, origin.z, -origin.x);
        let translation = Matrix4::from_translation(-converted_origin);
        let rotation = Matrix4::from(Euler::new(-angles.x, -angles.y, -angles.z));

        Camera {
            origin,
            angles,
            projection,
            transform: projection * rotation * translation,
        }
    }

    pub fn get_origin(&self) -> Vector3<f32> {
        self.origin
    }

    pub fn get_transform(&self) -> Matrix4<f32> {
        self.transform
    }
}

pub struct SceneRenderer {
    pipeline: PipelineState<Resources, <pipe::Data<Resources> as PipelineData<Resources>>::Meta>,
    world_renderer: WorldRenderer,
    brush_renderers: HashMap<usize, BrushRenderer>,
    alias_renderers: HashMap<usize, AliasRenderer>,
    // spr_renderers: ...,
}

impl SceneRenderer {
    pub fn new(models: &[Model], worldmodel_id: usize, palette: &Palette, factory: &mut Factory) -> Result<SceneRenderer, Error>
    {
        use gfx::traits::FactoryExt;
        let shader_set = factory.create_shader_set(VERTEX_SHADER_GLSL, FRAGMENT_SHADER_GLSL).unwrap();

        let rasterizer = gfx::state::Rasterizer {
            front_face: gfx::state::FrontFace::Clockwise,
            cull_face: gfx::state::CullFace::Back,
            method: gfx::state::RasterMethod::Fill,
            offset: None,
            samples: Some(gfx::state::MultiSample),
        };

        let pipeline = factory.create_pipeline_state(
            &shader_set,
            gfx::Primitive::TriangleList,
            rasterizer,
            pipe::new(),
        ).unwrap();

        let mut maybe_world_renderer = None;
        let mut brush_renderers = HashMap::new();
        let mut alias_renderers = HashMap::new();
        for (i, model) in models.iter().enumerate() {
            if i == worldmodel_id {
                match *model.kind() {
                    ModelKind::Brush(ref bmodel) => {
                        debug!("model {}: world model", i);
                        maybe_world_renderer = Some(WorldRenderer::new(model.name(), &bmodel, palette, factory));
                    }

                    _ => bail!("Invalid kind for worldmodel"),
                }
            } else {
                match *model.kind() {
                    ModelKind::Brush(ref bmodel) => {
                        debug!("model {}: brush model", i);
                        brush_renderers.insert(i, BrushRenderer::new(model.name(), &bmodel, palette, factory));
                    }

                    ModelKind::Alias(ref amodel) => {
                        debug!("model {}: alias model", i);
                        alias_renderers.insert(i, AliasRenderer::new(&amodel, palette, factory)?);
                    },

                    // TODO handle sprite and null models
                    ModelKind::Sprite(_) => debug!("model {}: sprite model", i),
                    _ => (),
                }
            }
        }

        let world_renderer = match maybe_world_renderer {
            Some(w) => w,
            None => bail!("No worldmodel provided"),
        };

        Ok(SceneRenderer {
            pipeline,
            world_renderer,
            brush_renderers,
            alias_renderers
        })
    }

    #[flame]
    pub fn render<C>(
        &self,
        encoder: &mut gfx::Encoder<Resources, C>,
        user_data: &mut pipe::Data<Resources>,
        entities: &[ClientEntity],
        time: Duration,
        camera: &Camera,
    ) -> Result<(), Error>
    where
        C: gfx::CommandBuffer<Resources>,
    {
        flame::start("render_world");
        self.world_renderer.render(
            encoder,
            &self.pipeline,
            user_data,
            time,
            camera,
            Vector3::zero(),
            Vector3::new(Deg(0.0), Deg(0.0), Deg(0.0)),
        );
        flame::end("render_world");

        flame::start("render_entities");
        for ent in entities.iter() {
            let model_id = ent.get_model_id();
            if let Some(ref brush_renderer) = self.brush_renderers.get(&model_id) {
                brush_renderer.render(
                    encoder,
                    &self.pipeline,
                    user_data,
                    time,
                    camera,
                    ent.get_origin(),
                    ent.get_angles()
                );
            } else if let Some(ref alias_renderer) = self.alias_renderers.get(&model_id) {
                // TODO: pull keyframe and texture ID
                alias_renderer.render(
                    encoder,
                    &self.pipeline,
                    user_data,
                    time,
                    camera,
                    ent.get_origin(),
                    ent.get_angles(),
                    0,
                    0
                )?;
            }
        }
        flame::end("render_entities");

        Ok(())
    }
}

pub struct UiRenderer {
    pipeline: PipelineState<Resources, <pipeline2d::Data<Resources> as PipelineData<Resources>>::Meta>,
    hud_renderer: HudRenderer,
}

impl UiRenderer {
    pub fn new(
        gfx_wad: &Wad,
        palette: &Palette,
        factory: &mut Factory,
    ) -> Result<UiRenderer, Error> {
        use gfx::traits::FactoryExt;
        let shader_set = factory.create_shader_set(VERTEX_SHADER_2D_GLSL, FRAGMENT_SHADER_2D_GLSL).unwrap();

        let rasterizer = gfx::state::Rasterizer {
            front_face: gfx::state::FrontFace::Clockwise,
            cull_face: gfx::state::CullFace::Back,
            method: gfx::state::RasterMethod::Fill,
            offset: None,
            samples: Some(gfx::state::MultiSample),
        };

        let pipeline = factory.create_pipeline_state(
            &shader_set,
            gfx::Primitive::TriangleList,
            rasterizer,
            pipeline2d::new(),
        ).unwrap();

        let hud_renderer = HudRenderer::new(gfx_wad, palette, factory)?;

        Ok(UiRenderer {
            pipeline,
            hud_renderer,
        })
    }

    pub fn render<C>(
        &mut self,
        factory: &mut Factory,
        encoder: &mut gfx::Encoder<Resources, C>,
        user_data: &mut pipeline2d::Data<Resources>,
        client: &Client,
        display_width: u32,
        display_height: u32,
    ) -> Result<(), Error>
    where
        C: gfx::CommandBuffer<Resources>,
    {
        self.hud_renderer.render(factory, encoder, &self.pipeline, user_data, client, display_width, display_height)?;

        Ok(())
    }
}

pub struct Palette {
    rgb: [[u8; 3]; 256],
}

impl Palette {
    pub fn load<S>(pak: &Pak, path: S) -> Palette
    where
        S: AsRef<str>,
    {
        let data = pak.open(path).unwrap();
        assert_eq!(data.len(), PALETTE_SIZE);

        let mut rgb = [[0u8; 3]; 256];

        for color in 0..256 {
            for component in 0..3 {
                rgb[color][component] = data[color * 3 + component];
            }
        }

        Palette { rgb }
    }

    // TODO: this will not render console characters correctly, as they use index 0 (black) to
    // indicate transparency.
    pub fn indexed_to_rgba(&self, indices: &[u8]) -> Vec<u8> {
        let mut rgba = Vec::with_capacity(indices.len() * 4);

        for index in indices {
            match *index {
                0xFF => for i in 0..4 {
                    rgba.push(0);
                },

                _ => {
                    for component in 0..3 {
                        rgba.push(self.rgb[*index as usize][component]);
                    }
                    rgba.push(0xFF);
                }
            }
        }

        rgba
    }
}

pub fn create_texture<F>(
    factory: &mut F,
    width: u32,
    height: u32,
    rgba: &[u8],
) -> Result<(Texture<Resources, R8_G8_B8_A8>, ShaderResourceView<Resources, [f32; 4]>), Error>
where
    F: gfx::Factory<Resources>
{
    ensure!((width * height * 4) as usize == rgba.len(), "Invalid dimensions for texture");
    let ret = factory.create_texture_immutable_u8::<ColorFormat>(
        gfx::texture::Kind::D2(width as u16, height as u16, gfx::texture::AaMode::Single),
        gfx::texture::Mipmap::Allocated,
        &[&rgba],
    )?;

    Ok(ret)
}
<commit_msg>Fix Camera pitch sign<commit_after>// Copyright © 2018 Cormac O'Brien
//
// 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.

pub mod alias;
pub mod bitmap;
pub mod brush;
pub mod hud;
pub mod world;

use std::collections::HashMap;

use client::Client;
use client::ClientEntity;
use common::model::Model;
use common::model::ModelKind;
use common::net::ItemFlags;
use common::net::MAX_ITEMS;
use common::pak::Pak;
use common::wad::Wad;

use cgmath::Deg;
use cgmath::Euler;
use cgmath::Matrix4;
use cgmath::Vector3;
use cgmath::Zero;
use chrono::Duration;
use failure::Error;
use flame;
use gfx;
use gfx::handle::ShaderResourceView;
use gfx::handle::Texture;
use gfx::format::R8_G8_B8_A8;
use gfx::pso::PipelineData;
use gfx::pso::PipelineState;
use gfx_device_gl::Factory;
use gfx_device_gl::Resources;

pub use gfx::format::Srgba8 as ColorFormat;
pub use gfx::format::DepthStencil as DepthFormat;

use self::alias::AliasRenderer;
use self::brush::BrushRenderer;
use self::hud::HudRenderer;
use self::world::WorldRenderer;

const PALETTE_SIZE: usize = 768;

// TODO: per-API coordinate system conversions
pub static VERTEX_SHADER_GLSL: &[u8] = br#"
#version 430

layout (location = 0) in vec3 a_Pos;
layout (location = 1) in vec2 a_Texcoord;

out vec2 f_texcoord;

uniform mat4 u_Transform;

void main() {
    f_texcoord = a_Texcoord;
    gl_Position = u_Transform * vec4(-a_Pos.y, a_Pos.z, -a_Pos.x, 1.0);
}
"#;

pub static FRAGMENT_SHADER_GLSL: &[u8] = br#"
#version 430

in vec2 f_texcoord;

uniform sampler2D u_Texture;

out vec4 Target0;

void main() {
    vec4 color = texture(u_Texture, f_texcoord);
    if (color.a == 0) {
        discard;
    } else {
        Target0 = color;
    }
}"#;

// TODO: per-API coordinate system conversions
pub static VERTEX_SHADER_2D_GLSL: &[u8] = br#"
#version 430

layout (location = 0) in vec2 a_Pos;
layout (location = 1) in vec2 a_Texcoord;

out vec2 f_texcoord;

uniform mat4 u_Transform;

void main() {
    f_texcoord = a_Texcoord;
    gl_Position = u_Transform * vec4(a_Pos.x, a_Pos.y, 0.0, 1.0);
}
"#;

pub static FRAGMENT_SHADER_2D_GLSL: &[u8] = br#"
#version 430

in vec2 f_texcoord;

uniform sampler2D u_Texture;

out vec4 Target0;

void main() {
    vec4 color = texture(u_Texture, f_texcoord);
    if (color.a == 0) {
        discard;
    } else {
        Target0 = color;
    }
}
"#;

gfx_defines! {
    vertex Vertex {
        pos: [f32; 3] = "a_Pos",
        texcoord: [f32; 2] = "a_Texcoord",
    }

    constant Locals {
        transform: [[f32; 4]; 4] = "u_Transform",
    }

    pipeline pipe {
        vertex_buffer: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        sampler: gfx::TextureSampler<[f32; 4]> = "u_Texture",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

gfx_defines! {
    vertex Vertex2d {
        pos: [f32; 2] = "a_Pos",
        texcoord: [f32; 2] = "a_Texcoord",
    }

    constant Locals2d {
        transform: [[f32; 4]; 4] = "u_Transform",
    }

    pipeline pipeline2d {
        vertex_buffer: gfx::VertexBuffer<Vertex2d> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        sampler: gfx::TextureSampler<[f32; 4]> = "u_Texture",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> = gfx::preset::depth::PASS_TEST,
    }
}

pub struct Camera {
    origin: Vector3<f32>,
    angles: Vector3<Deg<f32>>,
    projection: Matrix4<f32>,

    transform: Matrix4<f32>,
}

impl Camera {
    pub fn new(
        origin: Vector3<f32>,
        angles: Vector3<Deg<f32>>,
        projection: Matrix4<f32>,
    ) -> Camera {
        // negate the camera origin and angles
        // TODO: the OpenGL coordinate conversion is hardcoded here! XXX
        let converted_origin = Vector3::new(-origin.y, origin.z, -origin.x);
        let translation = Matrix4::from_translation(-converted_origin);
        let rotation = Matrix4::from(Euler::new(angles.x, -angles.y, -angles.z));

        Camera {
            origin,
            angles,
            projection,
            transform: projection * rotation * translation,
        }
    }

    pub fn get_origin(&self) -> Vector3<f32> {
        self.origin
    }

    pub fn get_transform(&self) -> Matrix4<f32> {
        self.transform
    }
}

pub struct SceneRenderer {
    pipeline: PipelineState<Resources, <pipe::Data<Resources> as PipelineData<Resources>>::Meta>,
    world_renderer: WorldRenderer,
    brush_renderers: HashMap<usize, BrushRenderer>,
    alias_renderers: HashMap<usize, AliasRenderer>,
    // spr_renderers: ...,
}

impl SceneRenderer {
    pub fn new(models: &[Model], worldmodel_id: usize, palette: &Palette, factory: &mut Factory) -> Result<SceneRenderer, Error>
    {
        use gfx::traits::FactoryExt;
        let shader_set = factory.create_shader_set(VERTEX_SHADER_GLSL, FRAGMENT_SHADER_GLSL).unwrap();

        let rasterizer = gfx::state::Rasterizer {
            front_face: gfx::state::FrontFace::Clockwise,
            cull_face: gfx::state::CullFace::Back,
            method: gfx::state::RasterMethod::Fill,
            offset: None,
            samples: Some(gfx::state::MultiSample),
        };

        let pipeline = factory.create_pipeline_state(
            &shader_set,
            gfx::Primitive::TriangleList,
            rasterizer,
            pipe::new(),
        ).unwrap();

        let mut maybe_world_renderer = None;
        let mut brush_renderers = HashMap::new();
        let mut alias_renderers = HashMap::new();
        for (i, model) in models.iter().enumerate() {
            if i == worldmodel_id {
                match *model.kind() {
                    ModelKind::Brush(ref bmodel) => {
                        debug!("model {}: world model", i);
                        maybe_world_renderer = Some(WorldRenderer::new(model.name(), &bmodel, palette, factory));
                    }

                    _ => bail!("Invalid kind for worldmodel"),
                }
            } else {
                match *model.kind() {
                    ModelKind::Brush(ref bmodel) => {
                        debug!("model {}: brush model", i);
                        brush_renderers.insert(i, BrushRenderer::new(model.name(), &bmodel, palette, factory));
                    }

                    ModelKind::Alias(ref amodel) => {
                        debug!("model {}: alias model", i);
                        alias_renderers.insert(i, AliasRenderer::new(&amodel, palette, factory)?);
                    },

                    // TODO handle sprite and null models
                    ModelKind::Sprite(_) => debug!("model {}: sprite model", i),
                    _ => (),
                }
            }
        }

        let world_renderer = match maybe_world_renderer {
            Some(w) => w,
            None => bail!("No worldmodel provided"),
        };

        Ok(SceneRenderer {
            pipeline,
            world_renderer,
            brush_renderers,
            alias_renderers
        })
    }

    #[flame]
    pub fn render<C>(
        &self,
        encoder: &mut gfx::Encoder<Resources, C>,
        user_data: &mut pipe::Data<Resources>,
        entities: &[ClientEntity],
        time: Duration,
        camera: &Camera,
    ) -> Result<(), Error>
    where
        C: gfx::CommandBuffer<Resources>,
    {
        flame::start("render_world");
        self.world_renderer.render(
            encoder,
            &self.pipeline,
            user_data,
            time,
            camera,
            Vector3::zero(),
            Vector3::new(Deg(0.0), Deg(0.0), Deg(0.0)),
        );
        flame::end("render_world");

        flame::start("render_entities");
        for ent in entities.iter() {
            let model_id = ent.get_model_id();
            if let Some(ref brush_renderer) = self.brush_renderers.get(&model_id) {
                brush_renderer.render(
                    encoder,
                    &self.pipeline,
                    user_data,
                    time,
                    camera,
                    ent.get_origin(),
                    ent.get_angles()
                );
            } else if let Some(ref alias_renderer) = self.alias_renderers.get(&model_id) {
                // TODO: pull keyframe and texture ID
                alias_renderer.render(
                    encoder,
                    &self.pipeline,
                    user_data,
                    time,
                    camera,
                    ent.get_origin(),
                    ent.get_angles(),
                    0,
                    0
                )?;
            }
        }
        flame::end("render_entities");

        Ok(())
    }
}

pub struct UiRenderer {
    pipeline: PipelineState<Resources, <pipeline2d::Data<Resources> as PipelineData<Resources>>::Meta>,
    hud_renderer: HudRenderer,
}

impl UiRenderer {
    pub fn new(
        gfx_wad: &Wad,
        palette: &Palette,
        factory: &mut Factory,
    ) -> Result<UiRenderer, Error> {
        use gfx::traits::FactoryExt;
        let shader_set = factory.create_shader_set(VERTEX_SHADER_2D_GLSL, FRAGMENT_SHADER_2D_GLSL).unwrap();

        let rasterizer = gfx::state::Rasterizer {
            front_face: gfx::state::FrontFace::Clockwise,
            cull_face: gfx::state::CullFace::Back,
            method: gfx::state::RasterMethod::Fill,
            offset: None,
            samples: Some(gfx::state::MultiSample),
        };

        let pipeline = factory.create_pipeline_state(
            &shader_set,
            gfx::Primitive::TriangleList,
            rasterizer,
            pipeline2d::new(),
        ).unwrap();

        let hud_renderer = HudRenderer::new(gfx_wad, palette, factory)?;

        Ok(UiRenderer {
            pipeline,
            hud_renderer,
        })
    }

    pub fn render<C>(
        &mut self,
        factory: &mut Factory,
        encoder: &mut gfx::Encoder<Resources, C>,
        user_data: &mut pipeline2d::Data<Resources>,
        client: &Client,
        display_width: u32,
        display_height: u32,
    ) -> Result<(), Error>
    where
        C: gfx::CommandBuffer<Resources>,
    {
        self.hud_renderer.render(factory, encoder, &self.pipeline, user_data, client, display_width, display_height)?;

        Ok(())
    }
}

pub struct Palette {
    rgb: [[u8; 3]; 256],
}

impl Palette {
    pub fn load<S>(pak: &Pak, path: S) -> Palette
    where
        S: AsRef<str>,
    {
        let data = pak.open(path).unwrap();
        assert_eq!(data.len(), PALETTE_SIZE);

        let mut rgb = [[0u8; 3]; 256];

        for color in 0..256 {
            for component in 0..3 {
                rgb[color][component] = data[color * 3 + component];
            }
        }

        Palette { rgb }
    }

    // TODO: this will not render console characters correctly, as they use index 0 (black) to
    // indicate transparency.
    pub fn indexed_to_rgba(&self, indices: &[u8]) -> Vec<u8> {
        let mut rgba = Vec::with_capacity(indices.len() * 4);

        for index in indices {
            match *index {
                0xFF => for i in 0..4 {
                    rgba.push(0);
                },

                _ => {
                    for component in 0..3 {
                        rgba.push(self.rgb[*index as usize][component]);
                    }
                    rgba.push(0xFF);
                }
            }
        }

        rgba
    }
}

pub fn create_texture<F>(
    factory: &mut F,
    width: u32,
    height: u32,
    rgba: &[u8],
) -> Result<(Texture<Resources, R8_G8_B8_A8>, ShaderResourceView<Resources, [f32; 4]>), Error>
where
    F: gfx::Factory<Resources>
{
    ensure!((width * height * 4) as usize == rgba.len(), "Invalid dimensions for texture");
    let ret = factory.create_texture_immutable_u8::<ColorFormat>(
        gfx::texture::Kind::D2(width as u16, height as u16, gfx::texture::AaMode::Single),
        gfx::texture::Mipmap::Allocated,
        &[&rgba],
    )?;

    Ok(ret)
}
<|endoftext|>


<commit_before>// -*- rust -*-

import front.creader;
import front.parser;
import front.token;
import front.eval;
import middle.trans;
import middle.resolve;
import middle.ty;
import middle.typeck;
import middle.typestate_check;
import util.common;

import std.map.mk_hashmap;
import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

fn default_environment(session.session sess,
                       str argv0,
                       str input) -> eval.env {

    auto libc = "libc.so";
    alt (sess.get_targ_cfg().os) {
        case (session.os_win32) { libc = "msvcrt.dll"; }
        case (session.os_macos) { libc = "libc.dylib"; }
        case (session.os_linux) { libc = "libc.so.6"; }
    }

    ret
        vec(
            // Target bindings.
            tup("target_os", eval.val_str(std.os.target_os())),
            tup("target_arch", eval.val_str("x86")),
            tup("target_libc", eval.val_str(libc)),

            // Build bindings.
            tup("build_compiler", eval.val_str(argv0)),
            tup("build_input", eval.val_str(input))
            );
}

impure fn parse_input(session.session sess,
                      parser.parser p,
                      str input) -> @front.ast.crate {
    if (_str.ends_with(input, ".rc")) {
        ret parser.parse_crate_from_crate_file(p);
    } else if (_str.ends_with(input, ".rs")) {
        ret parser.parse_crate_from_source_file(p);
    }
    sess.err("unknown input file type: " + input);
    fail;
}

impure fn compile_input(session.session sess,
                        eval.env env,
                        str input, str output,
                        bool shared,
                        bool optimize,
                        vec[str] library_search_paths) {
    auto def = tup(0, 0);
    auto p = parser.new_parser(sess, env, def, input);
    auto crate = parse_input(sess, p, input);
    crate = creader.read_crates(sess, crate, library_search_paths);
    crate = resolve.resolve_crate(sess, crate);
    auto typeck_result = typeck.check_crate(sess, crate);
    crate = typeck_result._0;
    auto type_cache = typeck_result._1;
    // FIXME: uncomment once typestate_check works
    // crate = typestate_check.check_crate(crate);
    trans.trans_crate(sess, crate, type_cache, output, shared, optimize);
}

impure fn pretty_print_input(session.session sess,
                             eval.env env,
                             str input) {
    auto def = tup(0, 0);
    auto p = front.parser.new_parser(sess, env, def, input);
    auto crate = front.parser.parse_crate_from_source_file(p);
    pretty.pprust.print_file(crate.node.module, input, std.io.stdout());
}

fn warn_wrong_compiler() {
    log "This is the rust 'self-hosted' compiler.";
    log "The one written in rust.";
    log "It is currently incomplete.";
    log "You may want rustboot instead, the compiler next door.";
}

fn usage(session.session sess, str argv0) {
    log #fmt("usage: %s [options] <input>", argv0);
    log "options:";
    log "";
    log "    -o <filename>      write output to <filename>";
    log "    -nowarn            suppress wrong-compiler warning";
    log "    -glue              generate glue.bc file";
    log "    -shared            compile a shared-library crate";
    log "    -pp                pretty-print the input instead of compiling";
    log "    -ls                list the symbols defined by a crate file";
    log "    -L <path>          add a directory to the library search path";
    log "    -h                 display this message";
    log "";
    log "";
}

fn get_os() -> session.os {
    auto s = std.os.target_os();
    if (_str.eq(s, "win32")) { ret session.os_win32; }
    if (_str.eq(s, "macos")) { ret session.os_macos; }
    if (_str.eq(s, "linux")) { ret session.os_linux; }
}

impure fn main(vec[str] args) {

    // FIXME: don't hard-wire this.
    auto target_cfg = rec(os = get_os(),
                          arch = session.arch_x86,
                          int_type = common.ty_i32,
                          uint_type = common.ty_u32,
                          float_type = common.ty_f64 );

    auto crate_cache = common.new_int_hash[session.crate_metadata]();
    auto target_crate_num = 0;
    auto sess = session.session(target_crate_num, target_cfg, crate_cache);

    let option.t[str] input_file = none[str];
    let option.t[str] output_file = none[str];
    let vec[str] library_search_paths = vec();
    let bool do_warn = true;
    let bool shared = false;
    let bool pretty = false;
    let bool ls = false;
    let bool glue = false;

    // FIXME: Maybe we should support -O0, -O1, -Os, etc
    let bool optimize = false;

    auto i = 1u;
    auto len = _vec.len[str](args);

    // FIXME: a getopt module would be nice.
    while (i < len) {
        auto arg = args.(i);
        if (_str.byte_len(arg) > 0u && arg.(0) == '-' as u8) {
            if (_str.eq(arg, "-nowarn")) {
                do_warn = false;
            } else if (_str.eq(arg, "-O")) {
                optimize = true;
            } else if (_str.eq(arg, "-glue")) {
                glue = true;
            } else if (_str.eq(arg, "-shared")) {
                shared = true;
            } else if (_str.eq(arg, "-pp")) {
                pretty = true;
            } else if (_str.eq(arg, "-ls")) {
                ls = true;
            } else if (_str.eq(arg, "-o")) {
                if (i+1u < len) {
                    output_file = some(args.(i+1u));
                    i += 1u;
                } else {
                    usage(sess, args.(0));
                    sess.err("-o requires an argument");
                }
            } else if (_str.eq(arg, "-L")) {
                if (i+1u < len) {
                    library_search_paths += vec(args.(i+1u));
                    i += 1u;
                } else {
                    usage(sess, args.(0));
                    sess.err("-L requires an argument");
                }
            } else if (_str.eq(arg, "-h")) {
                usage(sess, args.(0));
            } else {
                usage(sess, args.(0));
                sess.err("unrecognized option: " + arg);
            }
        } else {
            alt (input_file) {
                case (some[str](_)) {
                    usage(sess, args.(0));
                    sess.err("multiple inputs provided");
                }
                case (none[str]) {
                    input_file = some[str](arg);
                }
            }
        }
        i += 1u;
    }

    if (do_warn) {
        warn_wrong_compiler();
    }

    if (glue) {
        alt (output_file) {
            case (none[str]) {
                middle.trans.make_common_glue("glue.bc", optimize);
            }
            case (some[str](?s)) {
                middle.trans.make_common_glue(s, optimize);
            }
        }
        ret;
    }

    alt (input_file) {
        case (none[str]) {
            usage(sess, args.(0));
            sess.err("no input filename");
        }
        case (some[str](?ifile)) {

            auto env = default_environment(sess, args.(0), ifile);
            if (pretty) {
                pretty_print_input(sess, env, ifile);
            } else if (ls) {
                front.creader.list_file_metadata(ifile, std.io.stdout());
            } else {
                alt (output_file) {
                    case (none[str]) {
                        let vec[str] parts = _str.split(ifile, '.' as u8);
                        _vec.pop[str](parts);
                        parts += vec(".bc");
                        auto ofile = _str.concat(parts);
                        compile_input(sess, env, ifile, ofile, shared,
                                      optimize, library_search_paths);
                    }
                    case (some[str](?ofile)) {
                        compile_input(sess, env, ifile, ofile, shared,
                                      optimize, library_search_paths);
                    }
                }
            }
        }
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>add a -parse-only option to rustc<commit_after>// -*- rust -*-

import front.creader;
import front.parser;
import front.token;
import front.eval;
import middle.trans;
import middle.resolve;
import middle.ty;
import middle.typeck;
import middle.typestate_check;
import util.common;

import std.map.mk_hashmap;
import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

fn default_environment(session.session sess,
                       str argv0,
                       str input) -> eval.env {

    auto libc = "libc.so";
    alt (sess.get_targ_cfg().os) {
        case (session.os_win32) { libc = "msvcrt.dll"; }
        case (session.os_macos) { libc = "libc.dylib"; }
        case (session.os_linux) { libc = "libc.so.6"; }
    }

    ret
        vec(
            // Target bindings.
            tup("target_os", eval.val_str(std.os.target_os())),
            tup("target_arch", eval.val_str("x86")),
            tup("target_libc", eval.val_str(libc)),

            // Build bindings.
            tup("build_compiler", eval.val_str(argv0)),
            tup("build_input", eval.val_str(input))
            );
}

impure fn parse_input(session.session sess,
                      parser.parser p,
                      str input) -> @front.ast.crate {
    if (_str.ends_with(input, ".rc")) {
        ret parser.parse_crate_from_crate_file(p);
    } else if (_str.ends_with(input, ".rs")) {
        ret parser.parse_crate_from_source_file(p);
    }
    sess.err("unknown input file type: " + input);
    fail;
}

impure fn compile_input(session.session sess,
                        eval.env env,
                        str input, str output,
                        bool shared,
                        bool optimize,
                        bool parse_only,
                        vec[str] library_search_paths) {
    auto def = tup(0, 0);
    auto p = parser.new_parser(sess, env, def, input);
    auto crate = parse_input(sess, p, input);
    if (parse_only) {ret;}
    crate = creader.read_crates(sess, crate, library_search_paths);
    crate = resolve.resolve_crate(sess, crate);
    auto typeck_result = typeck.check_crate(sess, crate);
    crate = typeck_result._0;
    auto type_cache = typeck_result._1;
    // FIXME: uncomment once typestate_check works
    // crate = typestate_check.check_crate(crate);
    trans.trans_crate(sess, crate, type_cache, output, shared, optimize);
}

impure fn pretty_print_input(session.session sess,
                             eval.env env,
                             str input) {
    auto def = tup(0, 0);
    auto p = front.parser.new_parser(sess, env, def, input);
    auto crate = front.parser.parse_crate_from_source_file(p);
    pretty.pprust.print_file(crate.node.module, input, std.io.stdout());
}

fn warn_wrong_compiler() {
    log "This is the rust 'self-hosted' compiler.";
    log "The one written in rust.";
    log "It is currently incomplete.";
    log "You may want rustboot instead, the compiler next door.";
}

fn usage(session.session sess, str argv0) {
    log #fmt("usage: %s [options] <input>", argv0);
    log "options:";
    log "";
    log "    -o <filename>      write output to <filename>";
    log "    -nowarn            suppress wrong-compiler warning";
    log "    -glue              generate glue.bc file";
    log "    -shared            compile a shared-library crate";
    log "    -pp                pretty-print the input instead of compiling";
    log "    -ls                list the symbols defined by a crate file";
    log "    -L <path>          add a directory to the library search path";
    log "    -h                 display this message";
    log "";
    log "";
}

fn get_os() -> session.os {
    auto s = std.os.target_os();
    if (_str.eq(s, "win32")) { ret session.os_win32; }
    if (_str.eq(s, "macos")) { ret session.os_macos; }
    if (_str.eq(s, "linux")) { ret session.os_linux; }
}

impure fn main(vec[str] args) {

    // FIXME: don't hard-wire this.
    auto target_cfg = rec(os = get_os(),
                          arch = session.arch_x86,
                          int_type = common.ty_i32,
                          uint_type = common.ty_u32,
                          float_type = common.ty_f64 );

    auto crate_cache = common.new_int_hash[session.crate_metadata]();
    auto target_crate_num = 0;
    auto sess = session.session(target_crate_num, target_cfg, crate_cache);

    let option.t[str] input_file = none[str];
    let option.t[str] output_file = none[str];
    let vec[str] library_search_paths = vec();
    let bool do_warn = true;
    let bool shared = false;
    let bool pretty = false;
    let bool ls = false;
    let bool parse_only = false;
    let bool glue = false;

    // FIXME: Maybe we should support -O0, -O1, -Os, etc
    let bool optimize = false;

    auto i = 1u;
    auto len = _vec.len[str](args);

    // FIXME: a getopt module would be nice.
    while (i < len) {
        auto arg = args.(i);
        if (_str.byte_len(arg) > 0u && arg.(0) == '-' as u8) {
            if (_str.eq(arg, "-nowarn")) {
                do_warn = false;
            } else if (_str.eq(arg, "-O")) {
                optimize = true;
            } else if (_str.eq(arg, "-glue")) {
                glue = true;
            } else if (_str.eq(arg, "-shared")) {
                shared = true;
            } else if (_str.eq(arg, "-pp")) {
                pretty = true;
            } else if (_str.eq(arg, "-ls")) {
                ls = true;
            } else if (_str.eq(arg, "-parse-only")) {
                parse_only = true;
            } else if (_str.eq(arg, "-o")) {
                if (i+1u < len) {
                    output_file = some(args.(i+1u));
                    i += 1u;
                } else {
                    usage(sess, args.(0));
                    sess.err("-o requires an argument");
                }
            } else if (_str.eq(arg, "-L")) {
                if (i+1u < len) {
                    library_search_paths += vec(args.(i+1u));
                    i += 1u;
                } else {
                    usage(sess, args.(0));
                    sess.err("-L requires an argument");
                }
            } else if (_str.eq(arg, "-h")) {
                usage(sess, args.(0));
            } else {
                usage(sess, args.(0));
                sess.err("unrecognized option: " + arg);
            }
        } else {
            alt (input_file) {
                case (some[str](_)) {
                    usage(sess, args.(0));
                    sess.err("multiple inputs provided");
                }
                case (none[str]) {
                    input_file = some[str](arg);
                }
            }
        }
        i += 1u;
    }

    if (do_warn) {
        warn_wrong_compiler();
    }

    if (glue) {
        alt (output_file) {
            case (none[str]) {
                middle.trans.make_common_glue("glue.bc", optimize);
            }
            case (some[str](?s)) {
                middle.trans.make_common_glue(s, optimize);
            }
        }
        ret;
    }

    alt (input_file) {
        case (none[str]) {
            usage(sess, args.(0));
            sess.err("no input filename");
        }
        case (some[str](?ifile)) {

            auto env = default_environment(sess, args.(0), ifile);
            if (pretty) {
                pretty_print_input(sess, env, ifile);
            } else if (ls) {
                front.creader.list_file_metadata(ifile, std.io.stdout());
            } else {
                alt (output_file) {
                    case (none[str]) {
                        let vec[str] parts = _str.split(ifile, '.' as u8);
                        _vec.pop[str](parts);
                        parts += vec(".bc");
                        auto ofile = _str.concat(parts);
                        compile_input(sess, env, ifile, ofile, shared,
                                      optimize, parse_only,
                                      library_search_paths);
                    }
                    case (some[str](?ofile)) {
                        compile_input(sess, env, ifile, ofile, shared,
                                      optimize, parse_only,
                                      library_search_paths);
                    }
                }
            }
        }
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>extern crate tokio_proto;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate macro_attr;

use varlink::server::{Proto, VarlinkService};
use tokio_proto::TcpServer;
use std::sync::{Arc, RwLock};

extern crate varlink;

#[macro_use]
mod io_systemd_network {
    /*
    varlink_server! (r#"
    # Provides information about network state
	interface io.systemd.network

	type NetdevInfo (
	  ifindex: int,
	  ifname: string
	)

	type Netdev (
	  ifindex: int,
	  ifname: string
	)

	# Returns information about a network device
	method Info(ifindex: int) -> (info: NetdevInfo)

	# Lists all network devices
	method List() -> (netdevs: Netdev[])

	error UnknownNetworkDevice
	error InvalidParameter
    "#);
    */

    // will be autogenerated by the above macro in the future
    include!("io_systemd_network/mod.rs");

}

use io_systemd_network::*;

macro_attr! { #[derive(IoSystemdNetwork!)]
struct MyServer {
    pub state: Arc<RwLock<i64>>,
}}

impl Interface for MyServer {
    fn info(&self, i: i64) -> Result<InfoReply, Error> {
        // State example
        {
            let mut number = self.state.write().unwrap();

            *number += 1;

            println!("{}", *number);
        }

        match i {
            1 => {
                Ok(InfoReply {
                       info: NetdevInfo {
                           ifindex: 1,
                           ifname: "lo".into(),
                       },
                   })
            }
            2 => {
                Ok(InfoReply {
                       info: NetdevInfo {
                           ifindex: 2,
                           ifname: "eth0".into(),
                       },
                   })
            }
            _ => Err(Error::UnknownNetworkDevice),
        }
    }

    fn list(&self) -> Result<ListReply, Error> {
        // State example
        {
            let mut number = self.state.write().unwrap();

            *number -= 1;

            println!("{}", *number);
        }
        Ok(ListReply {
               netdevs: vec![Netdev {
                                 ifindex: 1,
                                 ifname: "lo".into(),
                             },
                             Netdev {
                                 ifindex: 2,
                                 ifname: "eth0".into(),
                             }],
           })
    }
}

fn main() {
    // Specify the localhost address
    let addr = "0.0.0.0:12345".parse().unwrap();

    // The builder requires a protocol and an address
    let server = TcpServer::new(Proto, addr);

    let state = Arc::new(RwLock::new(0));

    println!("Listening on {}", addr);

    // We provide a way to *instantiate* the service for each new
    // connection; here, we just immediately return a new instance.
    server.serve(move || {
        println!("New Server");
        let iosystemdnetwork = MyServer { state: state.clone() };
        Ok(VarlinkService::new("org.varlink".into(),
                               "test service".into(),
                               "0.1".into(),
                               "http://varlink.org".into(),
                               vec![Box::new(iosystemdnetwork)]))
    });
}
<commit_msg>examples/server.rs: update macro comment<commit_after>extern crate tokio_proto;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate macro_attr;

extern crate varlink;

use varlink::server::{Proto, VarlinkService};
use tokio_proto::TcpServer;
use std::sync::{Arc, RwLock};

#[macro_use]
mod io_systemd_network {
    /*
    varlink_server! (r#"
# Provides information about network state
interface io.systemd.network

type NetdevInfo (
  ifindex: int,
  ifname: string
)

type Netdev (
  ifindex: int,
  ifname: string
)

# Returns information about a network device
method Info(ifindex: int) -> (info: NetdevInfo)

# Lists all network devices
method List() -> (netdevs: Netdev[])

error UnknownNetworkDevice ()
error InvalidParameter (field: string)
    "#);
    */

    // will be autogenerated by the above macro in the future
    include!("io_systemd_network/mod.rs");

}

use io_systemd_network::*;

macro_attr! { #[derive(IoSystemdNetwork!)]
struct MyServer {
    pub state: Arc<RwLock<i64>>,
}}

impl Interface for MyServer {
    fn info(&self, i: i64) -> Result<InfoReply, Error> {
        // State example
        {
            let mut number = self.state.write().unwrap();

            *number += 1;

            println!("{}", *number);
        }

        match i {
            1 => {
                Ok(InfoReply {
                       info: NetdevInfo {
                           ifindex: 1,
                           ifname: "lo".into(),
                       },
                   })
            }
            2 => {
                Ok(InfoReply {
                       info: NetdevInfo {
                           ifindex: 2,
                           ifname: "eth0".into(),
                       },
                   })
            }
            _ => Err(Error::UnknownNetworkDevice),
        }
    }

    fn list(&self) -> Result<ListReply, Error> {
        // State example
        {
            let mut number = self.state.write().unwrap();

            *number -= 1;

            println!("{}", *number);
        }
        Ok(ListReply {
               netdevs: vec![Netdev {
                                 ifindex: 1,
                                 ifname: "lo".into(),
                             },
                             Netdev {
                                 ifindex: 2,
                                 ifname: "eth0".into(),
                             }],
           })
    }
}

fn main() {
    // Specify the localhost address
    let addr = "0.0.0.0:12345".parse().unwrap();

    // The builder requires a protocol and an address
    let server = TcpServer::new(Proto, addr);

    let state = Arc::new(RwLock::new(0));

    println!("Listening on {}", addr);

    // We provide a way to *instantiate* the service for each new
    // connection; here, we just immediately return a new instance.
    server.serve(move || {
        println!("New Server");
        let iosystemdnetwork = MyServer { state: state.clone() };
        Ok(VarlinkService::new("org.varlink".into(),
                               "test service".into(),
                               "0.1".into(),
                               "http://varlink.org".into(),
                               vec![Box::new(iosystemdnetwork)]))
    });
}
<|endoftext|>


<commit_before>extern crate glutin;

mod support;

fn main() {
    let events_loop = glutin::winit::EventsLoop::new();
    let window = glutin::winit::WindowBuilder::new()
        .with_title("A fantastic window!")
        .build(&events_loop)
        .unwrap();
    let context = glutin::ContextBuilder::new()
        .build(&window)
        .unwrap();

    let _ = unsafe { context.make_current() };

    println!("Pixel format of the window's GL context: {:?}", context.get_pixel_format());

    let gl = support::load(&context);

    events_loop.run_forever(|event| {
        println!("{:?}", event);

        gl.draw_frame((0.0, 1.0, 0.0, 1.0));
        let _ = context.swap_buffers();

        match event {
            glutin::winit::Event::WindowEvent { event, .. } => match event {
                glutin::winit::WindowEvent::Closed => events_loop.interrupt(),
                glutin::winit::WindowEvent::Resized(w, h) => context.resize(w, h),
                _ => (),
            },
            _ => ()
        }
    });
}
<commit_msg>Ensure that the context is resized before the window is drawn in window example<commit_after>extern crate glutin;

mod support;

fn main() {
    let events_loop = glutin::winit::EventsLoop::new();
    let window = glutin::winit::WindowBuilder::new()
        .with_title("A fantastic window!")
        .build(&events_loop)
        .unwrap();
    let context = glutin::ContextBuilder::new()
        .build(&window)
        .unwrap();

    let _ = unsafe { context.make_current() };

    println!("Pixel format of the window's GL context: {:?}", context.get_pixel_format());

    let gl = support::load(&context);

    events_loop.run_forever(|event| {
        println!("{:?}", event);
        match event {
            glutin::winit::Event::WindowEvent { event, .. } => match event {
                glutin::winit::WindowEvent::Closed => events_loop.interrupt(),
                glutin::winit::WindowEvent::Resized(w, h) => context.resize(w, h),
                _ => (),
            },
            _ => ()
        }

        gl.draw_frame((0.0, 1.0, 0.0, 1.0));
        let _ = context.swap_buffers();
    });
}
<|endoftext|>


<commit_before>use bus::busmatrix::BusMatrix;
use bus::internal::InternalBus;
use bus::ahblite::AHBLite;
use core::Core;
use core::instruction::Instruction;
use core::register::Reg;
use memory::flash::FlashMemory;
use memory::ram::RAM;
use semihosting::SemihostingResponse;
use semihosting::SemihostingCommand;

pub fn cortex_m0_simulate<F, G>(code: &[u8], mut trace_func: F, mut semihost_func: G) -> u64
where
    F: FnMut(u64, u32, &Instruction),
    G: FnMut(&SemihostingCommand) -> SemihostingResponse,
{
    let mut flash_memory = FlashMemory::new(0, 32768);
    let mut ram_memory = RAM::new(0x2000_0000, 128 * 1024);

    flash_memory.load(code);

    let mut internal_bus = InternalBus::new();
    let mut ahb = AHBLite::new(&mut flash_memory, &mut ram_memory);
    let mut bus = BusMatrix::new(&mut internal_bus, &mut ahb);

    let mut core = Core::new(&mut bus);
    let mut count = 0;
    core.reset();

    let mut instruction_cache = Vec::new();
    // pre-cache the decoded instructions

    {
        let mut pc = 0;
        core.set_r(&Reg::PC, pc);

        while pc < (code.len() as u32 / 2) {
            let thumb = core.fetch();
            let instruction = core.decode(&thumb);
            instruction_cache.push(instruction);
            pc += 2;
            core.set_r(&Reg::PC, pc);
        }
    }

    core.reset();
    while core.running {
        let pc = core.get_pc();
        let instruction = &instruction_cache[(pc >> 1) as usize];

        core.step(
            instruction,
            |semihost_cmd: &SemihostingCommand| -> SemihostingResponse {
                semihost_func(semihost_cmd)
            },
        );
        trace_func(count, pc, instruction);
        count += 1;
    }
    count
}
<commit_msg>bugfix: not all of code was properly cached<commit_after>use bus::busmatrix::BusMatrix;
use bus::internal::InternalBus;
use bus::ahblite::AHBLite;
use core::Core;
use core::instruction::Instruction;
use core::register::Reg;
use memory::flash::FlashMemory;
use memory::ram::RAM;
use semihosting::SemihostingResponse;
use semihosting::SemihostingCommand;

pub fn cortex_m0_simulate<F, G>(code: &[u8], mut trace_func: F, mut semihost_func: G) -> u64
where
    F: FnMut(u64, u32, &Instruction),
    G: FnMut(&SemihostingCommand) -> SemihostingResponse,
{
    let mut flash_memory = FlashMemory::new(0, 32768);
    let mut ram_memory = RAM::new(0x2000_0000, 128 * 1024);

    flash_memory.load(code);

    let mut internal_bus = InternalBus::new();
    let mut ahb = AHBLite::new(&mut flash_memory, &mut ram_memory);
    let mut bus = BusMatrix::new(&mut internal_bus, &mut ahb);

    let mut core = Core::new(&mut bus);
    let mut count = 0;
    core.reset();

    let mut instruction_cache = Vec::new();
    // pre-cache the decoded instructions

    {
        let mut pc = 0;
        core.set_r(&Reg::PC, pc);

        while pc < (code.len() as u32) {
            let thumb = core.fetch();
            let instruction = core.decode(&thumb);
            instruction_cache.push(instruction);
            pc += 2;
            core.set_r(&Reg::PC, pc);
        }
    }

    core.reset();
    while core.running {
        let pc = core.get_pc();
        let instruction = &instruction_cache[(pc >> 1) as usize];

        core.step(
            instruction,
            |semihost_cmd: &SemihostingCommand| -> SemihostingResponse {
                semihost_func(semihost_cmd)
            },
        );
        trace_func(count, pc, instruction);
        count += 1;
    }
    count
}
<|endoftext|>


<commit_before><commit_msg>simplify BTree::{ stem_align, leaf_align }<commit_after><|endoftext|>


<commit_before><commit_msg>Use correct cfg_attr syntax for i686<commit_after><|endoftext|>


<commit_before><commit_msg>Better binding names in `config::load`.<commit_after><|endoftext|>


<commit_before><commit_msg>Fixes DTD parser issue resulting in `ExpectedClosingQuote` error.<commit_after><|endoftext|>


<commit_before>//! # Socket code around `libc`
//!
//! ## Notes
//!
//! This module provides a low level one-to-one mapping between `libc` system call wrappers
//! with defaults specific to netlink sockets as well as a higher level API for simplification
//! of netlink code.

use std::io;
use std::os::unix::io::{AsRawFd,IntoRawFd,RawFd};
use std::marker::PhantomData;
use std::mem::{zeroed,size_of};

use buffering::copy::{StreamReadBuffer,StreamWriteBuffer};
use libc::{self,c_int,c_void};
#[cfg(feature = "evented")]
use mio::{self,Evented};
#[cfg(feature = "stream")]
use tokio::io::AsyncRead;
#[cfg(feature = "stream")]
use tokio::prelude::{Async,Stream};

use {Nl,MAX_NL_LENGTH};
use err::{NlError,Nlmsgerr};
use ffi::{self,NlFamily,GenlId,CtrlCmd,CtrlAttr,CtrlAttrMcastGrp,NlmF};
use genlhdr::GenlHdr;
use nlattr::NlAttrHdr;
use nlhdr::NlHdr;

/// Handle for the socket file descriptor
#[cfg(feature = "evented")]
pub struct NlSocket<T, P> {
    fd: c_int,
    poll: mio::Poll,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

/// Handle for the socket file descriptor
#[cfg(not(feature = "evented"))]
pub struct NlSocket<T, P> {
    fd: c_int,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

impl<T, P> NlSocket<T, P> where T: Nl, P: Nl {
    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(feature = "evented")]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        let poll = mio::Poll::new()?;
        let socket = NlSocket { fd, poll, data_type: PhantomData, data_payload: PhantomData };
        socket.register(&socket.poll, mio::Token(0), mio::Ready::readable(), mio::PollOpt::edge())?;
        Ok(socket)
    }

    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(not(feature = "evented"))]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        Ok(NlSocket { fd, data_type: PhantomData, data_payload: PhantomData })
    }

    /// Set underlying socket file descriptor to be blocking
    pub fn block(&mut self) -> Result<&mut Self, io::Error> {
        match unsafe { libc::fcntl(self.fd, libc::F_SETFL,
                                   libc::fcntl(self.fd, libc::F_GETFL, 0) & !libc::O_NONBLOCK) } {
            i if i < 0 => return Err(io::Error::last_os_error()),
            _ => Ok(self),
        }
    }

    /// Set underlying socket file descriptor to be non blocking
    pub fn nonblock(&mut self) -> Result<&mut Self, io::Error> {
        match unsafe { libc::fcntl(self.fd, libc::F_SETFL,
                                   libc::fcntl(self.fd, libc::F_GETFL, 0) | libc::O_NONBLOCK) } {
            i if i < 0 => return Err(io::Error::last_os_error()),
            _ => Ok(self),
        }
    }

    /// Determines if underlying file descriptor is blocking - `Stream` feature will throw an
    /// error if this function returns false
    pub fn is_blocking(&self) -> Result<bool, io::Error> {
        let is_blocking = match unsafe { libc::fcntl(self.fd, libc::F_GETFL, 0) } {
            i if i >= 0 => i & libc::O_NONBLOCK == 0,
            _ => return Err(io::Error::last_os_error()),
        };
        Ok(is_blocking)
    }

    /// Use this function to bind to a netlink ID and subscribe to groups. See netlink(7)
    /// man pages for more information on netlink IDs and groups.
    pub fn bind(&mut self, pid: Option<u32>, groups: Vec<u32>) -> Result<(), io::Error> {
        let mut nladdr = unsafe { zeroed::<libc::sockaddr_nl>() };
        nladdr.nl_family = libc::AF_NETLINK as u16;
        nladdr.nl_pid = pid.unwrap_or(0);
        nladdr.nl_groups = groups.into_iter().fold(0, |acc, next| {
            acc | (1 << (next - 1))
        });
        match unsafe {
            libc::bind(self.fd, &nladdr as *const _ as *const libc::sockaddr,
                       size_of::<libc::sockaddr_nl>() as u32)
        } {
            i if i >= 0 => Ok(()),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Send message encoded as byte slice to the netlink ID specified in the netlink header
    /// (`neli::nlhdr::NlHdr`)
    pub fn send<B>(&mut self, buf: StreamReadBuffer<B>, flags: i32) -> Result<isize, io::Error>
            where B: AsRef<[u8]> {
        match unsafe {
            libc::send(self.fd, buf.as_ref() as *const _ as *const c_void, buf.as_ref().len(), flags)
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to send an `NlHdr` struct
    pub fn send_nl(&mut self, msg: NlHdr<T, P>) -> Result<(), NlError> {
        let mut mem = StreamWriteBuffer::new_growable(Some(msg.asize()));
        msg.serialize(&mut mem)?;
        self.send(StreamReadBuffer::new(mem), 0)?;
        Ok(())
    }

    /// Receive message encoded as byte slice from the netlink socket
    pub fn recv<'a>(&mut self, mut buf: StreamWriteBuffer<'a>, flags: i32)
            -> Result<StreamReadBuffer<StreamWriteBuffer<'a>>, io::Error> {
        match unsafe {
            libc::recv(self.fd, buf.as_mut() as *mut _ as *mut c_void, buf.as_mut().len(), flags)
        } {
            i if i >= 0 => {
                unsafe { buf.set_bytes_written(i as usize) };
                Ok(StreamReadBuffer::new(buf))
            },
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to receive an `NlHdr` struct
    pub fn recv_nl(&mut self, buf_sz: Option<usize>) -> Result<NlHdr<T, P>, NlError> {
        let mem_write = StreamWriteBuffer::new_growable(buf_sz.or(Some(MAX_NL_LENGTH)));
        let mut mem_read = self.recv(mem_write, 0)?;
        Ok(NlHdr::<T, P>::deserialize(&mut mem_read)?)
    }

    /// Convenience function to receive an `NlHdr` struct with function type parameters
    /// that determine deserialization type
    pub fn recv_nl_typed<TT, PP>(&mut self, buf_sz: Option<usize>)
            -> Result<NlHdr<TT, PP>, NlError> where TT: Nl + Into<u16> + From<u16>, PP: Nl {
        let mem_write = StreamWriteBuffer::new_growable(buf_sz.or(Some(MAX_NL_LENGTH)));
        let mut mem_read = self.recv(mem_write, 0)?;
        Ok(NlHdr::<TT, PP>::deserialize(&mut mem_read)?)
    }

    /// Consume an ACK and return an error if an ACK is not found
    pub fn recv_ack(&mut self, buf_sz: Option<usize>) -> Result<(), NlError> {
        let ack = self.recv_nl_typed::<ffi::Nlmsg, Nlmsgerr<ffi::Nlmsg>>(buf_sz)?;
        if ack.nl_type == ffi::Nlmsg::Error && ack.nl_payload.error == 0 {
            Ok(())
        } else {
            Err(NlError::NoAck)
        }
    }

    /// Equivalent of `socket` and `bind` calls.
    pub fn connect(proto: NlFamily, pid: Option<u32>, groups: Vec<u32>)
                   -> Result<Self, io::Error> {
        let mut s = try!(NlSocket::new(proto));
        try!(s.bind(pid, groups));
        Ok(s)
    }
}

impl NlSocket<GenlId, GenlHdr<CtrlCmd>> {
    /// Create generic netlink resolution socket
    pub fn new_genl() -> Result<NlSocket<GenlId, GenlHdr<CtrlCmd>>, io::Error> {
        Self::connect(NlFamily::Generic, None, Vec::new())
    }

    fn get_genl_family(&mut self, family_name: &str)
            -> Result<NlHdr<GenlId, GenlHdr<CtrlCmd>>, NlError> {
        let attrs = vec![NlAttrHdr::new_str_payload(None, CtrlAttr::FamilyName, family_name)?];
        let genlhdr = GenlHdr::new(CtrlCmd::Getfamily, 2, attrs)?;
        let nlhdr = NlHdr::new(None, GenlId::Ctrl,
                               vec![NlmF::Request], None, None, genlhdr);
        self.send_nl(nlhdr)?;

        Ok(self.recv_nl(Some(4096))?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_genl_family(&mut self, family_name: &str) -> Result<u16, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        Ok(handle.get_payload_with::<u16>(CtrlAttr::FamilyId, None)?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_nl_mcast_group(&mut self, family_name: &str, mcast_name: &str)
            -> Result<u32, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        let mut mcast_groups = handle.get_nested_attributes::<u16>(CtrlAttr::McastGroups)?;
        mcast_groups.parse_nested_attributes()?;
        let mut id = None;
        if let Some(iter) = mcast_groups.iter() {
            for attribute in iter {
                let attribute_len = attribute.nla_len;
                let mut handle = attribute.get_attr_handle();
                let string = handle.get_payload_with::<String>(CtrlAttrMcastGrp::Name,
                    Some(attribute_len as usize))?;
                if string.as_str() == mcast_name {
                    id = handle.get_payload_with::<u32>(CtrlAttrMcastGrp::Id, None).ok();
                }
            }
        }
        id.ok_or(NlError::new("Failed to resolve multicast group ID"))
    }
}

impl<T, P> AsRawFd for NlSocket<T, P> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl<T, P> IntoRawFd for NlSocket<T, P> {
    fn into_raw_fd(self) -> RawFd {
        self.fd
    }
}

impl<T, P> io::Read for NlSocket<T, P> where T: Nl, P: Nl {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match unsafe {
            libc::recv(self.fd, buf as *mut _ as *mut c_void, buf.len(), 0)
        } {
            i if i >= 0 => Ok(i as usize),
            _ => Err(io::Error::last_os_error()),
        }
    }
}

#[cfg(feature = "stream")]
impl<T, P> AsyncRead for NlSocket<T, P> where T: Nl, P: Nl { }

#[cfg(feature = "stream")]
impl<T, P> Stream for NlSocket<T, P> where T: Nl, P: Nl {
    type Item = NlHdr<T, P>;
    type Error = ();

    fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
        if !self.is_blocking().map_err(|_| ())? {
            return Err(());
        }
        let mut mem = MemWrite::new_vec(Some(MAX_NL_LENGTH));
        let bytes_read = match self.poll_read(mem.as_mut_slice()) {
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Ok(Async::Ready(0)) => return Ok(Async::Ready(None)),
            Ok(Async::Ready(i)) => i,
            Err(_) => return Err(()),
        };
        let mut mem_read = mem.shrink(bytes_read).into();
        let hdr = match NlHdr::<T, P>::deserialize(&mut mem_read) {
            Ok(h) => h,
            Err(_) => return Err(()),
        };
        Ok(Async::Ready(Some(hdr)))
    }
}

#[cfg(feature = "evented")]
impl<T, P> Evented for NlSocket<T, P> {
    fn register(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                opts: mio::PollOpt) -> io::Result<()> {
        poll.register(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn reregister(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                  opts: mio::PollOpt) -> io::Result<()> {
        poll.reregister(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        poll.deregister(&mio::unix::EventedFd(&self.as_raw_fd()))
    }
}

impl<T, P> Drop for NlSocket<T, P> {
    /// Closes underlying file descriptor to avoid file descriptor leaks.
    fn drop(&mut self) {
        unsafe { libc::close(self.fd); }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ffi::{CtrlCmd,Nlmsg};
    use genlhdr::GenlHdr;

    #[test]
    fn test_socket_creation() {
       NlSocket::<Nlmsg, GenlHdr<CtrlCmd>>::connect(NlFamily::Generic, None, Vec::new()).unwrap();
    }

    #[ignore]
    #[test]
    fn test_genl_family_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(19, sock.resolve_genl_family("nl80211").unwrap());
    }

    #[ignore]
    #[test]
    fn test_nl_mcast_group_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(5, sock.resolve_nl_mcast_group("nl80211", "mlme").unwrap());
    }
}
<commit_msg>Fix broken build<commit_after>//! # Socket code around `libc`
//!
//! ## Notes
//!
//! This module provides a low level one-to-one mapping between `libc` system call wrappers
//! with defaults specific to netlink sockets as well as a higher level API for simplification
//! of netlink code.

use std::io;
use std::os::unix::io::{AsRawFd,IntoRawFd,RawFd};
use std::marker::PhantomData;
use std::mem::{zeroed,size_of};

use buffering::copy::{StreamReadBuffer,StreamWriteBuffer};
use libc::{self,c_int,c_void};
#[cfg(feature = "evented")]
use mio::{self,Evented};
#[cfg(feature = "stream")]
use tokio::io::AsyncRead;
#[cfg(feature = "stream")]
use tokio::prelude::{Async,Stream};

use {Nl,MAX_NL_LENGTH};
use err::{NlError,Nlmsgerr};
use ffi::{self,NlFamily,GenlId,CtrlCmd,CtrlAttr,CtrlAttrMcastGrp,NlmF};
use genlhdr::GenlHdr;
use nlattr::NlAttrHdr;
use nlhdr::NlHdr;

/// Handle for the socket file descriptor
#[cfg(feature = "evented")]
pub struct NlSocket<T, P> {
    fd: c_int,
    poll: mio::Poll,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

/// Handle for the socket file descriptor
#[cfg(not(feature = "evented"))]
pub struct NlSocket<T, P> {
    fd: c_int,
    data_type: PhantomData<T>,
    data_payload: PhantomData<P>,
}

impl<T, P> NlSocket<T, P> where T: Nl, P: Nl {
    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(feature = "evented")]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        let poll = mio::Poll::new()?;
        let socket = NlSocket { fd, poll, data_type: PhantomData, data_payload: PhantomData };
        socket.register(&socket.poll, mio::Token(0), mio::Ready::readable(), mio::PollOpt::edge())?;
        Ok(socket)
    }

    /// Wrapper around `socket()` syscall filling in the netlink-specific information
    #[cfg(not(feature = "evented"))]
    pub fn new(proto: NlFamily) -> Result<Self, io::Error> {
        let fd = match unsafe {
            libc::socket(libc::AF_NETLINK, libc::SOCK_RAW, proto.into())
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }?;
        Ok(NlSocket { fd, data_type: PhantomData, data_payload: PhantomData })
    }

    /// Set underlying socket file descriptor to be blocking
    pub fn block(&mut self) -> Result<&mut Self, io::Error> {
        match unsafe { libc::fcntl(self.fd, libc::F_SETFL,
                                   libc::fcntl(self.fd, libc::F_GETFL, 0) & !libc::O_NONBLOCK) } {
            i if i < 0 => return Err(io::Error::last_os_error()),
            _ => Ok(self),
        }
    }

    /// Set underlying socket file descriptor to be non blocking
    pub fn nonblock(&mut self) -> Result<&mut Self, io::Error> {
        match unsafe { libc::fcntl(self.fd, libc::F_SETFL,
                                   libc::fcntl(self.fd, libc::F_GETFL, 0) | libc::O_NONBLOCK) } {
            i if i < 0 => return Err(io::Error::last_os_error()),
            _ => Ok(self),
        }
    }

    /// Determines if underlying file descriptor is blocking - `Stream` feature will throw an
    /// error if this function returns false
    pub fn is_blocking(&self) -> Result<bool, io::Error> {
        let is_blocking = match unsafe { libc::fcntl(self.fd, libc::F_GETFL, 0) } {
            i if i >= 0 => i & libc::O_NONBLOCK == 0,
            _ => return Err(io::Error::last_os_error()),
        };
        Ok(is_blocking)
    }

    /// Use this function to bind to a netlink ID and subscribe to groups. See netlink(7)
    /// man pages for more information on netlink IDs and groups.
    pub fn bind(&mut self, pid: Option<u32>, groups: Vec<u32>) -> Result<(), io::Error> {
        let mut nladdr = unsafe { zeroed::<libc::sockaddr_nl>() };
        nladdr.nl_family = libc::AF_NETLINK as u16;
        nladdr.nl_pid = pid.unwrap_or(0);
        nladdr.nl_groups = groups.into_iter().fold(0, |acc, next| {
            acc | (1 << (next - 1))
        });
        match unsafe {
            libc::bind(self.fd, &nladdr as *const _ as *const libc::sockaddr,
                       size_of::<libc::sockaddr_nl>() as u32)
        } {
            i if i >= 0 => Ok(()),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Send message encoded as byte slice to the netlink ID specified in the netlink header
    /// (`neli::nlhdr::NlHdr`)
    pub fn send<B>(&mut self, buf: StreamReadBuffer<B>, flags: i32) -> Result<isize, io::Error>
            where B: AsRef<[u8]> {
        match unsafe {
            libc::send(self.fd, buf.as_ref() as *const _ as *const c_void, buf.as_ref().len(), flags)
        } {
            i if i >= 0 => Ok(i),
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to send an `NlHdr` struct
    pub fn send_nl(&mut self, msg: NlHdr<T, P>) -> Result<(), NlError> {
        let mut mem = StreamWriteBuffer::new_growable(Some(msg.asize()));
        msg.serialize(&mut mem)?;
        self.send(StreamReadBuffer::new(mem), 0)?;
        Ok(())
    }

    /// Receive message encoded as byte slice from the netlink socket
    pub fn recv<'a>(&mut self, mut buf: StreamWriteBuffer<'a>, flags: i32)
            -> Result<StreamReadBuffer<StreamWriteBuffer<'a>>, io::Error> {
        match unsafe {
            libc::recv(self.fd, buf.as_mut() as *mut _ as *mut c_void, buf.as_mut().len(), flags)
        } {
            i if i >= 0 => {
                unsafe { buf.set_bytes_written(i as usize) };
                Ok(StreamReadBuffer::new(buf))
            },
            _ => Err(io::Error::last_os_error()),
        }
    }

    /// Convenience function to receive an `NlHdr` struct
    pub fn recv_nl(&mut self, buf_sz: Option<usize>) -> Result<NlHdr<T, P>, NlError> {
        let mem_write = StreamWriteBuffer::new_growable(buf_sz.or(Some(MAX_NL_LENGTH)));
        let mut mem_read = self.recv(mem_write, 0)?;
        Ok(NlHdr::<T, P>::deserialize(&mut mem_read)?)
    }

    /// Convenience function to receive an `NlHdr` struct with function type parameters
    /// that determine deserialization type
    pub fn recv_nl_typed<TT, PP>(&mut self, buf_sz: Option<usize>)
            -> Result<NlHdr<TT, PP>, NlError> where TT: Nl + Into<u16> + From<u16>, PP: Nl {
        let mem_write = StreamWriteBuffer::new_growable(buf_sz.or(Some(MAX_NL_LENGTH)));
        let mut mem_read = self.recv(mem_write, 0)?;
        Ok(NlHdr::<TT, PP>::deserialize(&mut mem_read)?)
    }

    /// Consume an ACK and return an error if an ACK is not found
    pub fn recv_ack(&mut self, buf_sz: Option<usize>) -> Result<(), NlError> {
        let ack = self.recv_nl_typed::<ffi::Nlmsg, Nlmsgerr<ffi::Nlmsg>>(buf_sz)?;
        if ack.nl_type == ffi::Nlmsg::Error && ack.nl_payload.error == 0 {
            Ok(())
        } else {
            Err(NlError::NoAck)
        }
    }

    /// Equivalent of `socket` and `bind` calls.
    pub fn connect(proto: NlFamily, pid: Option<u32>, groups: Vec<u32>)
                   -> Result<Self, io::Error> {
        let mut s = try!(NlSocket::new(proto));
        try!(s.bind(pid, groups));
        Ok(s)
    }
}

impl NlSocket<GenlId, GenlHdr<CtrlCmd>> {
    /// Create generic netlink resolution socket
    pub fn new_genl() -> Result<NlSocket<GenlId, GenlHdr<CtrlCmd>>, io::Error> {
        Self::connect(NlFamily::Generic, None, Vec::new())
    }

    fn get_genl_family(&mut self, family_name: &str)
            -> Result<NlHdr<GenlId, GenlHdr<CtrlCmd>>, NlError> {
        let attrs = vec![NlAttrHdr::new_str_payload(None, CtrlAttr::FamilyName, family_name)?];
        let genlhdr = GenlHdr::new(CtrlCmd::Getfamily, 2, attrs)?;
        let nlhdr = NlHdr::new(None, GenlId::Ctrl,
                               vec![NlmF::Request], None, None, genlhdr);
        self.send_nl(nlhdr)?;

        Ok(self.recv_nl(Some(4096))?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_genl_family(&mut self, family_name: &str) -> Result<u16, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        Ok(handle.get_payload_with::<u16>(CtrlAttr::FamilyId, None)?)
    }

    /// Convenience function for resolving a `&str` containing the multicast group name to a
    /// numeric netlink ID
    pub fn resolve_nl_mcast_group(&mut self, family_name: &str, mcast_name: &str)
            -> Result<u32, NlError> {
        let nlhdr = self.get_genl_family(family_name)?;
        let mut handle = nlhdr.nl_payload.get_attr_handle::<CtrlAttr>();
        let mut mcast_groups = handle.get_nested_attributes::<u16>(CtrlAttr::McastGroups)?;
        mcast_groups.parse_nested_attributes()?;
        let mut id = None;
        if let Some(iter) = mcast_groups.iter() {
            for attribute in iter {
                let attribute_len = attribute.nla_len;
                let mut handle = attribute.get_attr_handle();
                let string = handle.get_payload_with::<String>(CtrlAttrMcastGrp::Name,
                    Some(attribute_len as usize))?;
                if string.as_str() == mcast_name {
                    id = handle.get_payload_with::<u32>(CtrlAttrMcastGrp::Id, None).ok();
                }
            }
        }
        id.ok_or(NlError::new("Failed to resolve multicast group ID"))
    }
}

impl<T, P> AsRawFd for NlSocket<T, P> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl<T, P> IntoRawFd for NlSocket<T, P> {
    fn into_raw_fd(self) -> RawFd {
        self.fd
    }
}

impl<T, P> io::Read for NlSocket<T, P> where T: Nl, P: Nl {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match unsafe {
            libc::recv(self.fd, buf as *mut _ as *mut c_void, buf.len(), 0)
        } {
            i if i >= 0 => Ok(i as usize),
            _ => Err(io::Error::last_os_error()),
        }
    }
}

#[cfg(feature = "stream")]
impl<T, P> AsyncRead for NlSocket<T, P> where T: Nl, P: Nl { }

#[cfg(feature = "stream")]
impl<T, P> Stream for NlSocket<T, P> where T: Nl, P: Nl {
    type Item = NlHdr<T, P>;
    type Error = ();

    fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
        if !self.is_blocking().map_err(|_| ())? {
            return Err(());
        }
        let mut mem = StreamWriteBuffer::new_growable(Some(MAX_NL_LENGTH));
        match self.poll_read(mem.as_mut()) {
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Ok(Async::Ready(0)) => return Ok(Async::Ready(None)),
            Ok(Async::Ready(_)) => (),
            Err(_) => return Err(()),
        };
        let mut mem_read = StreamReadBuffer::new(mem);
        let hdr = match NlHdr::<T, P>::deserialize(&mut mem_read) {
            Ok(h) => h,
            Err(_) => return Err(()),
        };
        Ok(Async::Ready(Some(hdr)))
    }
}

#[cfg(feature = "evented")]
impl<T, P> Evented for NlSocket<T, P> {
    fn register(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                opts: mio::PollOpt) -> io::Result<()> {
        poll.register(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn reregister(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready,
                  opts: mio::PollOpt) -> io::Result<()> {
        poll.reregister(&mio::unix::EventedFd(&self.as_raw_fd()), token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        poll.deregister(&mio::unix::EventedFd(&self.as_raw_fd()))
    }
}

impl<T, P> Drop for NlSocket<T, P> {
    /// Closes underlying file descriptor to avoid file descriptor leaks.
    fn drop(&mut self) {
        unsafe { libc::close(self.fd); }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ffi::{CtrlCmd,Nlmsg};
    use genlhdr::GenlHdr;

    #[test]
    fn test_socket_creation() {
       NlSocket::<Nlmsg, GenlHdr<CtrlCmd>>::connect(NlFamily::Generic, None, Vec::new()).unwrap();
    }

    #[ignore]
    #[test]
    fn test_genl_family_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(19, sock.resolve_genl_family("nl80211").unwrap());
    }

    #[ignore]
    #[test]
    fn test_nl_mcast_group_resolve() {
        let mut sock = NlSocket::new_genl().unwrap();
        assert_eq!(5, sock.resolve_nl_mcast_group("nl80211", "mlme").unwrap());
    }
}
<|endoftext|>


<commit_before>fn main() {
    // build the client shim
    cc::Build::new().file("src/sys/client/log_shim.c").compile("log_shim_client");
    println!("cargo:rerun-if-changed=src/client/log_shim.c");
    // build the server shim
    cc::Build::new().file("src/sys/server/log_shim.c").compile("log_shim_server");
    println!("cargo:rerun-if-changed=src/server/log_shim.c");
}
<commit_msg>Correct build.rs src/sys/*/log_shim.c rerun-if-changed path<commit_after>fn main() {
    // build the client shim
    cc::Build::new().file("src/sys/client/log_shim.c").compile("log_shim_client");
    println!("cargo:rerun-if-changed=src/sys/client/log_shim.c");
    // build the server shim
    cc::Build::new().file("src/sys/server/log_shim.c").compile("log_shim_server");
    println!("cargo:rerun-if-changed=src/sys/server/log_shim.c");
}
<|endoftext|>


<commit_before>use cpp_to_rust_generator::cpp_data::CppData;
use cpp_to_rust_common::errors::{Result, ChainErr};
use cpp_to_rust_common::file_utils::{read_dir, file_to_string, os_str_to_str};
use cpp_to_rust_common::log;
use cpp_to_rust_common::utils::add_to_multihash;

use std::path::PathBuf;
use std::collections::HashMap;

struct HeaderNameMap {
  map_real_to_all_fancy: HashMap<String, Vec<String>>,
  map_real_to_fancy: HashMap<String, String>,
}

impl HeaderNameMap {
  fn real_to_fancy(&self, real_header: &str, class_name: Option<&str>) -> String {
    if let Some(class_name) = class_name {
      if let Some(fancy_headers) = self.map_real_to_all_fancy.get(real_header) {
        if let Some(x) =
          fancy_headers
            .iter()
            .find(|&x| x == class_name || class_name.starts_with(&format!("{}::", x))) {
          return x.clone();
        }
      }
    }
    if let Some(fancy_header) = self.map_real_to_fancy.get(real_header) {
      return fancy_header.clone();
    }
    real_header.to_string()
  }

  fn new(headers_dir: &PathBuf) -> Result<HeaderNameMap> {
    let re = ::regex::Regex::new(r#"^#include "([a-zA-Z0-9._]+)"$"#)?;
    let mut map_real_to_all_fancy: HashMap<_, Vec<_>> = HashMap::new();
    log::status("Detecting fancy Qt header names");
    for header in read_dir(headers_dir)? {
      let header = header?;
      let header_path = header.path();
      if !header_path.is_file() {
        continue;
      }
      let metadata = ::std::fs::metadata(&header_path)
          .chain_err(|| format!("failed to get metadata for {}", header_path.display()))?;
      if metadata.len() < 100 {
        let file_content = file_to_string(&header_path)?;
        if let Some(matches) = re.captures(file_content.trim()) {
          let real_header = matches
            .at(1)
            .chain_err(|| "invalid regexp matches")?
            .to_string();
          let fancy_header = os_str_to_str(&header.file_name())?.to_string();
          add_to_multihash(&mut map_real_to_all_fancy, real_header, fancy_header);
        }
      }
    }
    if map_real_to_all_fancy.contains_key("qsharedpointer.h") {
      let v = map_real_to_all_fancy["qsharedpointer.h"].clone();
      map_real_to_all_fancy.insert("qsharedpointer_impl.h".to_string(), v);
    }
    let mut map_real_to_fancy = HashMap::new();
    for (real_header, fancy_headers) in &map_real_to_all_fancy {
      let fancy_header = if fancy_headers.len() == 1 {
        fancy_headers[0].clone()
      } else {
        let mut result = fancy_headers[0].clone();
        let mut ok = false;
        for h in fancy_headers {
          if format!("{}.h", h.to_lowercase()) == *real_header {
            result = h.clone();
            ok = true;
            break;
          }
        }
        if !ok {
          log::llog(log::DebugQtHeaderNames,
                    || format!("{} -> {:?} (detect failed)", real_header, fancy_headers));
        }
        result
      };
      log::llog(log::DebugQtHeaderNames,
                || format!("{} -> {}", real_header, fancy_header));
      map_real_to_fancy.insert(real_header.clone(), fancy_header);
    }
    Ok(HeaderNameMap {
         map_real_to_all_fancy: map_real_to_all_fancy,
         map_real_to_fancy: map_real_to_fancy,
       })
  }
}

pub fn fix_header_names(data: &mut CppData, headers_dir: &PathBuf) -> Result<()> {
  let map = HeaderNameMap::new(headers_dir)?;
  for t in &mut data.types {
    t.include_file = map.real_to_fancy(&t.include_file, Some(&t.name));
  }
  for m in &mut data.methods {
    let x = map.real_to_fancy(&m.include_file, m.class_name().map(|x| x.as_ref()));
    m.include_file = x;
  }
  Ok(())
}

#[test]
fn test_qt_fix_header_names() {
  let map = HeaderNameMap::new(&PathBuf::from(env!("CARGO_MANIFEST_DIR"))
                                  .with_added("test_assets")
                                  .with_added("qt_headers"))
      .unwrap();
  assert_eq!(map.real_to_fancy("qfile.h", None), "QFile");
  assert_eq!(map.real_to_fancy("qfile.h", Some("QFile")), "QFile");
  assert_eq!(map.real_to_fancy("qnotmap.h", None), "qnotmap.h");
  assert_eq!(map.real_to_fancy("qfactoryinterface.h", None),
             "QFactoryInterface");
  assert_eq!(map.real_to_fancy("qfactoryinterface.h", Some("^_^")),
             "QFactoryInterface");
}
<commit_msg>new ci config 6<commit_after>use cpp_to_rust_generator::cpp_data::CppData;
use cpp_to_rust_common::errors::{Result, ChainErr};
use cpp_to_rust_common::file_utils::{read_dir, file_to_string, os_str_to_str};
use cpp_to_rust_common::log;
use cpp_to_rust_common::utils::add_to_multihash;

use std::path::PathBuf;
use std::collections::HashMap;

struct HeaderNameMap {
  map_real_to_all_fancy: HashMap<String, Vec<String>>,
  map_real_to_fancy: HashMap<String, String>,
}

impl HeaderNameMap {
  fn real_to_fancy(&self, real_header: &str, class_name: Option<&str>) -> String {
    if let Some(class_name) = class_name {
      if let Some(fancy_headers) = self.map_real_to_all_fancy.get(real_header) {
        if let Some(x) =
          fancy_headers
            .iter()
            .find(|&x| x == class_name || class_name.starts_with(&format!("{}::", x))) {
          return x.clone();
        }
      }
    }
    if let Some(fancy_header) = self.map_real_to_fancy.get(real_header) {
      return fancy_header.clone();
    }
    real_header.to_string()
  }

  fn new(headers_dir: &PathBuf) -> Result<HeaderNameMap> {
    let re = ::regex::Regex::new(r#"^#include "([a-zA-Z0-9._]+)"$"#)?;
    let mut map_real_to_all_fancy: HashMap<_, Vec<_>> = HashMap::new();
    log::status("Detecting fancy Qt header names");
    for header in read_dir(headers_dir)? {
      let header = header?;
      let header_path = header.path();
      if !header_path.is_file() {
        continue;
      }
      let metadata = ::std::fs::metadata(&header_path)
          .chain_err(|| format!("failed to get metadata for {}", header_path.display()))?;
      if metadata.len() < 100 {
        let file_content = file_to_string(&header_path)?;
        if let Some(matches) = re.captures(file_content.trim()) {
          let real_header = matches
            .at(1)
            .chain_err(|| "invalid regexp matches")?
            .to_string();
          let fancy_header = os_str_to_str(&header.file_name())?.to_string();
          add_to_multihash(&mut map_real_to_all_fancy, real_header, fancy_header);
        }
      }
    }
    if map_real_to_all_fancy.contains_key("qsharedpointer.h") {
      let v = map_real_to_all_fancy["qsharedpointer.h"].clone();
      map_real_to_all_fancy.insert("qsharedpointer_impl.h".to_string(), v);
    }
    let mut map_real_to_fancy = HashMap::new();
    for (real_header, fancy_headers) in &map_real_to_all_fancy {
      let fancy_header = if fancy_headers.len() == 1 {
        fancy_headers[0].clone()
      } else {
        let mut result = fancy_headers[0].clone();
        let mut ok = false;
        for h in fancy_headers {
          if format!("{}.h", h.to_lowercase()) == *real_header {
            result = h.clone();
            ok = true;
            break;
          }
        }
        if !ok {
          log::llog(log::DebugQtHeaderNames,
                    || format!("{} -> {:?} (detect failed)", real_header, fancy_headers));
        }
        result
      };
      log::llog(log::DebugQtHeaderNames,
                || format!("{} -> {}", real_header, fancy_header));
      map_real_to_fancy.insert(real_header.clone(), fancy_header);
    }
    Ok(HeaderNameMap {
         map_real_to_all_fancy: map_real_to_all_fancy,
         map_real_to_fancy: map_real_to_fancy,
       })
  }
}

pub fn fix_header_names(data: &mut CppData, headers_dir: &PathBuf) -> Result<()> {
  let map = HeaderNameMap::new(headers_dir)?;
  for t in &mut data.types {
    t.include_file = map.real_to_fancy(&t.include_file, Some(&t.name));
  }
  for m in &mut data.methods {
    let x = map.real_to_fancy(&m.include_file, m.class_name().map(|x| x.as_ref()));
    m.include_file = x;
  }
  Ok(())
}

#[test]
fn test_qt_fix_header_names() {
  use cpp_to_rust_common::file_utils::PathBufWithAdded;
  let map = HeaderNameMap::new(&PathBuf::from(env!("CARGO_MANIFEST_DIR"))
                                  .with_added("test_assets")
                                  .with_added("qt_headers"))
      .unwrap();
  assert_eq!(map.real_to_fancy("qfile.h", None), "QFile");
  assert_eq!(map.real_to_fancy("qfile.h", Some("QFile")), "QFile");
  assert_eq!(map.real_to_fancy("qnotmap.h", None), "qnotmap.h");
  assert_eq!(map.real_to_fancy("qfactoryinterface.h", None),
             "QFactoryInterface");
  assert_eq!(map.real_to_fancy("qfactoryinterface.h", Some("^_^")),
             "QFactoryInterface");
}
<|endoftext|>