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

use std::rc::*;

use super::component::*;
use super::super::tree::*;

struct FunctionComponent;

impl Component for FunctionComponent {
}

impl Drop for FunctionComponent {
    fn drop(&mut self) {
    }
}

///
/// Simplest form of 'component function': a function that receives a `TreeChange` indicating how the
/// input tree has changed, and returns a new change indicating how the output has changed.
///
impl ConvertToComponent for Box<Fn(&TreeChange) -> TreeChange> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let action              = self;

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let change_result = action(change);
            our_publisher.publish(change_result);
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Simplest form of 'component function': a function that receives a `TreeChange` indicating how the
/// input tree has changed, and returns a new change indicating how the output has changed.
///
/// This variant allows for mutable state.
///
impl ConvertToComponent for Box<FnMut(&TreeChange) -> TreeChange> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let mut action          = self;

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let change_result = action(change);
            our_publisher.publish(change_result);
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Provides a component function that converts an input tree to an output tree
///
impl ConvertToComponent for Box<Fn(&TreeRef) -> TreeRef> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let action              = self;

        let mut tree = "empty".to_tree_node();

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            tree = change.apply(&tree);

            let new_tree = action(&tree);

            our_publisher.publish(TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&new_tree)));
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Provides a component function that converts an input tree to an output tree
///
/// This variant allows for mutable state
///
impl ConvertToComponent for Box<FnMut(&TreeRef) -> TreeRef> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let mut action          = self;

        let mut tree = "empty".to_tree_node();

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            tree = change.apply(&tree);

            let new_tree = action(&tree);

            our_publisher.publish(TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&new_tree)));
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Makes a function into a variant that can be used with a suitable `into_component()` call.
///
/// Short for 'make component'
///
/// For example:
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let component = mk_com(|tree: &TreeRef| { tree.clone() }).into_component(consumer, publisher);
/// ```
///
/// This exists to get around some limitations in rust's type inference.
///
/// What would be neat is if we could do `(|change: &TreeRef| -> TreeRef { ... }).into_component()`
/// and have rust figure out that there's an implementation on a `Fn(&TreeRef) -> TreeRef` that we
/// can use to generate the result. Even `Box::new(...).into_component()` would be OK.
///
/// However, closures and Fns are different types and don't get coerced implicitly so that doesn't work.
/// That is, `Box::new(...).into_component()` will produce an error as the box has the closure type and rust
/// isn't smart enough to realise there's a cast to `Box<Fn()>`
///
/// Here's what you have to do as a result:
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let component_fn: Box<Fn(&TreeRef) -> TreeRef> = Box::new(|tree: &TreeRef| { tree.clone() });
/// let component = component_fn.into_component(consumer, publisher);
/// ```
///
/// Type inference: utterly defeated. (`Box::<Fn blah blah>::new` doesn't work either because it coerces the
/// closure to the Fn trait too early and thus produces an error)
///
/// To make this less of a nightmare to use, the mk_com function tells rust that a function can be boxed and
/// helps out by inferring the various parameters.
///
#[inline]
pub fn mk_com<TIn, TOut, F>(func: F) -> Box<Fn(&TIn) -> TOut> where F: Fn(&TIn) -> TOut + 'static {
    Box::new(func)
}

///
/// Version of mk_com that works on `FnMut` functions
///
/// For example:
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let mut times_run       = 0;
/// let component = mk_com_mut(move |tree: &TreeRef| {
///     times_run = times_run + 1;
///     tree.clone()
/// }).into_component(consumer, publisher);
/// ```
///
#[inline]
pub fn mk_com_mut<TIn, TOut, F>(func: F) -> Box<FnMut(&TIn) -> TOut> where F: FnMut(&TIn) -> TOut + 'static {
    Box::new(func)
}

///
/// Starts running a function as a component
///
/// # Example
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let pass_through_component = component(consumer, publisher, |tree: &TreeRef| { tree.clone() });
/// ```
///
#[inline]
pub fn component<TIn, TOut, F>(consumer: ConsumerRef, publisher: PublisherRef, func: F) -> ComponentRef
    where   F: Fn(&TIn) -> TOut + 'static,
            Box<Fn(&TIn) -> TOut> : ConvertToComponent {
    mk_com(func).into_component(consumer, publisher)
}

///
/// Starts running a mutable function as a component
///
/// # Example
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let mut times_run       = 0;
/// let pass_through_component = component_mut(consumer, publisher, move |tree: &TreeRef| {
///     times_run = times_run + 1;
///     tree.clone()
/// });
/// ```
///
#[inline]
pub fn component_mut<TIn, TOut, F>(consumer: ConsumerRef, publisher: PublisherRef, func: F) -> ComponentRef
    where   F: FnMut(&TIn) -> TOut + 'static,
            Box<FnMut(&TIn) -> TOut> : ConvertToComponent {
    mk_com_mut(func).into_component(consumer, publisher)
}

#[cfg(test)]
mod component_function_tests {
    use super::super::super::component::*;
    use super::super::immediate_publisher::*;
    use super::super::output_tree_publisher::*;

    #[test]
    pub fn can_create_tree_change_component() {
        let mut input_publisher = ImmediatePublisher::new();
        let consumer            = input_publisher.create_consumer();

        let output_publisher    = OutputTreePublisher::new();
        let result_reader       = output_publisher.get_tree_reader();

        let _component = component(consumer, output_publisher, |_change: &TreeChange| {
            TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"passed".to_tree_node()))
        });

        // Publish something to our function
        input_publisher.publish(TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"test".to_tree_node())));

        // Check that the output was 'passed'
        let result = result_reader();
        assert!(result.get_tag() == "passed")
    }
}
<commit_msg>Rename mk_com() to component_fn() and component() to to_component() to hopefully increase readability a bit<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::rc::*;

use super::component::*;
use super::super::tree::*;

struct FunctionComponent;

impl Component for FunctionComponent {
}

impl Drop for FunctionComponent {
    fn drop(&mut self) {
    }
}

///
/// Simplest form of 'component function': a function that receives a `TreeChange` indicating how the
/// input tree has changed, and returns a new change indicating how the output has changed.
///
impl ConvertToComponent for Box<Fn(&TreeChange) -> TreeChange> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let action              = self;

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let change_result = action(change);
            our_publisher.publish(change_result);
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Simplest form of 'component function': a function that receives a `TreeChange` indicating how the
/// input tree has changed, and returns a new change indicating how the output has changed.
///
/// This variant allows for mutable state.
///
impl ConvertToComponent for Box<FnMut(&TreeChange) -> TreeChange> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let mut action          = self;

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let change_result = action(change);
            our_publisher.publish(change_result);
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Provides a component function that converts an input tree to an output tree
///
impl ConvertToComponent for Box<Fn(&TreeRef) -> TreeRef> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let action              = self;

        let mut tree = "empty".to_tree_node();

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            tree = change.apply(&tree);

            let new_tree = action(&tree);

            our_publisher.publish(TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&new_tree)));
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Provides a component function that converts an input tree to an output tree
///
/// This variant allows for mutable state
///
impl ConvertToComponent for Box<FnMut(&TreeRef) -> TreeRef> {
    ///
    /// Creates a component that consumes from a particular tree and publishes to a different tree
    ///
    fn into_component(self, consumer: ConsumerRef, publisher: PublisherRef) -> ComponentRef {
        let mut our_consumer    = consumer;
        let mut our_publisher   = publisher;
        let mut action          = self;

        let mut tree = "empty".to_tree_node();

        our_consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            tree = change.apply(&tree);

            let new_tree = action(&tree);

            our_publisher.publish(TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&new_tree)));
        }));

        return Rc::new(FunctionComponent);
    }
}

