<commit_before>/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  /// Information regarding the current audio frame.
  pub header: Header,
  /// CRC-16 of all frame bytes before this footer.
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  /// Independent channels, from one up to eight.
  Independent,
  /// Left and side stereo.
  LeftSide,
  /// Right and side stereo.
  RightSide,
  /// Middle and side stereo.
  MiddleSide,
}

/// Numbering scheme used from the frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  /// Frame number of first sample in frame.
  Frame(u32),
  /// Sample number of first sample in frame.
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  /// Number of samples per subframe.
  pub block_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels that also represent the number of subframes.
  pub channels: u8,
  /// Channel assignment order.
  pub channel_assignment: ChannelAssignment,
  /// Size, in bits, per sample.
  pub bits_per_sample: usize,
  /// Numbering scheme used from the frame.
  pub number: NumberType,
  /// CRC-8 of all header bytes before this crc.
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<commit_msg>Add subframes to `Frame` struct<commit_after>use frame::SubFrame;

/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  /// Information regarding the current audio frame.
  pub header: Header,
  pub subframes: [SubFrame; MAX_CHANNELS],
  /// CRC-16 of all frame bytes before this footer.
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  /// Independent channels, from one up to eight.
  Independent,
  /// Left and side stereo.
  LeftSide,
  /// Right and side stereo.
  RightSide,
  /// Middle and side stereo.
  MiddleSide,
}

/// Numbering scheme used from the frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  /// Frame number of first sample in frame.
  Frame(u32),
  /// Sample number of first sample in frame.
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  /// Number of samples per subframe.
  pub block_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels that also represent the number of subframes.
  pub channels: u8,
  /// Channel assignment order.
  pub channel_assignment: ChannelAssignment,
  /// Size, in bits, per sample.
  pub bits_per_sample: usize,
  /// Numbering scheme used from the frame.
  pub number: NumberType,
  /// CRC-8 of all header bytes before this crc.
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use shader_version::{opengl, glsl};
use graphics::{ Context, BackEnd };
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static VS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static FS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

void main()
{
    gl_FragColor = color;
}
";

static FS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

out vec4 out_color;

void main()
{
    out_color = color;
}
";

static VS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;
attribute vec2 uv;

uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static VS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static FS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;
uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    gl_FragColor = texture2D(s_texture, v_uv) * color;
}
";

static FS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;
uniform sampler2D s_texture;

out vec4 out_color;

in vec2 v_uv;

void main()
{
    out_color = texture(s_texture, v_uv) * color;
}
";

fn pick_120_150<T>(glsl: glsl::GLSL, for_120: T, for_150: T) -> T {
    match glsl {
        glsl::GLSL_1_10 => panic!("GLSL 1.10 not supported"),
        glsl::GLSL_1_20
      | glsl::GLSL_1_30
      | glsl::GLSL_1_40 => for_120,
        _ => for_150,
    }
}

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: glsl::GLSL) -> Colored {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_COLORED_120, VS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_COLORED_120, FS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: glsl::GLSL) -> Textured {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_TEXTURED_120, VS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_TEXTURED_120, FS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    color: [f32, ..4],
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new(opengl: opengl::OpenGL) -> Gl {
        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        Gl {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
            color: [1.0, ..4],
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Draws graphics.
    pub fn draw(&mut self, viewport: [i32, ..4], f: |c: Context, g: &mut Gl|) {
        let [x, y, w, h] = viewport;
        self.viewport(x, y, w, h);
        self.clear_program();
        self.enable_alpha_blend();
        let c = Context::abs(
            w as f64,
            h as f64
        );
        f(c, self);
        self.disable_alpha_blend();
    }
}

impl BackEnd<Texture> for Gl {
    fn clear(&mut self, color: [f32, ..4]) {
        unsafe {
            let [r, g, b, a] = color;
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn enable_alpha_blend(&mut self) {
        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        }
    }

    fn disable_alpha_blend(&mut self) {
        unsafe {
            gl::Disable(gl::BLEND);
        }
    }

    fn enable_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
        }
    }

    fn disable_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn color(&mut self, color: [f32, ..4]) {
        self.color = color;
    }

    fn tri_list(&mut self, vertices: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.colored;

        // xy makes two floats.
        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);

            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv(&mut self, vertices: &[f32], texture_coords: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.textured;

        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            shader.uv.set(texture_coords);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }
}

<commit_msg>Upgraded to latest piston-graphics<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use shader_version::{opengl, glsl};
use graphics::{ Context, BackEnd };
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static VS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static FS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

void main()
{
    gl_FragColor = color;
}
";

static FS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

out vec4 out_color;

void main()
{
    out_color = color;
}
";

static VS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;
attribute vec2 uv;

uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static VS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static FS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;
uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    gl_FragColor = texture2D(s_texture, v_uv) * color;
}
";

static FS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;
uniform sampler2D s_texture;

out vec4 out_color;

in vec2 v_uv;

void main()
{
    out_color = texture(s_texture, v_uv) * color;
}
";