///
/// Makes a function into a variant that can be used with a suitable `into_component()` call.
///
/// For example:
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let component = component_fn(|tree: &TreeRef| { tree.clone() }).into_component(consumer, publisher);
/// ```
///
/// This exists to get around some limitations in rust's type inference.
///
/// What would be neat is if we could do `(|change: &TreeRef| -> TreeRef { ... }).into_component()`
/// and have rust figure out that there's an implementation on a `Fn(&TreeRef) -> TreeRef` that we
/// can use to generate the result. Even `Box::new(...).into_component()` would be OK.
///
/// However, closures and Fns are different types and don't get coerced implicitly so that doesn't work.
/// That is, `Box::new(...).into_component()` will produce an error as the box has the closure type and rust
/// isn't smart enough to realise there's a cast to `Box<Fn()>`
///
/// Here's what you have to do as a result:
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let component_fn: Box<Fn(&TreeRef) -> TreeRef> = Box::new(|tree: &TreeRef| { tree.clone() });
/// let component = component_fn.into_component(consumer, publisher);
/// ```
///
/// Type inference: utterly defeated. (`Box::<Fn blah blah>::new` doesn't work either because it coerces the
/// closure to the Fn trait too early and thus produces an error)
///
/// To make this less of a nightmare to use, the component_fn function tells rust that a function can be boxed and
/// helps out by inferring the various parameters.
///
#[inline]
pub fn component_fn<TIn, TOut, F>(func: F) -> Box<Fn(&TIn) -> TOut> where F: Fn(&TIn) -> TOut + 'static {
    Box::new(func)
}

///
/// Version of component_fn that works on `FnMut` functions
///
/// For example:
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let mut times_run       = 0;
/// let component = component_fn_mut(move |tree: &TreeRef| {
///     times_run = times_run + 1;
///     tree.clone()
/// }).into_component(consumer, publisher);
/// ```
///
#[inline]
pub fn component_fn_mut<TIn, TOut, F>(func: F) -> Box<FnMut(&TIn) -> TOut> where F: FnMut(&TIn) -> TOut + 'static {
    Box::new(func)
}

///
/// Starts running a function as a component
///
/// # Example
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let pass_through_component = to_component(consumer, publisher, |tree: &TreeRef| { tree.clone() });
/// ```
///
#[inline]
pub fn to_component<TIn, TOut, F>(consumer: ConsumerRef, publisher: PublisherRef, func: F) -> ComponentRef
    where   F: Fn(&TIn) -> TOut + 'static,
            Box<Fn(&TIn) -> TOut> : ConvertToComponent {
    component_fn(func).into_component(consumer, publisher)
}

///
/// Starts running a mutable function as a component
///
/// # Example
///
/// ```
/// # use tametree::component::*;
/// # use tametree::component::immediate_publisher::*;
/// #
/// # let input_publisher   = ImmediatePublisher::new();
/// # let consumer          = input_publisher.create_consumer();
/// # let publisher         = ImmediatePublisher::new();
/// let mut times_run       = 0;
/// let pass_through_component = to_component_mut(consumer, publisher, move |tree: &TreeRef| {
///     times_run = times_run + 1;
///     tree.clone()
/// });
/// ```
///
#[inline]
pub fn to_component_mut<TIn, TOut, F>(consumer: ConsumerRef, publisher: PublisherRef, func: F) -> ComponentRef
    where   F: FnMut(&TIn) -> TOut + 'static,
            Box<FnMut(&TIn) -> TOut> : ConvertToComponent {
    component_fn_mut(func).into_component(consumer, publisher)
}

#[cfg(test)]
mod component_function_tests {
    use super::super::super::component::*;
    use super::super::immediate_publisher::*;
    use super::super::output_tree_publisher::*;

    #[test]
    pub fn can_create_tree_change_component() {
        let mut input_publisher = ImmediatePublisher::new();
        let consumer            = input_publisher.create_consumer();

        let output_publisher    = OutputTreePublisher::new();
        let result_reader       = output_publisher.get_tree_reader();

        let _component = to_component(consumer, output_publisher, |_change: &TreeChange| {
            TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"passed".to_tree_node()))
        });

        // Publish something to our function
        input_publisher.publish(TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"test".to_tree_node())));

        // Check that the output was 'passed'
        let result = result_reader();
        assert!(result.get_tag() == "passed")
    }
}
<|endoftext|>


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

// External crates.
use std::ffi::CString;
use shader_version::{opengl, glsl};
use graphics::{ Context, Graphics };
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 {
    use shader_version::glsl::GLSL;
    match glsl {
        GLSL::_1_10 => panic!("GLSL 1.10 not supported"),
        GLSL::_1_20
      | GLSL::_1_30
      | 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);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_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 {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        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);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_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 {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        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,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: opengl::OpenGL) -> GlGraphics {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            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
    ) {
        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<F>(&mut self, viewport: [i32; 4], f: F)
        where
            F: FnOnce(Context, &mut GlGraphics)
    {
        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 Graphics for GlGraphics {
    type Texture = Texture;

    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 tri_list<F>(&mut self, color: &[f32; 4], mut f: F)
        where F: FnMut(&mut FnMut(&[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            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);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(&mut self, color: &[f32; 4], texture: &Texture, mut f: F)
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_fail]
fn test_gl_loaded() {
    GlGraphics::new(opengl::OpenGL::_3_2);
}
<commit_msg>Updated to latest piston-graphics<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use std::ffi::CString;
use shader_version::{opengl, glsl};
use graphics::{ Context, DrawState, Graphics };
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 {
    use shader_version::glsl::GLSL;
    match glsl {
        GLSL::_1_10 => panic!("GLSL 1.10 not supported"),
        GLSL::_1_20
      | GLSL::_1_30
      | 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);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_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 {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        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);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_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 {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        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,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: opengl::OpenGL) -> GlGraphics {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            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
    ) {
        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<F>(&mut self, viewport: [i32; 4], f: F)
        where
            F: FnOnce(Context, &mut GlGraphics)
    {
        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 Graphics for GlGraphics {
    type Texture = Texture;

    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 tri_list<F>(
        &mut self,
        _draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            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);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(
        &mut self,
        _draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_fail]
fn test_gl_loaded() {
    GlGraphics::new(opengl::OpenGL::_3_2);
}
<|endoftext|>


<commit_before>
//! Glyph caching

use error::Error;
use freetype::ffi;
use freetype;
use freetype::error::Error::MissingFontField;
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use graphics;

use Texture;

pub type FontSize = u32;

pub type Character = graphics::character::Character<Texture>;

/// A struct used for caching rendered font.
pub struct GlyphCache {
    /// The font face.
    pub face: freetype::Face,
    data: HashMap<FontSize, HashMap<char, Character>>,
}

impl GlyphCache {

    /// Constructor for a GlyphCache.
    pub fn new(font: &Path) -> Result<GlyphCache, Error> {
        let freetype = match freetype::Library::init() {
            Ok(freetype) => freetype,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        let font_str = match font.as_str() {
            Some(font_str) => font_str,
            None => return Err(Error::FreetypeError(MissingFontField)),
        };
        let face = match freetype.new_face(font_str, 0) {
            Ok(face) => face,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        Ok(GlyphCache {
            face: face,
            data: HashMap::new(),
        })
    }

    /// Return a reference to a `Character`. If there is not yet a `Character` for
    /// the given `FontSize` and `char`, load the `Character`.
    pub fn get_character(&mut self, size: FontSize, ch: char) -> &Character {
        match {
            match self.data.entry(size) {
                Vacant(entry) => entry.set(HashMap::new()),
                Occupied(entry) => entry.into_mut(),
            }
        }.contains_key(&ch) {
            true => &self.data[size][ch],
            false => { self.load_character(size, ch); &self.data[size][ch] }
        }
    }

    /// Load a `Character` from a given `FontSize` and `char`.
    fn load_character(&mut self, size: FontSize, ch: char) {
        self.face.set_pixel_sizes(0, size).unwrap();
        self.face.load_char(ch as ffi::FT_ULong, freetype::face::DEFAULT).unwrap();
        let glyph = self.face.glyph().get_glyph().unwrap();
        let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None)
            .unwrap();
        let bitmap = bitmap_glyph.bitmap();
        let texture = Texture::from_memory_alpha(bitmap.buffer(),
                                                 bitmap.width() as u32,
                                                 bitmap.rows() as u32).unwrap();
        let glyph_size = glyph.advance();
        self.data[size].insert(ch, Character {
            offset: [
                    bitmap_glyph.left() as f64,
                    bitmap_glyph.top() as f64
                ],
            size: [
                    (glyph_size.x >> 16) as f64,
                    (glyph_size.y >> 16) as f64
                ],
            texture: texture,
        });
    }

}
<commit_msg>Implemented `CharacterCache` for `GlyphCache`<commit_after>
//! Glyph caching

use error::Error;
use freetype::ffi;
use freetype;
use freetype::error::Error::MissingFontField;
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use graphics;

use Texture;

pub type FontSize = u32;

pub type Character = graphics::character::Character<Texture>;

/// A struct used for caching rendered font.
pub struct GlyphCache {
    /// The font face.
    pub face: freetype::Face,
    data: HashMap<FontSize, HashMap<char, Character>>,
}

impl GlyphCache {

    /// Constructor for a GlyphCache.
    pub fn new(font: &Path) -> Result<GlyphCache, Error> {
        let freetype = match freetype::Library::init() {
            Ok(freetype) => freetype,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        let font_str = match font.as_str() {
            Some(font_str) => font_str,
            None => return Err(Error::FreetypeError(MissingFontField)),
        };
        let face = match freetype.new_face(font_str, 0) {
            Ok(face) => face,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        Ok(GlyphCache {
            face: face,
            data: HashMap::new(),
        })
    }

    /// Load a `Character` from a given `FontSize` and `char`.
    fn load_character(&mut self, size: FontSize, ch: char) {
        self.face.set_pixel_sizes(0, size).unwrap();
        self.face.load_char(ch as ffi::FT_ULong, freetype::face::DEFAULT).unwrap();
        let glyph = self.face.glyph().get_glyph().unwrap();
        let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None)
            .unwrap();
        let bitmap = bitmap_glyph.bitmap();
        let texture = Texture::from_memory_alpha(bitmap.buffer(),
                                                 bitmap.width() as u32,
                                                 bitmap.rows() as u32).unwrap();
        let glyph_size = glyph.advance();
        self.data[size].insert(ch, Character {
            offset: [
                    bitmap_glyph.left() as f64,
                    bitmap_glyph.top() as f64
                ],
            size: [
                    (glyph_size.x >> 16) as f64,
                    (glyph_size.y >> 16) as f64
                ],
            texture: texture,
        });
    }

}

impl graphics::character::CharacterCache<Texture> for GlyphCache {
    fn character(&mut self, size: FontSize, ch: char) -> &Character {
        match {
            match self.data.entry(size) {
                Vacant(entry) => entry.set(HashMap::new()),
                Occupied(entry) => entry.into_mut(),
            }
        }.contains_key(&ch) {
            true => &self.data[size][ch],
            false => { self.load_character(size, ch); &self.data[size][ch] }
        }
    }
}

<|endoftext|>


<commit_before>use std::iter::{Iterator, Peekable};

pub struct OrderedIterator<I: Ord, P: Iterator<Item = I>> {
    first: Peekable<P>,
    second: Peekable<P>
}

impl<I, P> OrderedIterator<I, P>
    where I: Ord,
          P: Iterator<Item = I>
{
    pub fn new(first: P, second: P) -> OrderedIterator<I, P> {
        let first_peekable = first.peekable();
        let second_peekable = second.peekable();

        OrderedIterator {
            first: first_peekable,
            second: second_peekable
        }
    }
}

impl<I, P> Iterator for OrderedIterator<I, P>
    where I: Ord + Clone,
          P: Iterator<Item = I>
{
    type Item = I;

    fn next(&mut self) -> Option<Self::Item> {

        let first_is_none = self.first.peek().is_none();
        let second_is_none = self.second.peek().is_none();

        if first_is_none && second_is_none {
            return None;
        }

        if first_is_none {
            return self.second.next();
        } else if second_is_none {
            return self.first.next();
        }

        if self.first.peek().unwrap() < self.second.peek().unwrap() {
            return self.first.next();
        } else {
            return self.second.next();
        }

    }
}
<commit_msg>@dashed's binary heap version of OrderedIterator<commit_after>use std::iter::{Iterator, Peekable};
use std::collections::BinaryHeap;
use std::cmp::Ordering;
use std::cell::RefCell;
use std::iter::FromIterator;

struct OrdIterator<T: Ord, P: Iterator<Item = T>>(RefCell<Peekable<P>>);

impl<T: Ord, P: Iterator<Item = T>> PartialEq for OrdIterator<T, P> {
    fn eq(&self, other: &Self) -> bool {

        let mut this = self.0.borrow_mut();
        let mut other = other.0.borrow_mut();

        let this = this.peek();
        let other = other.peek();

        if this.is_none() && other.is_none() {
            return true;
        }

        if this.is_none() || other.is_none() {
            return false;
        }
        let this = this.unwrap();
        let other = other.unwrap();

        *this == *other
    }
}

impl<T: Ord, P: Iterator<Item = T>> Eq for OrdIterator<T, P> {}

impl<T: Ord, P: Iterator<Item = T>> PartialOrd for OrdIterator<T, P> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {

        let mut this = self.0.borrow_mut();
        let mut other = other.0.borrow_mut();

        let this = this.peek();
        let other = other.peek();

        if this.is_none() || other.is_none() {
            return None;
        }

        let this = this.unwrap();
        let other = other.unwrap();

        match this.partial_cmp(other) {
            None => None,
            Some(ord) => {
                let ord = match ord {
                    Ordering::Greater => Ordering::Less,
                    Ordering::Less => Ordering::Greater,
                    Ordering::Equal => ord,
                };
                Some(ord)
            }
        }
    }
}

// http://stackoverflow.com/questions/39949939/how-can-i-implement-a-min-heap-of-f64-with-rusts-binaryheap
impl<T: Ord, P: Iterator<Item = T>> Ord for OrdIterator<T, P> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

struct SortedIterators<T: Ord, P: Iterator<Item = T>> {
    heap: BinaryHeap<OrdIterator<T, P>>,
}

impl<T: Ord, P: Iterator<Item = T>> FromIterator<P> for SortedIterators<T, P> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item = P>
    {

        let iter = iter.into_iter().map(|x| OrdIterator(RefCell::new(x.peekable())));
        SortedIterators { heap: BinaryHeap::from_iter(iter) }
    }
}

impl<T, P> Iterator for SortedIterators<T, P>
    where T: Ord + Clone,
          P: Iterator<Item = T>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {

        match self.heap.pop() {
            None => None,
            Some(iter) => {

                let next = {
                    iter.0.borrow_mut().next()
                };

                let has_next = iter.0.borrow_mut().peek().is_some();
                if has_next {
                    self.heap.push(iter);
                }

                next
            }
        }

    }
}
<|endoftext|>


<commit_before>use rustc_ast::token::{Delimiter, TokenKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ast, ptr};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS};
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{self, kw};
use rustc_span::Symbol;

use crate::macros::MacroArg;
use crate::rewrite::RewriteContext;

pub(crate) mod asm;
pub(crate) mod cfg_if;
pub(crate) mod lazy_static;

fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> {
    stream_to_parser(sess, tokens, MACRO_ARGUMENTS)
}

fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> {
    build_stream_parser(context.parse_sess.inner(), tokens)
}

fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
    macro_rules! parse_macro_arg {
        ($macro_arg:ident, $parser:expr, $f:expr) => {
            let mut cloned_parser = (*parser).clone();
            match $parser(&mut cloned_parser) {
                Ok(x) => {
                    if parser.sess.span_diagnostic.has_errors().is_some() {
                        parser.sess.span_diagnostic.reset_err_count();
                    } else {
                        // Parsing succeeded.
                        *parser = cloned_parser;
                        return Some(MacroArg::$macro_arg($f(x)?));
                    }
                }
                Err(e) => {
                    e.cancel();
                    parser.sess.span_diagnostic.reset_err_count();
                }
            }
        };
    }

    parse_macro_arg!(
        Expr,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(),
        |x: ptr::P<ast::Expr>| Some(x)
    );
    parse_macro_arg!(
        Ty,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(),
        |x: ptr::P<ast::Ty>| Some(x)
    );
    parse_macro_arg!(
        Pat,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None),
        |x: ptr::P<ast::Pat>| Some(x)
    );
    // `parse_item` returns `Option<ptr::P<ast::Item>>`.
    parse_macro_arg!(
        Item,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No),
        |x: Option<ptr::P<ast::Item>>| x
    );

    None
}

pub(crate) struct ParsedMacroArgs {
    pub(crate) vec_with_semi: bool,
    pub(crate) trailing_comma: bool,
    pub(crate) args: Vec<MacroArg>,
}

fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
    for &keyword in RUST_KW.iter() {
        if parser.token.is_keyword(keyword)
            && parser.look_ahead(1, |t| {
                t.kind == TokenKind::Eof
                    || t.kind == TokenKind::Comma
                    || t.kind == TokenKind::CloseDelim(Delimiter::Invisible)
            })
        {
            parser.bump();
            return Some(MacroArg::Keyword(
                symbol::Ident::with_dummy_span(keyword),
                parser.prev_token.span,
            ));
        }
    }
    None
}

pub(crate) fn parse_macro_args(
    context: &RewriteContext<'_>,
    tokens: TokenStream,
    style: Delimiter,
    forced_bracket: bool,
) -> Option<ParsedMacroArgs> {
    let mut parser = build_parser(context, tokens);
    let mut args = Vec::new();
    let mut vec_with_semi = false;
    let mut trailing_comma = false;

    if Delimiter::Brace != style {
        loop {
            if let Some(arg) = check_keyword(&mut parser) {
                args.push(arg);
            } else if let Some(arg) = parse_macro_arg(&mut parser) {
                args.push(arg);
            } else {
                return None;
            }

            match parser.token.kind {
                TokenKind::Eof => break,
                TokenKind::Comma => (),
                TokenKind::Semi => {
                    // Try to parse `vec![expr; expr]`
                    if forced_bracket {
                        parser.bump();
                        if parser.token.kind != TokenKind::Eof {
                            match parse_macro_arg(&mut parser) {
                                Some(arg) => {
                                    args.push(arg);
                                    parser.bump();
                                    if parser.token.kind == TokenKind::Eof && args.len() == 2 {
                                        vec_with_semi = true;
                                        break;
                                    }
                                }
                                None => {
                                    return None;
                                }
                            }
                        }
                    }
                    return None;
                }
                _ if args.last().map_or(false, MacroArg::is_item) => continue,
                _ => return None,
            }

            parser.bump();

            if parser.token.kind == TokenKind::Eof {
                trailing_comma = true;
                break;
            }
        }
    }

    Some(ParsedMacroArgs {
        vec_with_semi,
        trailing_comma,
        args,
    })
}

pub(crate) fn parse_expr(
    context: &RewriteContext<'_>,
    tokens: TokenStream,
) -> Option<ptr::P<ast::Expr>> {
    let mut parser = build_parser(context, tokens);
    parser.parse_expr().ok()
}

const RUST_KW: [Symbol; 59] = [
    kw::PathRoot,
    kw::DollarCrate,
    kw::Underscore,
    kw::As,
    kw::Box,
    kw::Break,
    kw::Const,
    kw::Continue,
    kw::Crate,
    kw::Else,
    kw::Enum,
    kw::Extern,
    kw::False,
    kw::Fn,
    kw::For,
    kw::If,
    kw::Impl,
    kw::In,
    kw::Let,
    kw::Loop,
    kw::Match,
    kw::Mod,
    kw::Move,
    kw::Mut,
    kw::Pub,
    kw::Ref,
    kw::Return,
    kw::SelfLower,
    kw::SelfUpper,
    kw::Static,
    kw::Struct,
    kw::Super,
    kw::Trait,
    kw::True,
    kw::Type,
    kw::Unsafe,
    kw::Use,
    kw::Where,
    kw::While,
    kw::Abstract,
    kw::Become,
    kw::Do,
    kw::Final,
    kw::Macro,
    kw::Override,
    kw::Priv,
    kw::Typeof,
    kw::Unsized,
    kw::Virtual,
    kw::Yield,
    kw::Dyn,
    kw::Async,
    kw::Try,
    kw::UnderscoreLifetime,
    kw::StaticLifetime,
    kw::Auto,
    kw::Catch,
    kw::Default,
    kw::Union,
];
<commit_msg>Rollup merge of #96543 - nnethercote:rm-make_token_stream-hacks, r=Aaron1011<commit_after>use rustc_ast::token::{Delimiter, TokenKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ast, ptr};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS};
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{self, kw};
use rustc_span::Symbol;

use crate::macros::MacroArg;
use crate::rewrite::RewriteContext;

pub(crate) mod asm;
pub(crate) mod cfg_if;
pub(crate) mod lazy_static;

fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> {
    stream_to_parser(sess, tokens, MACRO_ARGUMENTS)
}

fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> {
    build_stream_parser(context.parse_sess.inner(), tokens)
}

fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
    macro_rules! parse_macro_arg {
        ($macro_arg:ident, $parser:expr, $f:expr) => {
            let mut cloned_parser = (*parser).clone();
            match $parser(&mut cloned_parser) {
                Ok(x) => {
                    if parser.sess.span_diagnostic.has_errors().is_some() {
                        parser.sess.span_diagnostic.reset_err_count();
                    } else {
                        // Parsing succeeded.
                        *parser = cloned_parser;
                        return Some(MacroArg::$macro_arg($f(x)?));
                    }
                }
                Err(e) => {
                    e.cancel();
                    parser.sess.span_diagnostic.reset_err_count();
                }
            }
        };
    }

    parse_macro_arg!(
        Expr,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(),
        |x: ptr::P<ast::Expr>| Some(x)
    );
    parse_macro_arg!(
        Ty,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(),
        |x: ptr::P<ast::Ty>| Some(x)
    );
    parse_macro_arg!(
        Pat,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None),
        |x: ptr::P<ast::Pat>| Some(x)
    );
    // `parse_item` returns `Option<ptr::P<ast::Item>>`.
    parse_macro_arg!(
        Item,
        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No),
        |x: Option<ptr::P<ast::Item>>| x
    );

    None
}