fn pick_120_150<T>(glsl: glsl::GLSL, for_120: T, for_150: T) -> T {
    match glsl {
        glsl::GLSL_1_10 => panic!("GLSL 1.10 not supported"),
        glsl::GLSL_1_20
      | glsl::GLSL_1_30
      | glsl::GLSL_1_40 => for_120,
        _ => for_150,
    }
}

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: glsl::GLSL) -> Colored {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_COLORED_120, VS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_COLORED_120, FS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: glsl::GLSL) -> Textured {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_TEXTURED_120, VS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_TEXTURED_120, FS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    color: [f32, ..4],
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new(opengl: opengl::OpenGL) -> Gl {
        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        Gl {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
            color: [1.0, ..4],
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Draws graphics.
    pub fn draw(&mut self, viewport: [i32, ..4], f: |c: Context, g: &mut Gl|) {
        let [x, y, w, h] = viewport;
        self.viewport(x, y, w, h);
        self.clear_program();
        self.enable_alpha_blend();
        let c = Context::abs(
            w as f64,
            h as f64
        );
        f(c, self);
        self.disable_alpha_blend();
    }

    /// Assume all textures has alpha channel for now.
    pub fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    /// Enabled alpha blending.
    pub fn enable_alpha_blend(&mut self) {
        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        }
    }

    /// Disables alpha blending.
    pub fn disable_alpha_blend(&mut self) {
        unsafe {
            gl::Disable(gl::BLEND);
        }
    }
}

impl BackEnd<Texture> for Gl {
    fn clear(&mut self, color: [f32, ..4]) {
        unsafe {
            let [r, g, b, a] = color;
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn enable_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
        }
    }

    fn disable_texture(&mut self) {}

    fn color(&mut self, color: [f32, ..4]) {
        self.color = color;
    }

    fn tri_list(&mut self, vertices: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.colored;

        // xy makes two floats.
        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);

            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv(&mut self, vertices: &[f32], texture_coords: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.textured;

        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            shader.uv.set(texture_coords);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }
}

<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VERTEX_SHADER_XY_RGBA: &'static str = "
#version 330
in vec4 pos;
in vec4 color;

out vec4 v_color;

void main()
{
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_XY_RGBA: &'static str = "
#version 330
out vec4 out_color;
in vec4 v_color;

void main()
{
    out_color = v_color;
}
";

static VERTEX_SHADER_XY_RGBA_UV: &'static str = "
#version 330
in vec4 pos;
in vec4 color;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;
out vec4 v_color;

void main()
{
    v_uv = uv;
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_XY_RGBA_UV: &'static str = "
#version 330
out vec4 out_color;

uniform sampler2D s_texture;

in vec2 v_uv;
in vec4 v_color;

void main()
{
    out_color = texture(s_texture, v_uv) * v_color;
}
";

struct XYRGBA {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
}

impl Drop for XYRGBA {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl XYRGBA {
    fn new() -> XYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        XYRGBA {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct XYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for XYRGBAUV {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl XYRGBAUV {
    fn new() -> XYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        XYRGBAUV {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    xy_rgba: XYRGBA,
    xy_rgba_uv: XYRGBAUV,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        Gl {
            xy_rgba: XYRGBA::new(),
            xy_rgba_uv: XYRGBAUV::new(),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.xy_rgba.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.xy_rgba;
        gl::BindVertexArray(shader.vao);

        // xy makes two floats.
        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.xy_rgba_uv;
        gl::BindVertexArray(shader.vao);

        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
            shader.uv.set(texture_coords);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }
}

<commit_msg>Changed to 150 core<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VERTEX_SHADER_XY_RGBA: &'static str = "
#version 150 core
in vec4 pos;
in vec4 color;

out vec4 v_color;

void main()
{
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_XY_RGBA: &'static str = "
#version 150 core
out vec4 out_color;
in vec4 v_color;

void main()
{
    out_color = v_color;
}
";

static VERTEX_SHADER_XY_RGBA_UV: &'static str = "
#version 150 core
in vec4 pos;
in vec4 color;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;
out vec4 v_color;

void main()
{
    v_uv = uv;
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_XY_RGBA_UV: &'static str = "
#version 150 core
out vec4 out_color;

uniform sampler2D s_texture;

in vec2 v_uv;
in vec4 v_color;

void main()
{
    out_color = texture(s_texture, v_uv) * v_color;
}
";

struct XYRGBA {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
}

impl Drop for XYRGBA {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl XYRGBA {
    fn new() -> XYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        XYRGBA {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct XYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for XYRGBAUV {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl XYRGBAUV {
    fn new() -> XYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        XYRGBAUV {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    xy_rgba: XYRGBA,
    xy_rgba_uv: XYRGBAUV,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        Gl {
            xy_rgba: XYRGBA::new(),
            xy_rgba_uv: XYRGBAUV::new(),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.xy_rgba.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.xy_rgba;
        gl::BindVertexArray(shader.vao);

        // xy makes two floats.
        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.xy_rgba_uv;
        gl::BindVertexArray(shader.vao);

        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
            shader.uv.set(texture_coords);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }
}

<|endoftext|>


<commit_before><commit_msg>Thread RUSTC_THREAD_COUNT through to our rustc wrapper<commit_after><|endoftext|>


<commit_before><commit_msg>Do a cleanup/legibility pass<commit_after><|endoftext|>


<commit_before>//! IGD async API example.
//!
//! It demonstrates how to:
//! * get external IP
//! * add port mappings
//! * remove port mappings
//!
//! If everything works fine, 2 port mappings are added, 1 removed and we're left with single
//! port mapping: External 1234 ---> 4321 Internal

extern crate igd;
extern crate futures;
extern crate tokio_core;

use igd::tokio::search_gateway;
use igd::PortMappingProtocol;
use futures::future::Future;

fn main() {
    let mut evloop = tokio_core::reactor::Core::new().unwrap();
    let handle = evloop.handle();

    let task = search_gateway(&handle)
        .map_err(|e| panic!("Failed to find IGD: {}", e))
        .and_then(|gateway| gateway.get_external_ip()
            .map_err(|e| panic!("Failed to get external IP: {}", e))
            .and_then(|ip| Ok((gateway, ip)))
        )
        .and_then(|(gateway, pub_ip)| {
            println!("Our public IP: {}", pub_ip);
            Ok(gateway)
        })
        .and_then(|gateway| {
            gateway.add_port(
                PortMappingProtocol::TCP,
                1234,
                "192.168.1.210:4321".parse().unwrap(),
                0,
                "rust-igd-async-example",
            )
            .map_err(|e| panic!("Failed to add port mapping: {}", e))
            .and_then(|_| {
                println!("New port mapping was successfully added.");
                Ok(gateway)
            })
        })
        .and_then(|gateway| {
            gateway.add_port(
                PortMappingProtocol::TCP,
                2345,
                "192.168.1.210:5432".parse().unwrap(),
                0,
                "rust-igd-async-example",
            )
            .map_err(|e| panic!("Failed to add port mapping: {}", e))
            .and_then(|_| {
                println!("New port mapping was successfully added.");
                Ok(gateway)
            })
        })
        .and_then(|gateway| gateway.remove_port(PortMappingProtocol::TCP, 2345))
        .and_then(|_| {
            println!("Port was removed.");
            Ok(())
        });

    let _ = evloop.run(task).unwrap();
}
<commit_msg>fix async example<commit_after>//! IGD async API example.
//!
//! It demonstrates how to:
//! * get external IP
//! * add port mappings
//! * remove port mappings
//!
//! If everything works fine, 2 port mappings are added, 1 removed and we're left with single
//! port mapping: External 1234 ---> 4321 Internal

extern crate igd;
extern crate futures;
extern crate tokio_core;

use igd::async::search_gateway;
use igd::PortMappingProtocol;
use futures::future::Future;

fn main() {
    let mut evloop = tokio_core::reactor::Core::new().unwrap();
    let handle = evloop.handle();

    let task = search_gateway(&handle)
        .map_err(|e| panic!("Failed to find IGD: {}", e))
        .and_then(|gateway| gateway.get_external_ip()
            .map_err(|e| panic!("Failed to get external IP: {}", e))
            .and_then(|ip| Ok((gateway, ip)))
        )
        .and_then(|(gateway, pub_ip)| {
            println!("Our public IP: {}", pub_ip);
            Ok(gateway)
        })
        .and_then(|gateway| {
            gateway.add_port(
                PortMappingProtocol::TCP,
                1234,
                "192.168.1.210:4321".parse().unwrap(),
                0,
                "rust-igd-async-example",
            )
            .map_err(|e| panic!("Failed to add port mapping: {}", e))
            .and_then(|_| {
                println!("New port mapping was successfully added.");
                Ok(gateway)
            })
        })
        .and_then(|gateway| {
            gateway.add_port(
                PortMappingProtocol::TCP,
                2345,
                "192.168.1.210:5432".parse().unwrap(),
                0,
                "rust-igd-async-example",
            )
            .map_err(|e| panic!("Failed to add port mapping: {}", e))
            .and_then(|_| {
                println!("New port mapping was successfully added.");
                Ok(gateway)
            })
        })
        .and_then(|gateway| gateway.remove_port(PortMappingProtocol::TCP, 2345))
        .and_then(|_| {
            println!("Port was removed.");
            Ok(())
        });

    let _ = evloop.run(task).unwrap();
}
<|endoftext|>


<commit_before>// This is a part of rust-encoding.
// Copyright (c) 2013, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Common codec implementation for single-byte encodings.

use std::str;
use util::StrCharIndex;
use types::*;

pub struct SingleByteEncoding {
    name: &'static str,
    index_forward: extern "Rust" fn(u8) -> u16,
    index_backward: extern "Rust" fn(u16) -> u8,
}

impl Clone for SingleByteEncoding {
    fn clone(&self) -> SingleByteEncoding {
        SingleByteEncoding { name: self.name,
                             index_forward: self.index_forward,
                             index_backward: self.index_backward }
    }
}

impl Encoding for SingleByteEncoding {
    pub fn name(&self) -> ~str { self.name.to_owned() }
    pub fn encoder(&self) -> ~Encoder { ~SingleByteEncoder { encoding: self.clone() } as ~Encoder }
    pub fn decoder(&self) -> ~Decoder { ~SingleByteDecoder { encoding: self.clone() } as ~Decoder }
    pub fn preferred_replacement_seq(&self) -> ~[u8] { ~[0x3f] /* "?" */ }
}

#[deriving(Clone)]
pub struct SingleByteEncoder {
    encoding: SingleByteEncoding,
}

impl Encoder for SingleByteEncoder {
    pub fn encoding(&self) -> ~Encoding { ~self.encoding.clone() as ~Encoding }

    pub fn feed<'r>(&mut self, input: &'r str) -> (~[u8],Option<EncoderError<'r>>) {
        let mut ret = ~[];
        let mut err = None;
        for input.index_iter().advance |((_,j), ch)| {
            if ch <= '\u007f' {
                ret.push(ch as u8);
                loop
            }
            if ch <= '\uffff' {
                let index = (self.encoding.index_backward)(ch as u16);
                if index != 0xff {
                    ret.push((index + 0x80) as u8);
                    loop
                }
            }
            err = Some(CodecError {
                remaining: input.slice_from(j),
                problem: str::from_char(ch),
                cause: ~"unrepresentable character",
            });
            break;
        }
        (ret, err)
    }

    pub fn flush(~self) -> (~[u8],Option<EncoderError<'static>>) {
        (~[], None)
    }
}

#[deriving(Clone)]
pub struct SingleByteDecoder {
    encoding: SingleByteEncoding,
}

impl Decoder for SingleByteDecoder {
    pub fn encoding(&self) -> ~Encoding { ~self.encoding.clone() as ~Encoding }

    pub fn feed<'r>(&mut self, input: &'r [u8]) -> (~str,Option<DecoderError<'r>>) {
        let mut ret = ~"";
        let mut i = 0;
        let len = input.len();
        while i < len {
            if input[i] <= 0x7f {
                ret.push_char(input[i] as char);
            } else {
                let ch = (self.encoding.index_forward)(input[i] - 0x80);
                if ch != 0xffff {
                    ret.push_char(ch as char);
                } else {
                    return (ret, Some(CodecError {
                        remaining: input.slice(i+1, input.len()),
                        problem: ~[input[i]],
                        cause: ~"invalid sequence",
                    }));
                }
            }
            i += 1;
        }
        (ret, None)
    }

    pub fn flush(~self) -> (~str,Option<DecoderError<'static>>) {
        (~"", None)
    }
}

#[test]
fn test_non_bmp() {
    use all;
    assert_eq!(all::ISO_8859_2.encode("A\uFFFFB", Replace).unwrap(), ~[0x41, 0x3F, 0x42]);
    assert_eq!(all::ISO_8859_2.encode("A\U00010000B", Replace).unwrap(), ~[0x41, 0x3F, 0x42]);
}
<commit_msg>converted `test_non_bmp` to the encoder test.<commit_after>// This is a part of rust-encoding.
// Copyright (c) 2013, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Common codec implementation for single-byte encodings.

use std::str;
use util::StrCharIndex;
use types::*;

pub struct SingleByteEncoding {
    name: &'static str,
    index_forward: extern "Rust" fn(u8) -> u16,
    index_backward: extern "Rust" fn(u16) -> u8,
}

impl Clone for SingleByteEncoding {
    fn clone(&self) -> SingleByteEncoding {
        SingleByteEncoding { name: self.name,
                             index_forward: self.index_forward,
                             index_backward: self.index_backward }
    }
}

impl Encoding for SingleByteEncoding {
    pub fn name(&self) -> ~str { self.name.to_owned() }
    pub fn encoder(&self) -> ~Encoder { ~SingleByteEncoder { encoding: self.clone() } as ~Encoder }
    pub fn decoder(&self) -> ~Decoder { ~SingleByteDecoder { encoding: self.clone() } as ~Decoder }
    pub fn preferred_replacement_seq(&self) -> ~[u8] { ~[0x3f] /* "?" */ }
}

#[deriving(Clone)]
pub struct SingleByteEncoder {
    encoding: SingleByteEncoding,
}

impl Encoder for SingleByteEncoder {
    pub fn encoding(&self) -> ~Encoding { ~self.encoding.clone() as ~Encoding }

    pub fn feed<'r>(&mut self, input: &'r str) -> (~[u8],Option<EncoderError<'r>>) {
        let mut ret = ~[];
        let mut err = None;
        for input.index_iter().advance |((_,j), ch)| {
            if ch <= '\u007f' {
                ret.push(ch as u8);
                loop
            }
            if ch <= '\uffff' {
                let index = (self.encoding.index_backward)(ch as u16);
                if index != 0xff {
                    ret.push((index + 0x80) as u8);
                    loop
                }
            }
            err = Some(CodecError {
                remaining: input.slice_from(j),
                problem: str::from_char(ch),
                cause: ~"unrepresentable character",
            });
            break;
        }
        (ret, err)
    }

    pub fn flush(~self) -> (~[u8],Option<EncoderError<'static>>) {
        (~[], None)
    }
}

#[deriving(Clone)]
pub struct SingleByteDecoder {
    encoding: SingleByteEncoding,
}

impl Decoder for SingleByteDecoder {
    pub fn encoding(&self) -> ~Encoding { ~self.encoding.clone() as ~Encoding }

    pub fn feed<'r>(&mut self, input: &'r [u8]) -> (~str,Option<DecoderError<'r>>) {
        let mut ret = ~"";
        let mut i = 0;
        let len = input.len();
        while i < len {
            if input[i] <= 0x7f {
                ret.push_char(input[i] as char);
            } else {
                let ch = (self.encoding.index_forward)(input[i] - 0x80);
                if ch != 0xffff {
                    ret.push_char(ch as char);
                } else {
                    return (ret, Some(CodecError {
                        remaining: input.slice(i+1, input.len()),
                        problem: ~[input[i]],
                        cause: ~"invalid sequence",
                    }));
                }
            }
            i += 1;
        }
        (ret, None)
    }

    pub fn flush(~self) -> (~str,Option<DecoderError<'static>>) {
        (~"", None)
    }
}

#[cfg(test)]
mod tests {
    use all::ISO_8859_2;
    use types::*;

    fn strip_cause<T,Remaining,Problem>(result: (T,Option<CodecError<Remaining,Problem>>))
                                    -> (T,Option<(Remaining,Problem)>) {
        match result {
            (processed, None) => (processed, None),
            (processed, Some(CodecError { remaining, problem, cause: _cause })) =>
                (processed, Some((remaining, problem)))
        }
    }

    macro_rules! assert_result(
        ($lhs:expr, $rhs:expr) => (assert_eq!(strip_cause($lhs), $rhs))
    )

    #[test]
    fn test_encoder_non_bmp() {
        let mut e = ISO_8859_2.encoder();
        assert_result!(e.feed("A\uFFFFB"), (~[0x41], Some(("B", ~"\uFFFF"))));
        assert_result!(e.feed("A\U00010000B"), (~[0x41], Some(("B", ~"\U00010000"))));
    }
}

<|endoftext|>


<commit_before>extern crate getopts;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;

#[macro_use]
extern crate torchrs;

use torchrs::autograd::{Variable, VariableArgs, VarAccess};
use torchrs::tensor::Tensor;
use torchrs::optim;

use torchrs::macros::*;
use torchrs::nn;
use torchrs::nn::{ModuleStruct, ModIntf, ModDelegate, Module};
use torchrs::nn::functional as F;
use torchrs::utils::data as D;

use getopts::Options;
use std::env;

fn MNIST() -> D::Dataset<D::Batch<f32, i64>> {
    unimplemented!()
}

#[derive(Clone, Builder)]
struct NetArgs {
    #[builder(default="64")]
    batch_size: usize,
    #[builder(default="1000")]
    test_batch_size: usize,
    #[builder(default="10")]
    epochs: u32,
    #[builder(default="0.01")]
    lr: f32,
    #[builder(default="0.5")]
    momentum: f32,
    #[builder(default="true")]
    cuda: bool,
    #[builder(default="1")]
    seed: usize,
    #[builder(default="10")]
    log_interval: usize,
}

impl Default for NetArgs {
    fn default() -> Self {
        NetArgsBuilder::default().build().unwrap()
    }
}

fn parse_args() -> NetArgs {
    let cmd_args: Vec<String> = env::args().collect();
    let mut args = NetArgs::default();
    let mut opts = Options::new();
    unimplemented!();
    /*
    	* XXX do parsey stuff
    	*/
    args
}

#[derive(ModParse)]
struct Net<T: Default + Copy> {
    delegate: nn::Module<T>,
    conv1: nn::Conv2d<T>,
    conv2: nn::Conv2d<T>,
    fc1: nn::Linear<T>,
    fc2: nn::Linear<T>,
}

impl<T: Default + Copy> Net<T> {
    pub fn new() -> Net<T> {
        Net {
                delegate: nn::Module::new(),
                conv1: nn::Conv2d::build(1, 10, (5, 5)).done(),
                conv2: nn::Conv2d::build(10, 20, (5, 5)).done(),
                fc1: nn::Linear::build(320, 50).done(),
                fc2: nn::Linear::build(50, 10).done(),
            }
            .init_module()
    }
}
impl_mod_delegate!(Net);

// The forward operations could take on one of two implementations.
// The first supporting a near verbatim version of the python
// implementation, and the second supporting a slightly more
// idiomatic to Rust method chaining.

// a) as a near verbatim implementation of the python version
impl ModIntf<f32> for Net<f32> {
    fn forward(&mut self, args: &mut Variable<f32>) -> Variable<f32> {
        let training = self.delegate.training;
        let pool_val = F::MaxPool2dArgs::default();
        let dropout_val = F::DropoutArgs::default();
        let mut x = F::relu(&F::max_pool2d(&self.conv1.f(args), (2, 2), &pool_val));
        let mut x = F::relu(&F::max_pool2d(&F::dropout2d(&self.conv2.f(&mut x), &dropout_val),
                                           (2, 2),
                                           &pool_val));
        let mut x = x.view(&[-1, 320]);
        let x = F::relu(&self.fc1.f(&mut x));
        let mut x = F::dropout(&x, &dropout_val);
        let x = self.fc2.f(&mut x);
        F::log_softmax(&x)
    }
}

fn train(model: &mut Net<f32>,
         args: &NetArgs,
         train_loader: &D::BatchLoader<f32, i64>,
         epoch: u32,
         optimizer: &mut optim::OptIntf) {
    model.train();
    for (batch_idx, (ref data, ref target)) in train_loader.iter().enumerate() {
        let (mut data, target) = if args.cuda {
            (Variable::new(data.cuda().clone()), Variable::new(target.cuda().clone()))
        } else {
            (Variable::new(data.clone()), Variable::new(target.clone()))
        };
        optimizer.zero_grad();
        let output = model.f(&mut data);
        let mut loss = F::nll_loss(&output, &target, &F::NLLLossArgs::default());
        loss.backward();
        optimizer.step();
        if batch_idx % args.log_interval == 0 {
            println!("Train Epoch: {} [{}/{} ({:.0}%)]\tLoss: {:.6}",
                     epoch,
                     batch_idx * data.data().len(),
                     train_loader.dataset.len(),
                     100. * (batch_idx as f32) / train_loader.len() as f32,
                     loss.data()[0]);
        }
    }
}

fn test(model: &mut Net<f32>, args: &NetArgs, test_loader: &D::BatchLoader<f32, i64>, epoch: u32) {
    model.eval();
    let mut test_loss = 0.;
    let mut correct = 0;
    for (ref data, ref target) in test_loader.iter() {
        let varargs = VariableArgs {
            volatile: true,
            ..Default::default()
        };
        let (mut data, mut target) = if args.cuda {
            (Variable::new_args(data.cuda().clone(), &varargs),
             Variable::new(target.cuda().clone()))
        } else {
            (Variable::new_args(data.clone(), &varargs), Variable::new(target.clone()))
        };
        let mut output = model.f(&mut data);
        test_loss += F::nll_loss(&output, &target, &F::NLLLossArgs::default());
        let pred = output.data().reduce_max(1).1;
        correct += pred.tensor_eq(&*target.data()).cpu().sum();
    }
    test_loss /= test_loader.len() as f32;
    println!("\nTest set: Average loss: {:.4}, Accuracy: {}/{} ({:.0}%)\n",
             test_loss,
             correct,
             test_loader.dataset.len(),
             100. * (correct as f32) / (test_loader.dataset.len() as f32))

}

fn main() {
    // no data loaders yet so demonstrate with Vec placeholder
    let train_loader: D::BatchLoader<f32, i64> = D::DataLoader::new(MNIST(),
                                                                    D::DataLoaderArgs::default());
    let test_loader: D::BatchLoader<f32, i64> = D::DataLoader::new(MNIST(),
                                                                   D::DataLoaderArgs::default());
    let args = parse_args();
    let mut optimizer = optim::SGD::new();

    let mut model = Net::new();
    for epoch in 1..args.epochs + 1 {
        train(&mut model, &args, &train_loader, epoch, &mut optimizer);
        test(&mut model, &args, &test_loader, epoch);
    }
}
<commit_msg>fix compile post-update<commit_after>extern crate getopts;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;

#[macro_use]
extern crate torchrs;

use torchrs::autograd::{Variable, VariableArgs, VarAccess};
use torchrs::tensor::Tensor;
use torchrs::optim;

use torchrs::macros::*;
use torchrs::nn;
use torchrs::nn::{ModuleStruct, ModIntf, ModDelegate, Module};
use torchrs::nn::functional as F;
use torchrs::utils::data as D;

use getopts::Options;
use std::env;

fn MNIST() -> D::Dataset<D::Batch<f32, i64>> {
    unimplemented!()
}

#[derive(Clone, Builder)]
struct NetArgs {
    #[builder(default="64")]
    batch_size: usize,
    #[builder(default="1000")]
    test_batch_size: usize,
    #[builder(default="10")]
    epochs: u32,
    #[builder(default="0.01")]
    lr: f32,
    #[builder(default="0.5")]
    momentum: f32,
    #[builder(default="true")]
    cuda: bool,
    #[builder(default="1")]
    seed: usize,
    #[builder(default="10")]
    log_interval: usize,
}

impl Default for NetArgs {
    fn default() -> Self {
        NetArgsBuilder::default().build().unwrap()
    }
}

fn parse_args() -> NetArgs {
    let cmd_args: Vec<String> = env::args().collect();
    let mut args = NetArgs::default();
    let mut opts = Options::new();
    unimplemented!();
    /*
    	* XXX do parsey stuff
    	*/
    args
}

#[derive(ModParse)]
struct Net<T: Default + Copy> {
    delegate: nn::Module<T>,
    conv1: nn::Conv2d<T>,
    conv2: nn::Conv2d<T>,
    fc1: nn::Linear<T>,
    fc2: nn::Linear<T>,
}

impl<T: Default + Copy> Net<T> {
    pub fn new() -> Net<T> {
        Net {
                delegate: nn::Module::new(),
                conv1: nn::Conv2d::build(1, 10, (5, 5)).done(),
                conv2: nn::Conv2d::build(10, 20, (5, 5)).done(),
                fc1: nn::Linear::build(320, 50).done(),
                fc2: nn::Linear::build(50, 10).done(),
            }
            .init_module()
    }
}
impl_mod_delegate!(Net);

// The forward operations could take on one of two implementations.
// The first supporting a near verbatim version of the python
// implementation, and the second supporting a slightly more
// idiomatic to Rust method chaining.

// a) as a near verbatim implementation of the python version
impl ModIntf<f32> for Net<f32> {
    fn forward(&mut self, args: &mut Variable<f32>) -> Variable<f32> {
        let training = self.delegate.training;
        let pool_val = F::MaxPool2dArgs::default();
        let dropout_val = F::DropoutArgs::default();
        let mut x = F::relu(&F::max_pool2d(&self.conv1.f(args), (2, 2), &pool_val));
        let mut x = F::relu(&F::max_pool2d(&F::dropout2d(&self.conv2.f(&mut x), &dropout_val),
                                           (2, 2),
                                           &pool_val));
        let mut x = x.view(&[-1, 320]);
        let x = F::relu(&self.fc1.f(&mut x));
        let mut x = F::dropout(&x, &dropout_val);
        let x = self.fc2.f(&mut x);
        F::log_softmax(&x)
    }
}

fn train(model: &mut Net<f32>,
         args: &NetArgs,
         train_loader: &D::BatchLoader<f32, i64>,
         epoch: u32,
         optimizer: &mut optim::OptIntf) {
    model.train();
    for (batch_idx, (ref data, ref target)) in train_loader.iter().enumerate() {
        let (mut data, target) = if args.cuda {
            (Variable::new(data.cuda(None).clone()), Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new(data.clone()), Variable::new(target.clone()))
        };
        optimizer.zero_grad();
        let output = model.f(&mut data);
        let mut loss = F::nll_loss(&output, &target, &F::NLLLossArgs::default());
        loss.backward();
        optimizer.step();
        if batch_idx % args.log_interval == 0 {
            println!("Train Epoch: {} [{}/{} ({:.0}%)]\tLoss: {:.6}",
                     epoch,
                     batch_idx * data.data().len(),
                     train_loader.dataset.len(),
                     100. * (batch_idx as f32) / train_loader.len() as f32,
                     loss.data()[0]);
        }
    }
}

fn test(model: &mut Net<f32>, args: &NetArgs, test_loader: &D::BatchLoader<f32, i64>) {
    model.eval();
    let mut test_loss = 0.;
    let mut correct = 0;
    for (ref data, ref target) in test_loader.iter() {
        let varargs = VariableArgs {
            volatile: true,
            ..Default::default()
        };
        let (mut data, mut target) = if args.cuda {
            (Variable::new_args(data.cuda(None).clone(), &varargs),
             Variable::new(target.cuda(None).clone()))
        } else {
            (Variable::new_args(data.clone(), &varargs), Variable::new(target.clone()))
        };
        let mut output = model.f(&mut data);
        test_loss += F::nll_loss(&output, &target, &F::NLLLossArgs::default());
        let pred = output.data().max_reduce(1).1;
        correct += pred.eq_tensor(&*target.data()).cpu().sum() as u32;
    }
    test_loss /= test_loader.len() as f32;
    println!("\nTest set: Average loss: {:.4}, Accuracy: {}/{} ({:.0}%)\n",
             test_loss,
             correct,
             test_loader.dataset.len(),
             100. * (correct as f32) / (test_loader.dataset.len() as f32))

}

fn main() {
    // no data loaders yet so demonstrate with Vec placeholder
    let train_loader: D::BatchLoader<f32, i64> = D::DataLoader::new(MNIST(),
                                                                    D::DataLoaderArgs::default());
    let test_loader: D::BatchLoader<f32, i64> = D::DataLoader::new(MNIST(),
                                                                   D::DataLoaderArgs::default());
    let args = parse_args();
    let mut optimizer = optim::SGD::new();

    let mut model = Net::new();
    for epoch in 1..args.epochs + 1 {
        train(&mut model, &args, &train_loader, epoch, &mut optimizer);
        test(&mut model, &args, &test_loader);
    }
}
<|endoftext|>


<commit_before>//! Processor
//!
//! ## Terminololgy
//! * Evaluator - a code fragment to evaluate an expression
//! * Processor - A list of evaluators
//!
//! ## Phases for Generation
//!

use std::rc::Rc;

use common::err::{Result, Void, void_ok};
use common::func::{
	NoArgFn,
	UnaryFn,
	BinaryFn,
	TrinityFn
};
use common::plugin::{
	FuncRegistry,
	TypeRegistry
};
use common::rows::{
	Page,
	PageBuilder,
	PageId
};
use common::session::Session;
use common::types::Ty;
use plan::expr::*;
use plan::expr::visitor::{accept_by_default, Visitor};

use driver::DriverContext;

pub trait Processor
{
  fn process(
    &self,
    input: &Page,
    builder: &mut PageBuilder) -> Void;
}

pub trait ProcessorFactory
{
	fn create(&self, ctx: &DriverContext) -> Result<Box<Processor>>;
}

pub trait Evaluator
{
	fn evaluate(&self, input: &Page, &mut PageBuilder) -> Void;

	fn ty(&self) -> &Ty;
}

pub trait EvaluatorFactory
{
	fn create(&self, ctx: &DriverContext) -> Result<Box<Evaluator>>;

  fn types(&self) -> &Ty;
}

pub struct NoArgFnEvaluator
{
	f: NoArgFn,
	output_pid: PageId
}

pub struct UnaryFnEvaluator
{
	f: UnaryFn,
	input_pid: PageId,
	output_pid: PageId
}

pub struct BinaryFnEvaluator
{
	f: BinaryFn,
	lhs_pid: PageId,
	rhs_pid: PageId,
	output_pid: PageId
}

pub struct Interpreter<'a>
{
	ty_registry: &'a TypeRegistry,
	fn_registry: &'a FuncRegistry,
	stack      : Vec<Box<EvaluatorFactory>>
}

impl<'a> Interpreter<'a>
{
	pub fn build(session: &Session,
		        ty_register: &TypeRegistry,
					  fn_registry: &FuncRegistry,
					  expression : &Expr) -> Result<Box<EvaluatorFactory>>
	{
		unimplemented!()
  }

	pub fn Not(&self, c: &Expr)
	{
	}

	pub fn IsNull(&self, c: &Expr)
	{
	}

	pub fn IsNotNull(&self, c: &Expr)
	{
	}

	pub fn PlusSign(&self, c: &Expr)
	{
	}

	pub fn MinusSign(&self, c: &Expr)
	{
	}

	pub fn Cast(&self, c: &Expr, from: &Ty, to: &Ty)
	{
	}

	pub fn And(&self, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Or(&self, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Cmp(&self, op: &CmpOp, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Arithm(&self, op: &ArithmOp, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Func(&self, f: &FnDecl, args: &Vec<Box<Expr>>)
	{
	}
}

pub struct UnaryEvaluatorFactory
{
	f: EvaluatorFactory
}

impl<'a> visitor::Visitor for Interpreter<'a>
{
	fn accept(&mut self, e: &Expr)
	{
	  match *e.kind() {
	    ExprKind::Not      (ref c)               => self.Not(c),
	    ExprKind::IsNull   (ref c)               => self.IsNull(c),
	    ExprKind::IsNotNull(ref c)               => self.IsNotNull(c),
	    ExprKind::PlusSign (ref c)               => self.PlusSign(c),
	    ExprKind::MinusSign(ref c)               => self.MinusSign(c),
	    ExprKind::Cast     (ref c, ref f, ref t) => self.Cast(c, f, t),

	    ExprKind::And      (ref l, ref r)        => self.And(l, r),
	    ExprKind::Or       (ref l, ref r)        => self.And(l, r),
	    ExprKind::Cmp      (ref o, ref l, ref r) => self.Cmp(o, l, r),
	    ExprKind::Arithm   (ref o, ref l, ref r) => self.Arithm(o, l, r),

	    ExprKind::Fn     (ref f, ref args)  => self.Func(f, args),
			ExprKind::Field  (_) 	          => {},
			/*
	    ExprKind::Const  (_)            => {}

	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },*/
	    _ => panic!("")
	  }
	}
}

pub struct InterpreterProcessorFactory
{
	factories: Vec<Box<EvaluatorFactory>>
}

impl InterpreterProcessorFactory
{
	pub fn new(exprs: Vec<Box<Expr>>) -> Box<ProcessorFactory>
	{
		Box::new(InterpreterProcessorFactory {
  		factories: Vec::new()
		})
	}
}

impl ProcessorFactory for InterpreterProcessorFactory
{
	fn create(&self, ctx: &DriverContext) -> Result<Box<Processor>>
	{
		let evals = try!(self.factories
									.iter()
									.map(|f| f.create(ctx))
									.collect::<Result<Vec<Box<Evaluator>>>>());

		Ok(Box::new(InterpreterProcessor {
			evals: evals
		}))
	}
}

pub struct InterpreterProcessor
{
	evals: Vec<Box<Evaluator>>
}

impl Processor for InterpreterProcessor
{
	fn process(
    &self,
    input: &Page,
    builder: &mut PageBuilder) -> Void
	{
  	for e in self.evals.iter() {
  		try!(e.evaluate(input, builder));
  	}

  	void_ok
  }
}<commit_msg>Add TPCH Q1 unit test for Processor.<commit_after>//! Processor
//!
//! ## Terminololgy
//! * Evaluator - a code fragment to evaluate an expression
//! * Processor - A list of evaluators
//!
//! ## Phases for Generation
//!

use std::rc::Rc;

use common::err::{Result, Void, void_ok};
use common::func::{
	NoArgFn,
	UnaryFn,
	BinaryFn,
	TrinityFn
};
use common::plugin::{
	FuncRegistry,
	TypeRegistry
};
use common::rows::{
	Page,
	PageBuilder,
	PageId
};
use common::session::Session;
use common::types::*;
use plan::expr::*;
use plan::expr::visitor::{accept_by_default, Visitor};

use driver::DriverContext;

pub trait Processor
{
  fn process(
    &self,
    input: &Page,
    builder: &mut PageBuilder) -> Void;
}

pub trait ProcessorFactory
{
	fn create(&self, ctx: &DriverContext) -> Result<Box<Processor>>;
}

pub trait Evaluator
{
	fn evaluate(&self, input: &Page, &mut PageBuilder) -> Void;

	fn ty(&self) -> &Ty;
}

pub trait EvaluatorFactory
{
	fn create(&self, ctx: &DriverContext) -> Result<Box<Evaluator>>;

  fn types(&self) -> &Ty;
}

pub struct NoArgFnEvaluator
{
	f: NoArgFn,
	output_pid: PageId
}

pub struct UnaryFnEvaluator
{
	f: UnaryFn,
	input_pid: PageId,
	output_pid: PageId
}

pub struct BinaryFnEvaluator
{
	f: BinaryFn,
	lhs_pid: PageId,
	rhs_pid: PageId,
	output_pid: PageId
}

pub struct Interpreter<'a>
{
	ty_registry: &'a TypeRegistry,
	fn_registry: &'a FuncRegistry,
	stack      : Vec<Box<EvaluatorFactory>>
}

impl<'a> Interpreter<'a>
{
	pub fn build(session: &Session,
		        ty_register: &TypeRegistry,
					  fn_registry: &FuncRegistry,
					  expression : &Expr) -> Result<Box<EvaluatorFactory>>
	{
		unimplemented!()
  }

	pub fn Not(&self, c: &Expr)
	{
	}

	pub fn IsNull(&self, c: &Expr)
	{
	}

	pub fn IsNotNull(&self, c: &Expr)
	{
	}

	pub fn PlusSign(&self, c: &Expr)
	{
	}

	pub fn MinusSign(&self, c: &Expr)
	{
	}

	pub fn Cast(&self, c: &Expr, f: &Ty, t: &Ty)
	{
	}

	pub fn And(&self, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Or(&self, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Cmp(&self, op: &CmpOp, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Arithm(&self, op: &ArithmOp, lhs: &Expr, rhs: &Expr)
	{
	}

	pub fn Func(&self, f: &FnDecl, args: &Vec<Box<Expr>>)
	{
	}
}

pub struct UnaryEvaluatorFactory
{
	f: EvaluatorFactory
}

impl<'a> visitor::Visitor for Interpreter<'a>
{
	fn accept(&mut self, e: &Expr)
	{
	  match *e.kind() {
	    ExprKind::Not      (ref c)               => self.Not(c),
	    ExprKind::IsNull   (ref c)               => self.IsNull(c),
	    ExprKind::IsNotNull(ref c)               => self.IsNotNull(c),
	    ExprKind::PlusSign (ref c)               => self.PlusSign(c),
	    ExprKind::MinusSign(ref c)               => self.MinusSign(c),
	    ExprKind::Cast     (ref c, ref f, ref t) => self.Cast(c, f, t),

	    ExprKind::And      (ref l, ref r)        => self.And(l, r),
	    ExprKind::Or       (ref l, ref r)        => self.And(l, r),
	    ExprKind::Cmp      (ref o, ref l, ref r) => self.Cmp(o, l, r),
	    ExprKind::Arithm   (ref o, ref l, ref r) => self.Arithm(o, l, r),

	    ExprKind::Fn     (ref f, ref args)  => self.Func(f, args),
			ExprKind::Field  (_) 	          => {},
			/*
	    ExprKind::Const  (_)            => {}

	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },*/
	    _ => panic!("")
	  }
	}
}

pub struct InterpreterProcessorFactory
{
	factories: Vec<Box<EvaluatorFactory>>
}

impl InterpreterProcessorFactory
{
	pub fn new(exprs: &Vec<Box<Expr>>) -> Box<ProcessorFactory>
	{
		Box::new(InterpreterProcessorFactory {
  		factories: Vec::new()
		})
	}
}

impl ProcessorFactory for InterpreterProcessorFactory
{
	fn create(&self, ctx: &DriverContext) -> Result<Box<Processor>>
	{
		let evals = try!(self.factories
									.iter()
									.map(|f| f.create(ctx))
									.collect::<Result<Vec<Box<Evaluator>>>>());

		Ok(Box::new(InterpreterProcessor {
			evals: evals
		}))
	}
}

pub struct InterpreterProcessor
{
	evals: Vec<Box<Evaluator>>
}

impl Processor for InterpreterProcessor
{
	fn process(
    &self,
    input: &Page,
    builder: &mut PageBuilder) -> Void
	{
  	for e in self.evals.iter() {
  		try!(e.evaluate(input, builder));
  	}

  	void_ok
  }
}

#[cfg(test)]
mod tests {
	use common::rows::{
		Page,
		PageBuilder,
		PageId
	};
	use common::plugin::*;
	use common::session::Session;
	use common::storage::{RandomTable, MemTable};
	use common::types::*;

	use plan::expr::*;
	use driver::DriverContext;

	use super::*;

	#[test]
	pub fn tpch_q1() {
		let plugin_mgr = PluginManager::new();

		/*
			l_orderkey long,
			l_partkey long,
			l_suppkey long,
			l_linenumber int,
			l_quantity double,
			l_extendedprice double,
			l_discount double,
			l_tax double,
			l_returnflag string,
			l_linestatus string,
			l_shipdate string,
			l_commitdate string,
			l_receiptdate string,
			l_shipinstruct string,
			l_shipmode string,
			l_comment string
		*/
		let types: Vec<Ty> = vec![
	    i64_ty(), // l_orderkey      bigint
	    i64_ty(), // l_partkey       bigint
	    i64_ty(), // l_suppkey       bigint
	    i32_ty(), // l_linenumber    int
	    f64_ty(), // l_quantity      double,
	    f64_ty(), // l_extendedprice double,
	    f64_ty(), // l_discount      double,
	    f64_ty(), // l_tax           double,
	    // string types are not implmeneted yet.
	  ];

	  let sum_disc_price =
	  	Mul(
	  		&f64_ty(), Field(&f64_ty(), "l_extendedprice"), Subtract(&f64_ty(), Const(1), Field(&f64_ty(), "l_discount")));

  	let sum_charge =
	  	Mul(&f64_ty(), sum_disc_price.clone(), Plus(&f64_ty(), Const(1), Field(&f64_ty(), "l_tax")));

	  let exprs = vec![
	  	Box::new(sum_disc_price),
	  	Box::new(sum_charge)
  	];
		let factory = InterpreterProcessorFactory::new(&exprs);
		let drv_ctx = DriverContext::new(plugin_mgr.ty_registry(), plugin_mgr.fn_registry());
		let processor = factory.create(&drv_ctx).ok().unwrap();

		let session    = Session;
		let mut input  = RandomTable::new(&session, &types, 1024);

		let output_tys = exprs.iter()
											.map(|e| e.ty().clone())
											.collect::<Vec<Ty>>();
		let mut output = MemTable::new(&session, &output_tys, &vec!["x","y"]);

		let mut builder = PageBuilder::new(&output_tys);

		loop {
		  let mut read_page = input.next().unwrap();

		  if read_page.value_count() == 0 {
		  	break;
		  }

		  processor.process(read_page, &mut builder);
		  output.write(builder.build(read_page.value_count()));
		  builder.reset();
		}
	}
}<|endoftext|>


<commit_before>//! Store XML element attributes and their values.

use std::mem;
use std::slice;
use std::str;

use markup5ever::{namespace_url, LocalName, Namespace, Prefix, QualName};

use crate::util::{opt_utf8_cstr, utf8_cstr};

/// Iterable wrapper for libxml2's representation of attribute/value.
///
/// See the [`new_from_xml2_attributes`] function for information.
///
/// [`new_from_xml2_attributes`]: #method.new_from_xml2_attributes
pub struct Attributes<'a>(Vec<(QualName, &'a str)>);

/// Iterator from `Attributes.iter`.
pub struct AttributesIter<'a>(slice::Iter<'a, (QualName, &'a str)>);

impl<'a> Attributes<'a> {
    /// Creates an iterable `Attributes` from the C array of borrowed C strings.
    ///
    /// With libxml2's SAX parser, the caller's startElementNsSAX2Func
    /// callback gets passed a `xmlChar **` for attributes, which
    /// comes in groups of (localname/prefix/URI/value_start/value_end).
    /// In those, localname/prefix/URI are NUL-terminated strings;
    /// value_start and value_end point to the start-inclusive and
    /// end-exclusive bytes in the attribute's value.
    ///
    /// This function is unsafe because the caller must guarantee the following:
    ///
    /// * `attrs` is a valid pointer, with (n_attributes * 5) elements.
    ///
    /// * All strings are valid UTF-8.
    ///
    /// The lifetime of the `Attributes` should be considered the same as the lifetime of the
    /// `attrs` array, as the `Attributes` does not copy the strings - it directly stores pointers
    /// into that array's strings.
    pub unsafe fn new_from_xml2_attributes(
        n_attributes: usize,
        attrs: *const *const libc::c_char,
    ) -> Attributes<'a> {
        let mut array = Vec::new();

        if n_attributes > 0 && !attrs.is_null() {
            for attr in slice::from_raw_parts(attrs, n_attributes * 5).chunks_exact(5) {
                let localname = attr[0];
                let prefix = attr[1];
                let uri = attr[2];
                let value_start = attr[3];
                let value_end = attr[4];

                assert!(!localname.is_null());

                let localname = utf8_cstr(localname);

                let prefix = opt_utf8_cstr(prefix);
                let uri = opt_utf8_cstr(uri);
                let qual_name = QualName::new(
                    prefix.map(Prefix::from),
                    uri.map(Namespace::from)
                        .unwrap_or_else(|| namespace_url!("")),
                    LocalName::from(localname),
                );

                if !value_start.is_null() && !value_end.is_null() {
                    assert!(value_end >= value_start);

                    // FIXME: ptr::offset_from() is nightly-only.
                    // We'll do the computation of the length by hand.
                    let start: usize = mem::transmute(value_start);
                    let end: usize = mem::transmute(value_end);
                    let len = end - start;

                    let value_slice = slice::from_raw_parts(value_start as *const u8, len);
                    let value_str = str::from_utf8_unchecked(value_slice);

                    array.push((qual_name, value_str));
                }
            }
        }

        Attributes(array)
    }

    /// Returns the number of attributes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Creates an iterator that yields `(QualName, &'a str)` tuples.
    pub fn iter(&self) -> AttributesIter<'_> {
        AttributesIter(self.0.iter())
    }
}

impl<'a> Iterator for AttributesIter<'a> {
    type Item = (QualName, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(a, v)| (a.clone(), <&str>::clone(v)))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use markup5ever::{expanded_name, local_name, namespace_url, ns};
    use std::ffi::CString;
    use std::ptr;

    #[test]
    fn empty_attributes() {
        let map = unsafe { Attributes::new_from_xml2_attributes(0, ptr::null()) };
        assert_eq!(map.len(), 0);
    }

    #[test]
    fn attributes_with_namespaces() {
        let attrs = [
            (
                CString::new("href").unwrap(),
                Some(CString::new("xlink").unwrap()),
                Some(CString::new("http://www.w3.org/1999/xlink").unwrap()),
                CString::new("1").unwrap(),
            ),
            (
                CString::new("ry").unwrap(),
                None,
                None,
                CString::new("2").unwrap(),
            ),
            (
                CString::new("d").unwrap(),
                None,
                None,
                CString::new("").unwrap(),
            ),
        ];

        let mut v: Vec<*const libc::c_char> = Vec::new();

        for (localname, prefix, uri, val) in &attrs {
            v.push(localname.as_ptr() as *const libc::c_char);
            v.push(
                prefix
                    .as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );
            v.push(
                uri.as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );

            let val_start = val.as_ptr() as *const libc::c_char;
            let val_end = unsafe { val_start.offset(val.as_bytes().len() as isize) };
            v.push(val_start); // value_start
            v.push(val_end); // value_end
        }

        let attrs = unsafe { Attributes::new_from_xml2_attributes(3, v.as_ptr()) };

        let mut had_href: bool = false;
        let mut had_ry: bool = false;
        let mut had_d: bool = false;

        for (a, v) in attrs.iter() {
            match a.expanded() {
                expanded_name!(xlink "href") => {
                    assert!(v == "1");
                    had_href = true;
                }

                expanded_name!("", "ry") => {
                    assert!(v == "2");
                    had_ry = true;
                }

                expanded_name!("", "d") => {
                    assert!(v == "");
                    had_d = true;
                }

                _ => unreachable!(),
            }
        }

        assert!(had_href);
        assert!(had_ry);
        assert!(had_d);
    }
}
<commit_msg>In Attributes, store the values long-term as interned atoms<commit_after>//! Store XML element attributes and their values.

use std::mem;
use std::slice;
use std::str;

use markup5ever::{namespace_url, LocalName, Namespace, Prefix, QualName};
use string_cache::DefaultAtom;

use crate::util::{opt_utf8_cstr, utf8_cstr};

/// Type used to store attribute values.
///
/// Attribute values are often repeated in an SVG file, so we intern them using the
/// string_cache crate.
pub type AttributeValue = DefaultAtom;

/// Iterable wrapper for libxml2's representation of attribute/value.
///
/// See the [`new_from_xml2_attributes`] function for information.
///
/// [`new_from_xml2_attributes`]: #method.new_from_xml2_attributes
pub struct Attributes(Vec<(QualName, AttributeValue)>);

/// Iterator from `Attributes.iter`.
pub struct AttributesIter<'a>(slice::Iter<'a, (QualName, AttributeValue)>);

impl Attributes {
    /// Creates an iterable `Attributes` from the C array of borrowed C strings.
    ///
    /// With libxml2's SAX parser, the caller's startElementNsSAX2Func
    /// callback gets passed a `xmlChar **` for attributes, which
    /// comes in groups of (localname/prefix/URI/value_start/value_end).
    /// In those, localname/prefix/URI are NUL-terminated strings;
    /// value_start and value_end point to the start-inclusive and
    /// end-exclusive bytes in the attribute's value.
    ///
    /// This function is unsafe because the caller must guarantee the following:
    ///
    /// * `attrs` is a valid pointer, with (n_attributes * 5) elements.
    ///
    /// * All strings are valid UTF-8.
    ///
    /// The lifetime of the `Attributes` should be considered the same as the lifetime of the
    /// `attrs` array, as the `Attributes` does not copy the strings - it directly stores pointers
    /// into that array's strings.
    pub unsafe fn new_from_xml2_attributes(
        n_attributes: usize,
        attrs: *const *const libc::c_char,
    ) -> Attributes {
        let mut array = Vec::new();

        if n_attributes > 0 && !attrs.is_null() {
            for attr in slice::from_raw_parts(attrs, n_attributes * 5).chunks_exact(5) {
                let localname = attr[0];
                let prefix = attr[1];
                let uri = attr[2];
                let value_start = attr[3];
                let value_end = attr[4];

                assert!(!localname.is_null());

                let localname = utf8_cstr(localname);

                let prefix = opt_utf8_cstr(prefix);
                let uri = opt_utf8_cstr(uri);
                let qual_name = QualName::new(
                    prefix.map(Prefix::from),
                    uri.map(Namespace::from)
                        .unwrap_or_else(|| namespace_url!("")),
                    LocalName::from(localname),
                );

                if !value_start.is_null() && !value_end.is_null() {
                    assert!(value_end >= value_start);

                    // FIXME: ptr::offset_from() is nightly-only.
                    // We'll do the computation of the length by hand.
                    let start: usize = mem::transmute(value_start);
                    let end: usize = mem::transmute(value_end);
                    let len = end - start;

                    let value_slice = slice::from_raw_parts(value_start as *const u8, len);
                    let value_str = str::from_utf8_unchecked(value_slice);
                    let value_atom = DefaultAtom::from(value_str);

                    array.push((qual_name, value_atom));
                }
            }
        }

        Attributes(array)
    }

    /// Returns the number of attributes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Creates an iterator that yields `(QualName, &'a str)` tuples.
    pub fn iter(&self) -> AttributesIter<'_> {
        AttributesIter(self.0.iter())
    }
}

impl<'a> Iterator for AttributesIter<'a> {
    type Item = (QualName, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(a, v)| (a.clone(), v.as_ref()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use markup5ever::{expanded_name, local_name, namespace_url, ns};
    use std::ffi::CString;
    use std::ptr;

    #[test]
    fn empty_attributes() {
        let map = unsafe { Attributes::new_from_xml2_attributes(0, ptr::null()) };
        assert_eq!(map.len(), 0);
    }

    #[test]
    fn attributes_with_namespaces() {
        let attrs = [
            (
                CString::new("href").unwrap(),
                Some(CString::new("xlink").unwrap()),
                Some(CString::new("http://www.w3.org/1999/xlink").unwrap()),
                CString::new("1").unwrap(),
            ),
            (
                CString::new("ry").unwrap(),
                None,
                None,
                CString::new("2").unwrap(),
            ),
            (
                CString::new("d").unwrap(),
                None,
                None,
                CString::new("").unwrap(),
            ),
        ];

        let mut v: Vec<*const libc::c_char> = Vec::new();

        for (localname, prefix, uri, val) in &attrs {
            v.push(localname.as_ptr() as *const libc::c_char);
            v.push(
                prefix
                    .as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );
            v.push(
                uri.as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );

            let val_start = val.as_ptr() as *const libc::c_char;
            let val_end = unsafe { val_start.offset(val.as_bytes().len() as isize) };
            v.push(val_start); // value_start
            v.push(val_end); // value_end
        }

        let attrs = unsafe { Attributes::new_from_xml2_attributes(3, v.as_ptr()) };

        let mut had_href: bool = false;
        let mut had_ry: bool = false;
        let mut had_d: bool = false;

        for (a, v) in attrs.iter() {
            match a.expanded() {
                expanded_name!(xlink "href") => {
                    assert!(v == "1");
                    had_href = true;
                }

                expanded_name!("", "ry") => {
                    assert!(v == "2");
                    had_ry = true;
                }

                expanded_name!("", "d") => {
                    assert!(v == "");
                    had_d = true;
                }

                _ => unreachable!(),
            }
        }

        assert!(had_href);
        assert!(had_ry);
        assert!(had_d);
    }
}
<|endoftext|>


<commit_before>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

 * BigRedRPG is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.

 * BigRedRPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU Affero General Public License
 * along with BigRedRPG.  If not, see <http://www.gnu.org/licenses/>.
 */

use chance::Chance;
use location::{LocationId, Map};
use student::{StatusKind, StatusModifier, Student, StudentId};

pub enum Trigger {
    Location(LocationId),
    Status(StatusKind, u32, u32),
    All(Vec<Trigger>),
    Any(Vec<Trigger>),
}

impl Trigger {
    pub fn evaluate(&self, student: &Student, location: LocationId) -> bool {
        use self::Trigger::*;
        match self {
            &Location(id) => id == location,
            &Status(kind, min, max) => false,
            &All(ref statuses) => statuses.iter().all(|x| x.evaluate(student, location)),
            &Any(ref statuses) => statuses.iter().any(|x| x.evaluate(student, location)),
        }
    }
}

pub enum SideEffect {
    // student, current, destination
    Move(StudentId, LocationId, LocationId),
}

impl SideEffect {
    pub fn apply(&self, map: &mut Map) {
        use self::SideEffect::*;

        match self {
            &Move(student, current, destination) => {
                let student = {
                    let current = map.get_mut(current)
                        .expect(&format!("location {:?} does not exist!", current));
                    current.remove_student_by_id(student)
                };
                let destination = map.get_mut(destination)
                    .expect(&format!("location {:?} does not exist!", destination));
                destination.add_student(student);
            }
        }
    }
}

pub enum EffectAction {
    Status(StatusModifier),
    Move(LocationId),
}

impl EffectAction {
    pub fn apply(&self, location: LocationId, target: &mut Student, side_effects: &mut Vec<SideEffect>) {
        use self::EffectAction::*;

        match self {
            &Status(ref modifier) => {
                target.apply_modifier(modifier.clone());
            }
            &Move(id) => {
                side_effects.push(SideEffect::Move(target.id, location, id));
            }
        }
    }
}

pub enum EffectTarget {
    Initiator,
    Participant,
    Both,
    None,
}

pub struct Effect {
    pub target: EffectTarget,
    pub action: EffectAction,
}

impl Effect {
    pub fn apply(&self, location: LocationId, initiator: &mut Student, side_effects: &mut Vec<SideEffect>) {
        self.action.apply(location, initiator, side_effects);
    }
}

pub struct Choice {
    pub description: String,
    pub effects: Vec<Effect>,
}

pub enum Disposition {
    Nature {
        name: String,
        modifier: i32,
    }
}

impl Disposition {
    pub fn value(&self, student: &Student) -> i32 {
        use self::Disposition::*;

        match self {
            &Nature { ref name, modifier } => {
                if student.has_nature(name.as_str()) {
                    return modifier
                }
            }
        }

        0
    }
}

pub struct Interaction {
    pub text: String,
    pub choices: Vec<(Choice, Chance, Vec<Disposition>)>,
    pub trigger: Trigger,
}
<commit_msg>feat(Interaction): add status-based trigger<commit_after>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

 * BigRedRPG is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.

 * BigRedRPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU Affero General Public License
 * along with BigRedRPG.  If not, see <http://www.gnu.org/licenses/>.
 */

use chance::Chance;
use location::{LocationId, Map};
use student::{StatusKind, StatusModifier, Student, StudentId};

pub enum Trigger {
    Location(LocationId),
    Status(StatusKind, u32, u32),
    All(Vec<Trigger>),
    Any(Vec<Trigger>),
}

impl Trigger {
    pub fn evaluate(&self, student: &Student, location: LocationId) -> bool {
        use self::Trigger::*;
        match self {
            &Location(id) => id == location,
            &Status(kind, min, max) => {
                let status = student.get_status(kind).value();

                status >= min && status <= max
            },
            &All(ref statuses) => statuses.iter().all(|x| x.evaluate(student, location)),
            &Any(ref statuses) => statuses.iter().any(|x| x.evaluate(student, location)),
        }
    }
}

pub enum SideEffect {
    // student, current, destination
    Move(StudentId, LocationId, LocationId),
}

impl SideEffect {
    pub fn apply(&self, map: &mut Map) {
        use self::SideEffect::*;

        match self {
            &Move(student, current, destination) => {
                let student = {
                    let current = map.get_mut(current)
                        .expect(&format!("location {:?} does not exist!", current));
                    current.remove_student_by_id(student)
                };
                let destination = map.get_mut(destination)
                    .expect(&format!("location {:?} does not exist!", destination));
                destination.add_student(student);
            }
        }
    }
}

pub enum EffectAction {
    Status(StatusModifier),
    Move(LocationId),
}

impl EffectAction {
    pub fn apply(&self, location: LocationId, target: &mut Student, side_effects: &mut Vec<SideEffect>) {
        use self::EffectAction::*;

        match self {
            &Status(ref modifier) => {
                target.apply_modifier(modifier.clone());
            }
            &Move(id) => {
                side_effects.push(SideEffect::Move(target.id, location, id));
            }
        }
    }
}

pub enum EffectTarget {
    Initiator,
    Participant,
    Both,
    None,
}

pub struct Effect {
    pub target: EffectTarget,
    pub action: EffectAction,
}

impl Effect {
    pub fn apply(&self, location: LocationId, initiator: &mut Student, side_effects: &mut Vec<SideEffect>) {
        self.action.apply(location, initiator, side_effects);
    }
}

pub struct Choice {
    pub description: String,
    pub effects: Vec<Effect>,
}

pub enum Disposition {
    Nature {
        name: String,
        modifier: i32,
    }
}

impl Disposition {
    pub fn value(&self, student: &Student) -> i32 {
        use self::Disposition::*;

        match self {
            &Nature { ref name, modifier } => {
                if student.has_nature(name.as_str()) {
                    return modifier
                }
            }
        }

        0
    }
}

pub struct Interaction {
    pub text: String,
    pub choices: Vec<(Choice, Chance, Vec<Disposition>)>,
    pub trigger: Trigger,
}
<|endoftext|>