pub(crate) struct ParsedMacroArgs {
    pub(crate) vec_with_semi: bool,
    pub(crate) trailing_comma: bool,
    pub(crate) args: Vec<MacroArg>,
}

fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
    for &keyword in RUST_KW.iter() {
        if parser.token.is_keyword(keyword)
            && parser.look_ahead(1, |t| {
                t.kind == TokenKind::Eof || t.kind == TokenKind::Comma
            })
        {
            parser.bump();
            return Some(MacroArg::Keyword(
                symbol::Ident::with_dummy_span(keyword),
                parser.prev_token.span,
            ));
        }
    }
    None
}

pub(crate) fn parse_macro_args(
    context: &RewriteContext<'_>,
    tokens: TokenStream,
    style: Delimiter,
    forced_bracket: bool,
) -> Option<ParsedMacroArgs> {
    let mut parser = build_parser(context, tokens);
    let mut args = Vec::new();
    let mut vec_with_semi = false;
    let mut trailing_comma = false;

    if Delimiter::Brace != style {
        loop {
            if let Some(arg) = check_keyword(&mut parser) {
                args.push(arg);
            } else if let Some(arg) = parse_macro_arg(&mut parser) {
                args.push(arg);
            } else {
                return None;
            }

            match parser.token.kind {
                TokenKind::Eof => break,
                TokenKind::Comma => (),
                TokenKind::Semi => {
                    // Try to parse `vec![expr; expr]`
                    if forced_bracket {
                        parser.bump();
                        if parser.token.kind != TokenKind::Eof {
                            match parse_macro_arg(&mut parser) {
                                Some(arg) => {
                                    args.push(arg);
                                    parser.bump();
                                    if parser.token.kind == TokenKind::Eof && args.len() == 2 {
                                        vec_with_semi = true;
                                        break;
                                    }
                                }
                                None => {
                                    return None;
                                }
                            }
                        }
                    }
                    return None;
                }
                _ if args.last().map_or(false, MacroArg::is_item) => continue,
                _ => return None,
            }

            parser.bump();

            if parser.token.kind == TokenKind::Eof {
                trailing_comma = true;
                break;
            }
        }
    }

    Some(ParsedMacroArgs {
        vec_with_semi,
        trailing_comma,
        args,
    })
}

pub(crate) fn parse_expr(
    context: &RewriteContext<'_>,
    tokens: TokenStream,
) -> Option<ptr::P<ast::Expr>> {
    let mut parser = build_parser(context, tokens);
    parser.parse_expr().ok()
}

const RUST_KW: [Symbol; 59] = [
    kw::PathRoot,
    kw::DollarCrate,
    kw::Underscore,
    kw::As,
    kw::Box,
    kw::Break,
    kw::Const,
    kw::Continue,
    kw::Crate,
    kw::Else,
    kw::Enum,
    kw::Extern,
    kw::False,
    kw::Fn,
    kw::For,
    kw::If,
    kw::Impl,
    kw::In,
    kw::Let,
    kw::Loop,
    kw::Match,
    kw::Mod,
    kw::Move,
    kw::Mut,
    kw::Pub,
    kw::Ref,
    kw::Return,
    kw::SelfLower,
    kw::SelfUpper,
    kw::Static,
    kw::Struct,
    kw::Super,
    kw::Trait,
    kw::True,
    kw::Type,
    kw::Unsafe,
    kw::Use,
    kw::Where,
    kw::While,
    kw::Abstract,
    kw::Become,
    kw::Do,
    kw::Final,
    kw::Macro,
    kw::Override,
    kw::Priv,
    kw::Typeof,
    kw::Unsized,
    kw::Virtual,
    kw::Yield,
    kw::Dyn,
    kw::Async,
    kw::Try,
    kw::UnderscoreLifetime,
    kw::StaticLifetime,
    kw::Auto,
    kw::Catch,
    kw::Default,
    kw::Union,
];
<|endoftext|>


<commit_before>use rustc::middle::{const_eval, def_id, ty};
use rustc_mir::mir_map::MirMap;
use rustc_mir::repr::{self as mir, Mir};
use syntax::ast::Attribute;
use syntax::attr::AttrMetaMethods;

use std::iter;

const TRACE_EXECUTION: bool = false;

#[derive(Clone, Debug, PartialEq)]
enum Value {
    Uninit,
    Bool(bool),
    Int(i64), // FIXME: Should be bit-width aware.
    Func(def_id::DefId),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Pointer {
    Stack(usize),
    // TODO(tsion): Heap
}

/// A stack frame:
///
/// ```text
/// +-----------------------+
/// | ReturnPointer         | return value
/// + - - - - - - - - - - - +
/// | Arg(0)                |
/// | Arg(1)                | arguments
/// | ...                   |
/// | Arg(num_args - 1)     |
/// + - - - - - - - - - - - +
/// | Var(0)                |
/// | Var(1)                | variables
/// | ...                   |
/// | Var(num_vars - 1)     |
/// + - - - - - - - - - - - +
/// | Temp(0)               |
/// | Temp(1)               | temporaries
/// | ...                   |
/// | Temp(num_temps - 1)   |
/// + - - - - - - - - - - - +
/// | Aggregates            | aggregates
/// +-----------------------+
/// ```
#[derive(Debug)]
struct Frame {
    offset: usize,
    num_args: usize,
    num_vars: usize,
    num_temps: usize,
    // aggregates
}

impl Frame {
    fn size(&self) -> usize {
        1 + self.num_args + self.num_vars + self.num_temps
    }

    fn return_val_offset(&self) -> usize {
        self.offset
    }

    fn arg_offset(&self, i: u32) -> usize {
        self.offset + 1 + i as usize
    }

    fn var_offset(&self, i: u32) -> usize {
        self.offset + 1 + self.num_args + i as usize
    }

    fn temp_offset(&self, i: u32) -> usize {
        self.offset + 1 + self.num_args + self.num_vars + i as usize
    }
}

struct Interpreter<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    mir_map: &'a MirMap<'tcx>,
    value_stack: Vec<Value>,
    call_stack: Vec<Frame>,
}

impl<'a, 'tcx> Interpreter<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
        Interpreter {
            tcx: tcx,
            mir_map: mir_map,
            value_stack: Vec::new(),
            call_stack: Vec::new(),
        }
    }

    fn push_stack_frame(&mut self, mir: &Mir, args: &[Value]) {
        self.call_stack.push(Frame {
            offset: self.value_stack.len(),
            num_args: mir.arg_decls.len(),
            num_vars: mir.var_decls.len(),
            num_temps: mir.temp_decls.len(),
        });

        let frame = self.call_stack.last().unwrap();
        self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));

        for (i, arg) in args.iter().enumerate() {
            self.value_stack[frame.offset + 1 + i] = arg.clone();
        }
    }

    fn pop_stack_frame(&mut self) {
        let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
        self.value_stack.truncate(frame.offset);
    }

    fn call(&mut self, mir: &Mir, args: &[Value]) -> Value {
        self.push_stack_frame(mir, args);
        let mut block = mir::START_BLOCK;

        loop {
            let block_data = mir.basic_block_data(block);

            for stmt in &block_data.statements {
                if TRACE_EXECUTION { println!("{:?}", stmt); }

                match stmt.kind {
                    mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
                        let ptr = self.eval_lvalue(lvalue);
                        let value = self.eval_rvalue(rvalue);
                        self.write_pointer(ptr, value);
                    }

                    mir::StatementKind::Drop(_kind, ref _lv) => {
                        // TODO
                    },
                }
            }

            if TRACE_EXECUTION { println!("{:?}", block_data.terminator); }

            match block_data.terminator {
                mir::Terminator::Return => break,
                mir::Terminator::Goto { target } => block = target,

                mir::Terminator::Call { ref data, targets } => {
                    let mir::CallData { ref destination, ref func, ref args } = *data;

                    let ptr = self.eval_lvalue(destination);
                    let func_val = self.eval_operand(func);

                    if let Value::Func(def_id) = func_val {
                        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
                        let mir = &self.mir_map[&node_id];
                        let arg_vals: Vec<Value> =
                            args.iter().map(|arg| self.eval_operand(arg)).collect();

                        // FIXME: Pass the destination lvalue such that the ReturnPointer inside
                        // the function call will point to the destination.
                        let return_val = self.call(mir, &arg_vals);
                        self.write_pointer(ptr, return_val);
                        block = targets[0];
                    } else {
                        panic!("tried to call a non-function value: {:?}", func_val);
                    }
                }

                mir::Terminator::If { ref cond, targets } => {
                    match self.eval_operand(cond) {
                        Value::Bool(true) => block = targets[0],
                        Value::Bool(false) => block = targets[1],
                        cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
                    }
                }

                mir::Terminator::SwitchInt { ref discr, ref values, ref targets, .. } => {
                    let discr_val = self.read_lvalue(discr);

                    let index = values.iter().position(|v| discr_val == self.eval_constant(v))
                        .expect("discriminant matched no values");

                    block = targets[index];
                }

                // mir::Terminator::Diverge => unimplemented!(),
                // mir::Terminator::Panic { target } => unimplemented!(),
                // mir::Terminator::Switch { ref discr, adt_def, ref targets } => unimplemented!(),
                _ => unimplemented!(),
            }
        }

        let ret_val = self.read_lvalue(&mir::Lvalue::ReturnPointer);
        self.pop_stack_frame();
        ret_val
    }

    fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> Pointer {
        let frame = self.call_stack.last().expect("missing call frame");

        match *lvalue {
            mir::Lvalue::ReturnPointer => Pointer::Stack(frame.return_val_offset()),
            mir::Lvalue::Arg(i)  => Pointer::Stack(frame.arg_offset(i)),
            mir::Lvalue::Var(i)  => Pointer::Stack(frame.var_offset(i)),
            mir::Lvalue::Temp(i) => Pointer::Stack(frame.temp_offset(i)),
            _ => unimplemented!(),
        }
    }

    fn eval_binary_op(&mut self, bin_op: mir::BinOp, left: Value, right: Value) -> Value {
        match (left, right) {
            (Value::Int(l), Value::Int(r)) => {
                match bin_op {
                    mir::BinOp::Add    => Value::Int(l + r),
                    mir::BinOp::Sub    => Value::Int(l - r),
                    mir::BinOp::Mul    => Value::Int(l * r),
                    mir::BinOp::Div    => Value::Int(l / r),
                    mir::BinOp::Rem    => Value::Int(l % r),
                    mir::BinOp::BitXor => Value::Int(l ^ r),
                    mir::BinOp::BitAnd => Value::Int(l & r),
                    mir::BinOp::BitOr  => Value::Int(l | r),
                    mir::BinOp::Shl    => Value::Int(l << r),
                    mir::BinOp::Shr    => Value::Int(l >> r),
                    mir::BinOp::Eq     => Value::Bool(l == r),
                    mir::BinOp::Lt     => Value::Bool(l < r),
                    mir::BinOp::Le     => Value::Bool(l <= r),
                    mir::BinOp::Ne     => Value::Bool(l != r),
                    mir::BinOp::Ge     => Value::Bool(l >= r),
                    mir::BinOp::Gt     => Value::Bool(l > r),
                }
            }

            _ => unimplemented!(),
        }
    }

    fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value {
        match *rvalue {
            mir::Rvalue::Use(ref operand) => self.eval_operand(operand),

            mir::Rvalue::BinaryOp(bin_op, ref left, ref right) => {
                let left_val = self.eval_operand(left);
                let right_val = self.eval_operand(right);
                self.eval_binary_op(bin_op, left_val, right_val)
            }

            mir::Rvalue::UnaryOp(un_op, ref operand) => {
                match (un_op, self.eval_operand(operand)) {
                    (mir::UnOp::Not, Value::Int(n)) => Value::Int(!n),
                    (mir::UnOp::Neg, Value::Int(n)) => Value::Int(-n),
                    _ => unimplemented!(),
                }
            }

            // mir::Rvalue::Aggregate(mir::AggregateKind::Adt(ref adt_def, variant, substs),
            //                        ref operands) => {
            //     let num_fields = adt_def.variants[variant].fields.len();
            //     debug_assert_eq!(num_fields, operands.len());

            //     let data = operands.iter().map(|op| self.eval_operand(op)).collect();
            //     Value::Adt(variant, data)
            // }

            _ => unimplemented!(),
        }
    }

    fn eval_operand(&mut self, op: &mir::Operand) -> Value {
        match *op {
            mir::Operand::Consume(ref lvalue) => self.read_lvalue(lvalue),

            mir::Operand::Constant(ref constant) => {
                match constant.literal {
                    mir::Literal::Value { ref value } => self.eval_constant(value),

                    mir::Literal::Item { def_id, substs: _ } => {
                        Value::Func(def_id)
                    }
                }
            }
        }
    }

    fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
        match *const_val {
            const_eval::ConstVal::Float(_f)         => unimplemented!(),
            const_eval::ConstVal::Int(i)            => Value::Int(i),
            const_eval::ConstVal::Uint(_u)          => unimplemented!(),
            const_eval::ConstVal::Str(ref _s)       => unimplemented!(),
            const_eval::ConstVal::ByteStr(ref _bs)  => unimplemented!(),
            const_eval::ConstVal::Bool(b)           => Value::Bool(b),
            const_eval::ConstVal::Struct(_node_id)  => unimplemented!(),
            const_eval::ConstVal::Tuple(_node_id)   => unimplemented!(),
            const_eval::ConstVal::Function(_def_id) => unimplemented!(),
        }
    }

    fn read_lvalue(&self, lvalue: &mir::Lvalue) -> Value {
        self.read_pointer(self.eval_lvalue(lvalue))
    }

    fn read_pointer(&self, p: Pointer) -> Value {
        match p {
            Pointer::Stack(offset) => self.value_stack[offset].clone(),
        }
    }

    fn write_pointer(&mut self, p: Pointer, val: Value) {
        match p {
            Pointer::Stack(offset) => self.value_stack[offset] = val,
        }
    }
}

pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) {
    for (&id, mir) in mir_map {
        for attr in tcx.map.attrs(id) {
            if attr.check_name("miri_run") {
                let item = tcx.map.expect_item(id);

                println!("Interpreting: {}", item.name);
                let mut interpreter = Interpreter::new(tcx, mir_map);
                let val = interpreter.call(mir, &[]);
                let val_str = format!("{:?}", val);

                if !check_expected(&val_str, attr) {
                    println!("=> {}\n", val_str);
                }
            }
        }
    }
}

fn check_expected(actual: &str, attr: &Attribute) -> bool {
    if let Some(meta_items) = attr.meta_item_list() {
        for meta_item in meta_items {
            if meta_item.check_name("expected") {
                let expected = meta_item.value_str().unwrap();

                if actual == &expected[..] {
                    println!("Test passed!\n");
                } else {
                    println!("Actual value:\t{}\nExpected value:\t{}\n", actual, expected);
                }

                return true;
            }
        }
    }

    false
}
<commit_msg>Write fn call return values directly into an lvalue the caller provides.<commit_after>use rustc::middle::{const_eval, def_id, ty};
use rustc_mir::mir_map::MirMap;
use rustc_mir::repr::{self as mir, Mir};
use syntax::ast::Attribute;
use syntax::attr::AttrMetaMethods;

use std::iter;

const TRACE_EXECUTION: bool = false;

#[derive(Clone, Debug, PartialEq)]
enum Value {
    Uninit,
    Bool(bool),
    Int(i64), // FIXME: Should be bit-width aware.
    Func(def_id::DefId),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Pointer {
    Stack(usize),
    // TODO(tsion): Heap
}

/// A stack frame:
///
/// ```text
/// +-----------------------+
/// | Arg(0)                |
/// | Arg(1)                | arguments
/// | ...                   |
/// | Arg(num_args - 1)     |
/// + - - - - - - - - - - - +
/// | Var(0)                |
/// | Var(1)                | variables
/// | ...                   |
/// | Var(num_vars - 1)     |
/// + - - - - - - - - - - - +
/// | Temp(0)               |
/// | Temp(1)               | temporaries
/// | ...                   |
/// | Temp(num_temps - 1)   |
/// + - - - - - - - - - - - +
/// | Aggregates            | aggregates
/// +-----------------------+
/// ```
#[derive(Debug)]
struct Frame {
    return_ptr: Pointer,
    offset: usize,
    num_args: usize,
    num_vars: usize,
    num_temps: usize,
    // aggregates
}

impl Frame {
    fn size(&self) -> usize {
        self.num_args + self.num_vars + self.num_temps
    }

    fn arg_offset(&self, i: usize) -> usize {
        self.offset + i
    }

    fn var_offset(&self, i: usize) -> usize {
        self.offset + self.num_args + i
    }

    fn temp_offset(&self, i: usize) -> usize {
        self.offset + self.num_args + self.num_vars + i
    }
}

struct Interpreter<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    mir_map: &'a MirMap<'tcx>,
    value_stack: Vec<Value>,
    call_stack: Vec<Frame>,
}

impl<'a, 'tcx> Interpreter<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
        Interpreter {
            tcx: tcx,
            mir_map: mir_map,
            value_stack: vec![Value::Uninit], // Allocate a spot for the top-level return value.
            call_stack: Vec::new(),
        }
    }

    fn push_stack_frame(&mut self, mir: &Mir, args: &[Value], return_ptr: Pointer) {
        self.call_stack.push(Frame {
            return_ptr: return_ptr,
            offset: self.value_stack.len(),
            num_args: mir.arg_decls.len(),
            num_vars: mir.var_decls.len(),
            num_temps: mir.temp_decls.len(),
        });

        let frame = self.call_stack.last().unwrap();
        self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));

        for (i, arg) in args.iter().enumerate() {
            self.value_stack[frame.arg_offset(i)] = arg.clone();
        }
    }

    fn pop_stack_frame(&mut self) {
        let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
        self.value_stack.truncate(frame.offset);
    }

    fn call(&mut self, mir: &Mir, args: &[Value], return_ptr: Pointer) {
        self.push_stack_frame(mir, args, return_ptr);
        let mut block = mir::START_BLOCK;

        loop {
            let block_data = mir.basic_block_data(block);

            for stmt in &block_data.statements {
                if TRACE_EXECUTION { println!("{:?}", stmt); }

                match stmt.kind {
                    mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
                        let ptr = self.eval_lvalue(lvalue);
                        let value = self.eval_rvalue(rvalue);
                        self.write_pointer(ptr, value);
                    }

                    mir::StatementKind::Drop(_kind, ref _lv) => {
                        // TODO
                    },
                }
            }

            if TRACE_EXECUTION { println!("{:?}", block_data.terminator); }

            match block_data.terminator {
                mir::Terminator::Return => break,
                mir::Terminator::Goto { target } => block = target,

                mir::Terminator::Call { ref data, targets } => {
                    let mir::CallData { ref destination, ref func, ref args } = *data;

                    let ptr = self.eval_lvalue(destination);
                    let func_val = self.eval_operand(func);

                    if let Value::Func(def_id) = func_val {
                        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
                        let mir = &self.mir_map[&node_id];
                        let arg_vals: Vec<Value> =
                            args.iter().map(|arg| self.eval_operand(arg)).collect();

                        self.call(mir, &arg_vals, ptr);
                        block = targets[0];
                    } else {
                        panic!("tried to call a non-function value: {:?}", func_val);
                    }
                }

                mir::Terminator::If { ref cond, targets } => {
                    match self.eval_operand(cond) {
                        Value::Bool(true) => block = targets[0],
                        Value::Bool(false) => block = targets[1],
                        cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
                    }
                }

                mir::Terminator::SwitchInt { ref discr, ref values, ref targets, .. } => {
                    let discr_val = self.read_lvalue(discr);

                    let index = values.iter().position(|v| discr_val == self.eval_constant(v))
                        .expect("discriminant matched no values");

                    block = targets[index];
                }

                // mir::Terminator::Diverge => unimplemented!(),
                // mir::Terminator::Panic { target } => unimplemented!(),
                // mir::Terminator::Switch { ref discr, adt_def, ref targets } => unimplemented!(),
                _ => unimplemented!(),
            }
        }

        self.pop_stack_frame();
    }

    fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> Pointer {
        let frame = self.call_stack.last().expect("missing call frame");

        match *lvalue {
            mir::Lvalue::ReturnPointer => frame.return_ptr,
            mir::Lvalue::Arg(i)  => Pointer::Stack(frame.arg_offset(i as usize)),
            mir::Lvalue::Var(i)  => Pointer::Stack(frame.var_offset(i as usize)),
            mir::Lvalue::Temp(i) => Pointer::Stack(frame.temp_offset(i as usize)),
            _ => unimplemented!(),
        }
    }

    fn eval_binary_op(&mut self, bin_op: mir::BinOp, left: Value, right: Value) -> Value {
        match (left, right) {
            (Value::Int(l), Value::Int(r)) => {
                match bin_op {
                    mir::BinOp::Add    => Value::Int(l + r),
                    mir::BinOp::Sub    => Value::Int(l - r),
                    mir::BinOp::Mul    => Value::Int(l * r),
                    mir::BinOp::Div    => Value::Int(l / r),
                    mir::BinOp::Rem    => Value::Int(l % r),
                    mir::BinOp::BitXor => Value::Int(l ^ r),
                    mir::BinOp::BitAnd => Value::Int(l & r),
                    mir::BinOp::BitOr  => Value::Int(l | r),
                    mir::BinOp::Shl    => Value::Int(l << r),
                    mir::BinOp::Shr    => Value::Int(l >> r),
                    mir::BinOp::Eq     => Value::Bool(l == r),
                    mir::BinOp::Lt     => Value::Bool(l < r),
                    mir::BinOp::Le     => Value::Bool(l <= r),
                    mir::BinOp::Ne     => Value::Bool(l != r),
                    mir::BinOp::Ge     => Value::Bool(l >= r),
                    mir::BinOp::Gt     => Value::Bool(l > r),
                }
            }

            _ => unimplemented!(),
        }
    }

    fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value {
        match *rvalue {
            mir::Rvalue::Use(ref operand) => self.eval_operand(operand),

            mir::Rvalue::BinaryOp(bin_op, ref left, ref right) => {
                let left_val = self.eval_operand(left);
                let right_val = self.eval_operand(right);
                self.eval_binary_op(bin_op, left_val, right_val)
            }

            mir::Rvalue::UnaryOp(un_op, ref operand) => {
                match (un_op, self.eval_operand(operand)) {
                    (mir::UnOp::Not, Value::Int(n)) => Value::Int(!n),
                    (mir::UnOp::Neg, Value::Int(n)) => Value::Int(-n),
                    _ => unimplemented!(),
                }
            }

            // mir::Rvalue::Aggregate(mir::AggregateKind::Adt(ref adt_def, variant, substs),
            //                        ref operands) => {
            //     let num_fields = adt_def.variants[variant].fields.len();
            //     debug_assert_eq!(num_fields, operands.len());

            //     let data = operands.iter().map(|op| self.eval_operand(op)).collect();
            //     Value::Adt(variant, data)
            // }

            _ => unimplemented!(),
        }
    }

    fn eval_operand(&mut self, op: &mir::Operand) -> Value {
        match *op {
            mir::Operand::Consume(ref lvalue) => self.read_lvalue(lvalue),

            mir::Operand::Constant(ref constant) => {
                match constant.literal {
                    mir::Literal::Value { ref value } => self.eval_constant(value),

                    mir::Literal::Item { def_id, substs: _ } => {
                        Value::Func(def_id)
                    }
                }
            }
        }
    }

    fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
        match *const_val {
            const_eval::ConstVal::Float(_f)         => unimplemented!(),
            const_eval::ConstVal::Int(i)            => Value::Int(i),
            const_eval::ConstVal::Uint(_u)          => unimplemented!(),
            const_eval::ConstVal::Str(ref _s)       => unimplemented!(),
            const_eval::ConstVal::ByteStr(ref _bs)  => unimplemented!(),
            const_eval::ConstVal::Bool(b)           => Value::Bool(b),
            const_eval::ConstVal::Struct(_node_id)  => unimplemented!(),
            const_eval::ConstVal::Tuple(_node_id)   => unimplemented!(),
            const_eval::ConstVal::Function(_def_id) => unimplemented!(),
        }
    }

    fn read_lvalue(&self, lvalue: &mir::Lvalue) -> Value {
        self.read_pointer(self.eval_lvalue(lvalue))
    }

    fn read_pointer(&self, p: Pointer) -> Value {
        match p {
            Pointer::Stack(offset) => self.value_stack[offset].clone(),
        }
    }

    fn write_pointer(&mut self, p: Pointer, val: Value) {
        match p {
            Pointer::Stack(offset) => self.value_stack[offset] = val,
        }
    }
}

pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) {
    for (&id, mir) in mir_map {
        for attr in tcx.map.attrs(id) {
            if attr.check_name("miri_run") {
                let item = tcx.map.expect_item(id);

                println!("Interpreting: {}", item.name);

                let mut interpreter = Interpreter::new(tcx, mir_map);
                let return_ptr = Pointer::Stack(0);
                interpreter.call(mir, &[], return_ptr);

                let val_str = format!("{:?}", interpreter.read_pointer(return_ptr));
                if !check_expected(&val_str, attr) {
                    println!("=> {}\n", val_str);
                }
            }
        }
    }
}

fn check_expected(actual: &str, attr: &Attribute) -> bool {
    if let Some(meta_items) = attr.meta_item_list() {
        for meta_item in meta_items {
            if meta_item.check_name("expected") {
                let expected = meta_item.value_str().unwrap();

                if actual == &expected[..] {
                    println!("Test passed!\n");
                } else {
                    println!("Actual value:\t{}\nExpected value:\t{}\n", actual, expected);
                }

                return true;
            }
        }
    }

    false
}
<|endoftext|>