<commit_before>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

extern mod std;

use ll::base::*;

use core::cast;
use core::libc::{c_int,free};
use core::Option;

use core::num::*;

use xproto;

pub struct Connection {
    priv c : *connection
}

pub impl<'self> Connection {
    #[inline]
    fn flush(&self) -> bool {
        unsafe {
            xcb_flush(self.c) > 0
        }
    }

    #[inline]
    fn get_maximum_request_length(&self) -> u32 {
        unsafe {
            xcb_get_maximum_request_length(self.c)
        }
    }

    #[inline]
    fn wait_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_wait_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    fn poll_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    fn poll_for_queued_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_queued_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    fn get_setup(&self) -> &'self xproto::Setup {
        unsafe {
            let setup = xcb_get_setup(self.c);
            if ptr::is_null(setup) {
                fail!(~"NULL setup on connection")
            } else {
                cast::transmute(setup)
            }
        }
    }

    #[inline]
    fn has_error(&self) -> bool {
        unsafe {
            xcb_connection_has_error(self.c) > 0
        }
    }

    #[inline]
    fn generate_id<T>(&self) -> T {
        unsafe {
            cast::transmute(xcb_generate_id(self.c))
        }
    }

    #[inline]
    unsafe fn get_raw_conn(&self) -> *connection {
        self.c
    }

    fn send_event<T>(&self,
                  propogate: bool,
                  destination: xproto::Window,
                  event_mask : u32,
                  event : Event<T>) {
        use ll;
        unsafe {
        ll::xproto::xcb_send_event(self.c,
            propogate as u8, destination as ll::xproto::window,
            event_mask, event.event as *libc::c_char);
        }
    }

    #[inline]
    fn connect() -> (Connection, int) {
        let screen : c_int = 0;
        unsafe {
            let conn = xcb_connect(ptr::null(), &screen);
            if ptr::is_null(conn) {
                fail!(~"Couldn't connect")
            } else {
                xcb_prefetch_maximum_request_length(conn);
                (Connection {c:conn}, screen as int)
            }
        }
    }

    #[inline]
    fn connect_to_display(display:&str) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect(s as *u8, &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

    #[inline]
    fn connect_with_auth(display:&str, auth_info: &AuthInfo) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect_to_display_with_auth_info(s as *u8,
                    cast::transmute(auth_info), &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

}

impl Drop for Connection {
    fn finalize(&self) {
        unsafe {
            xcb_disconnect(self.c);
        }
    }
}

pub struct Event<T> {
    event:*T
}

#[unsafe_destructor]
impl<T> Drop for Event<T> {
    fn finalize(&self) {
        use core::libc::c_void;
        unsafe {
            free(self.event as *c_void);
        }
    }
}

pub struct Error<T> {
    error:*T
}

pub fn mk_error<T>(err:*T) -> Error<T> {
    Error {error:err}
}

#[unsafe_destructor]
impl<T> Drop for Error<T> {
    fn finalize(&self) {
        use core::libc::c_void;
        unsafe {
            free(self.error as *c_void);
        }
    }
}

pub type AuthInfo = auth_info;
//TODO: Implement wrapper functions for constructing auth_info

pub struct Struct<T> {
    strct: T
}

pub struct Cookie<'self, T> {
    cookie: T,
    conn: &'self Connection,
    checked: bool
}

pub trait ReplyCookie<R> {
    fn get_reply(&self) -> Result<Reply<R>, GenericError>;
}

pub impl<'self, T> Cookie<'self, T> {
    fn request_check(&self) -> Option<GenericError> {
        unsafe {
            // Crazy pointer dance to get the right bit
            // of the struct
            let c : *void_cookie = cast::transmute(&self.cookie);
            let err = xcb_request_check(self.conn.c, *c);
            if ptr::is_null(err) {
                None
            } else {
                Some(Error {error:err})
            }
        }
    }
}

pub struct Reply<T> {
    reply:*T
}

pub fn mk_reply<T>(reply:*T) -> Reply<T> {
    Reply {reply:reply}
}

#[unsafe_destructor]
impl<T> Drop for Reply<T> {
    fn finalize(&self) {
        use core::libc::c_void;
        unsafe {
            free(self.reply as *c_void);
        }
    }
}

pub type GenericReply = Reply<generic_reply>;
pub type GenericEvent = Event<generic_event>;
pub type GenericError = Error<generic_error>;
pub type VoidCookie<'self> = Cookie<'self, void_cookie>;

/**
 * Casts the generic event to the right event. Assumes that the given
 * event is really the correct type.
 */
#[inline(always)]
pub fn cast_event<'r, T>(event : &'r GenericEvent) -> &'r T {
    // This isn't very safe... but other options incur yet more overhead
    // that I really don't want to.
    unsafe { cast::transmute(event) }
}

//Accessor methods for all Events
pub trait EventUtil {
    #[inline(always)]
    fn response_type(&self) -> u8;
}

impl<T> EventUtil for Event<T> {
    fn response_type(&self) -> u8 {
        unsafe {
            let gev : *generic_event = cast::transmute(self.event);
            (*gev).response_type
        }
    }
}

pub fn pack_bitfield<T:Ord+Zero+NumCast+Copy,L:Copy>(bf : &[(T,L)]) -> (T, ~[L]) {
    let len = bf.len();

    let sorted = std::sort::merge_sort(bf, |a,b| {
        let &(a, _) = a;
        let &(b, _) = b;
        a < b});

    let mut mask = 0u;
    let mut list : ~[L] = vec::with_capacity(len);

    for sorted.each |el| {
        let &(f, v) = el;
        let fld = num::cast(f);
        if (mask & fld) > 0 {
            loop;
        } else {
            mask |= fld;
            list.push(v);
        }
    }

    (num::cast(mask), list)
}
<commit_msg>Add a constructor for making a Connection from a raw pointer<commit_after>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

extern mod std;

use ll::base::*;

use core::cast;
use core::libc::{c_int,free};
use core::Option;

use core::num::*;

use xproto;

pub struct Connection {
    priv c : *connection
}

pub impl<'self> Connection {
    #[inline]
    fn flush(&self) -> bool {
        unsafe {
            xcb_flush(self.c) > 0
        }
    }

    #[inline]
    fn get_maximum_request_length(&self) -> u32 {
        unsafe {
            xcb_get_maximum_request_length(self.c)
        }
    }

    #[inline]
    fn wait_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_wait_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    fn poll_for_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    fn poll_for_queued_event(&self) -> Option<GenericEvent> {
        unsafe {
            let event = xcb_poll_for_queued_event(self.c);
            if ptr::is_null(event) {
                None
            } else {
                Some(Event {event:event})
            }
        }
    }

    #[inline]
    fn get_setup(&self) -> &'self xproto::Setup {
        unsafe {
            let setup = xcb_get_setup(self.c);
            if ptr::is_null(setup) {
                fail!(~"NULL setup on connection")
            } else {
                cast::transmute(setup)
            }
        }
    }

    #[inline]
    fn has_error(&self) -> bool {
        unsafe {
            xcb_connection_has_error(self.c) > 0
        }
    }

    #[inline]
    fn generate_id<T>(&self) -> T {
        unsafe {
            cast::transmute(xcb_generate_id(self.c))
        }
    }

    #[inline]
    unsafe fn get_raw_conn(&self) -> *connection {
        self.c
    }

    fn send_event<T>(&self,
                  propogate: bool,
                  destination: xproto::Window,
                  event_mask : u32,
                  event : Event<T>) {
        use ll;
        unsafe {
        ll::xproto::xcb_send_event(self.c,
            propogate as u8, destination as ll::xproto::window,
            event_mask, event.event as *libc::c_char);
        }
    }

    #[inline]
    fn connect() -> (Connection, int) {
        let screen : c_int = 0;
        unsafe {
            let conn = xcb_connect(ptr::null(), &screen);
            if ptr::is_null(conn) {
                fail!(~"Couldn't connect")
            } else {
                xcb_prefetch_maximum_request_length(conn);
                (Connection {c:conn}, screen as int)
            }
        }
    }

    #[inline]
    fn connect_to_display(display:&str) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect(s as *u8, &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

    #[inline]
    fn connect_with_auth(display:&str, auth_info: &AuthInfo) -> Option<(Connection, int)> {
        let screen : c_int = 0;
        unsafe {
            let conn = do str::as_c_str(display) |s| {
                xcb_connect_to_display_with_auth_info(s as *u8,
                    cast::transmute(auth_info), &screen)
            };
            if ptr::is_null(conn) {
                None
            } else {
                xcb_prefetch_maximum_request_length(conn);
                Some((Connection {c:conn}, screen as int))
            }
        }
    }

    unsafe fn from_raw_conn(conn:*connection) -> Connection {
        if ptr::is_null(conn) {
            fail!("Cannot construct from null pointer");
        }

        Connection {c:conn}
    }

}

impl Drop for Connection {
    fn finalize(&self) {
        unsafe {
            xcb_disconnect(self.c);
        }
    }
}

pub struct Event<T> {
    event:*T
}

#[unsafe_destructor]
impl<T> Drop for Event<T> {
    fn finalize(&self) {
        use core::libc::c_void;
        unsafe {
            free(self.event as *c_void);
        }
    }
}

pub struct Error<T> {
    error:*T
}

pub fn mk_error<T>(err:*T) -> Error<T> {
    Error {error:err}
}

#[unsafe_destructor]
impl<T> Drop for Error<T> {
    fn finalize(&self) {
        use core::libc::c_void;
        unsafe {
            free(self.error as *c_void);
        }
    }
}

pub type AuthInfo = auth_info;
//TODO: Implement wrapper functions for constructing auth_info

pub struct Struct<T> {
    strct: T
}

pub struct Cookie<'self, T> {
    cookie: T,
    conn: &'self Connection,
    checked: bool
}

pub trait ReplyCookie<R> {
    fn get_reply(&self) -> Result<Reply<R>, GenericError>;
}

pub impl<'self, T> Cookie<'self, T> {
    fn request_check(&self) -> Option<GenericError> {
        unsafe {
            // Crazy pointer dance to get the right bit
            // of the struct
            let c : *void_cookie = cast::transmute(&self.cookie);
            let err = xcb_request_check(self.conn.c, *c);
            if ptr::is_null(err) {
                None
            } else {
                Some(Error {error:err})
            }
        }
    }
}

pub struct Reply<T> {
    reply:*T
}

pub fn mk_reply<T>(reply:*T) -> Reply<T> {
    Reply {reply:reply}
}

#[unsafe_destructor]
impl<T> Drop for Reply<T> {
    fn finalize(&self) {
        use core::libc::c_void;
        unsafe {
            free(self.reply as *c_void);
        }
    }
}

pub type GenericReply = Reply<generic_reply>;
pub type GenericEvent = Event<generic_event>;
pub type GenericError = Error<generic_error>;
pub type VoidCookie<'self> = Cookie<'self, void_cookie>;

/**
 * Casts the generic event to the right event. Assumes that the given
 * event is really the correct type.
 */
#[inline(always)]
pub fn cast_event<'r, T>(event : &'r GenericEvent) -> &'r T {
    // This isn't very safe... but other options incur yet more overhead
    // that I really don't want to.
    unsafe { cast::transmute(event) }
}

//Accessor methods for all Events
pub trait EventUtil {
    #[inline(always)]
    fn response_type(&self) -> u8;
}

impl<T> EventUtil for Event<T> {
    fn response_type(&self) -> u8 {
        unsafe {
            let gev : *generic_event = cast::transmute(self.event);
            (*gev).response_type
        }
    }
}

pub fn pack_bitfield<T:Ord+Zero+NumCast+Copy,L:Copy>(bf : &[(T,L)]) -> (T, ~[L]) {
    let len = bf.len();

    let sorted = std::sort::merge_sort(bf, |a,b| {
        let &(a, _) = a;
        let &(b, _) = b;
        a < b});

    let mut mask = 0u;
    let mut list : ~[L] = vec::with_capacity(len);

    for sorted.each |el| {
        let &(f, v) = el;
        let fld = num::cast(f);
        if (mask & fld) > 0 {
            loop;
        } else {
            mask |= fld;
            list.push(v);
        }
    }

    (num::cast(mask), list)
}
<|endoftext|>


<commit_before>use Cost;

/// Pass an instance of this type to a training algorithm to optimize for C=Error^2
///
/// Optimizing a `model::Constant` for `LeastSquares` should yield the mean value
pub struct LeastSquares;

impl Cost<f64> for LeastSquares {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: f64, gradient_error_by_coefficent: f64) -> f64 {
        let error = prediction - truth;
        2.0 * error * gradient_error_by_coefficent
    }
}

/// Pass an instance of this type to a training algorithm to optimize for C=|Error|
///
/// Optimizing a `model::Constant` for `LeastAbsoluteDeviation` should yield the median.
/// Gradient for error == 0 is set to 0
pub struct LeastAbsoluteDeviation;

impl Cost<f64> for LeastAbsoluteDeviation {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: f64, gradient_error_by_coefficent: f64) -> f64 {
        let error = prediction - truth;
        if error > 0.0 {
            gradient_error_by_coefficent
        } else if error < 0.0 {
            -gradient_error_by_coefficent
        } else {
            0.0
        }
    }
}

/// Maximizes the likelihood function `L` by defining `C=-ln(L)`
///
/// You can use this function if your truth is a probability
/// (i.e., a value betwenn 0 and 1). Maximizing the likelihood
/// function is equivalent to minimizing the least square error,
/// yet this cost function has shown itself to converge quicker
/// for some problems.
pub struct MaxLikelihood;

impl Cost<f64> for MaxLikelihood {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: f64, gradient_error_by_coefficent: f64) -> f64 {
        gradient_error_by_coefficent * ((1.0 - truth) / (1.0 - prediction) - truth / prediction)
    }
}

impl Cost<bool> for MaxLikelihood {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: bool, gradient_error_by_coefficent: f64) -> f64 {
        gradient_error_by_coefficent / if truth { -prediction } else { 1.0 - prediction }
    }
}
<commit_msg>example for MaxLikelihood<commit_after>use Cost;

/// Pass an instance of this type to a training algorithm to optimize for C=Error^2
///
/// Optimizing a `model::Constant` for `LeastSquares` should yield the mean value
pub struct LeastSquares;

impl Cost<f64> for LeastSquares {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: f64, gradient_error_by_coefficent: f64) -> f64 {
        let error = prediction - truth;
        2.0 * error * gradient_error_by_coefficent
    }
}

/// Pass an instance of this type to a training algorithm to optimize for C=|Error|
///
/// Optimizing a `model::Constant` for `LeastAbsoluteDeviation` should yield the median.
/// Gradient for error == 0 is set to 0
pub struct LeastAbsoluteDeviation;

impl Cost<f64> for LeastAbsoluteDeviation {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: f64, gradient_error_by_coefficent: f64) -> f64 {
        let error = prediction - truth;
        if error > 0.0 {
            gradient_error_by_coefficent
        } else if error < 0.0 {
            -gradient_error_by_coefficent
        } else {
            0.0
        }
    }
}

/// Maximizes the likelihood function `L` by defining `C=-ln(L)`
///
/// You can use this function if your truth is a probability
/// (i.e., a value betwenn 0 and 1). Maximizing the likelihood
/// function is equivalent to minimizing the least square error,
/// yet this cost function has shown itself to converge quicker
/// for some problems.
///
/// #Examples
///
/// ```
/// use vikos::{learn_history, Model};
/// use vikos::model::{Logistic, Linear};
///
/// let history = [([2.7, 2.5], false),
///                ([1.4, 2.3], false),
///                ([3.3, 4.4], false),
///                ([1.3, 1.8], false),
///                ([3.0, 3.0], false),
///                ([7.6, 2.7], true),
///                ([5.3, 2.0], true),
///                ([6.9, 1.7], true),
///                ([8.6, -0.2], true),
///                ([7.6, 3.5], true)];
///
/// let mut model = Logistic {
///     linear: Linear {
///         m: [0.0, 0.0],
///         c: 0.0,
///     },
/// };
/// let teacher = teacher::GradientDescent { learning_rate: 0.3 };
/// let cost = cost::MaxLikelihood {};
///
/// learn_history(&teacher,
///               &cost,
///               &mut model,
///               history.iter().cycle().take(20).cloned());
/// ```
pub struct MaxLikelihood;

impl Cost<f64> for MaxLikelihood {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: f64, gradient_error_by_coefficent: f64) -> f64 {
        gradient_error_by_coefficent * ((1.0 - truth) / (1.0 - prediction) - truth / prediction)
    }
}

impl Cost<bool> for MaxLikelihood {
    type Error = f64;

    fn gradient(&self, prediction: f64, truth: bool, gradient_error_by_coefficent: f64) -> f64 {
        gradient_error_by_coefficent / if truth { -prediction } else { 1.0 - prediction }
    }
}
<|endoftext|>


<commit_before>use image;
use image::RgbaImage;

use glium::{DisplayBuild, VertexBuffer, Program, DrawParameters, Display, Surface};
use glium::{IndexBuffer, Frame, Blend};
use glium::index::PrimitiveType;
use glium::texture::{Texture2d, RawImage2d};
use glium::glutin::WindowBuilder;

use std::path::Path;
use std::ops::{Deref, DerefMut};

use super::{DrawResult, TextureResult};

#[derive(Copy, Clone)]
struct Vertex {
    position  : [f32; 2],
    tex_coords: [f32; 2]
}

implement_vertex!(Vertex, position, tex_coords);

impl Vertex{
    #[inline]
    fn new(position: [f32; 2], tex_coords: [f32; 2]) -> Self{
        Vertex{
            position  : position,
            tex_coords: tex_coords,
        }
    }
}

/// A 2D texture that is ready to be drawn
pub struct Texture{
    tex: Texture2d,
    vertex_buffer: VertexBuffer<Vertex>,
}

impl Texture {
    #[inline]
    /// Creates a `Texture` from a PNG-encoded byte slice
    pub fn from_png_bytes(display: &Display, bytes: &[u8]) -> TextureResult{
        Texture::new(display,
            try!(
                image::load_from_memory_with_format(bytes, image::PNG)
            ).to_rgba()
        )
    }
    #[inline]
    /// Creates a `Texture` from a file
    pub fn from_file<P: AsRef<Path>>(display: &Display, path: P) -> TextureResult{
        Texture::new(display,
            try!(
                image::open(path)
            ).to_rgba()
        )
    }

    /// Creates a `Texture` from an `image::RgbaImage`
    pub fn new(display: &Display, image: RgbaImage) -> TextureResult{
        let (width, height) = image.dimensions();
        let image = RawImage2d::from_raw_rgba_reversed(image.into_raw(), (width, height));

        let (w, h) = (width as f32 / 2.0, height as f32 / 2.0);

        let vb = try!(VertexBuffer::new(display, &[
            Vertex::new([-w, -h], [0.0, 0.0]),
            Vertex::new([ w, -h], [1.0, 0.0]),
            Vertex::new([ w,  h], [1.0, 1.0]),
            Vertex::new([-w,  h], [0.0, 1.0])
        ]));

        Ok(Texture {
            tex: try!(Texture2d::new(display, image)),
            vertex_buffer: vb,
        })
    }
}

/// Loads a texture, by loading the bytes at compile-time
#[macro_export]
macro_rules! include_texture {
    ($graphics:expr, $texture:tt) => {
        $crate::Texture::from_png_bytes(&$graphics, include_bytes!($texture))
    };
}

quick_error! {
    /// Wraps together errors that could occur creating a `Graphics` context
    #[derive(Debug)]
    pub enum GraphicsCreationError{
        /// A `glium::GliumCreationError<::glium::glutin::CreationError>`
        WindowBuilderError(err: ::glium::GliumCreationError<::glium::glutin::CreationError>){
            from()
            cause(err)
            description(err.description())
        }
        /// This shouldn't occur often
        IndexBufferCreationError(err: ::glium::index::BufferCreationError){
            from()
            cause(err)
            description(err.description())
        }
    }
}

/// Contains the display and handles most of the graphics
pub struct Graphics<'a> {
    display: Display,
    program: Program,
    h_size : (f32, f32),
    indices: IndexBuffer<u8>,
    params : DrawParameters<'a>
}

impl<'a> Graphics<'a> {
    /// Creates a new `Graphics` from a `Display` made using the arguments
    pub fn new(title: &str, width: u32, height: u32) -> Result<Self, GraphicsCreationError> {
        WindowBuilder::new()
            .with_title(title.to_string())
            .with_dimensions(width, height)
            .with_vsync()
            .build_glium()
            .map_err(Into::into)
            .and_then(Self::from_display)
    }

    /// Creates a new `Graphics` instance using the given display
    pub fn from_display(display: Display) -> Result<Self, GraphicsCreationError> {
        let (w, h) = display.get_window().unwrap().get_inner_size().unwrap();
        let (w, h) = (w as f32 / 2.0, h as f32 / 2.0);

        let params = DrawParameters{
            blend : Blend::alpha_blending(),
            .. Default::default()
        };

        let indices = try!(IndexBuffer::new(&display, PrimitiveType::TriangleStrip, &[0u8, 1, 3, 2]));

        Ok(Graphics{
            // Unwrap should be safe
            program: Program::from_source(&display, include_str!("shaders/texture.vs"), include_str!("shaders/texture.fs"), None).unwrap(),
            display: display,
            params : params,
            indices: indices,
            h_size : (w, h)
        })
    }

    #[inline]
    /// Returns half of the size of the window
    pub fn get_h_size(&self) -> (f32, f32){
        self.h_size
    }
}

#[inline(always)]
// This function is only used inside `FrameInfo` when Event::Resized occurs
pub fn resize(graphics: &mut Graphics, width: u32, height: u32){
    graphics.h_size = (width as f32 / 2.0, height as f32 / 2.0);
}

impl<'a> Deref for Graphics<'a>{
    type Target = Display;

    #[inline]
    fn deref(&self) -> &Display{
        &self.display
    }
}

/// Provides functionality for drawing.
///
/// Can also be dereferenced into a `glium::Frame`.
pub struct Drawer<'a>{
    target: Frame,
    /// Reference to the `Graphics` object
    pub graphics: &'a Graphics<'a>
}

impl<'a> Drawer<'a>{
    #[inline]
    /// Creates a new `Drawer` to draw the next frame
    pub fn new(graphics: &'a Graphics<'a>) -> Self{
        Drawer{
            target: graphics.draw(),
            graphics: graphics
        }
    }

    #[inline]
    /// Clears the screen with the specified colour
    pub fn clear(&mut self, red: f32, green: f32, blue: f32){
        self.clear_color(red, green, blue, 1.)
    }
    /// Draws a texture onto the screen
    #[deprecated(since = "0.11.1", note="use Drawer::texture() instead")]
    #[inline]
    pub fn draw_texture(&mut self, texture: &Texture, x: f32, y: f32, rotation: f32) -> DrawResult{
        self.texture(texture).pos((x, y)).rotation(rotation).draw()
    }
    /// Draws a texture onto the screen without rotation
    #[deprecated(since = "0.11.1", note="use Drawer::texture() instead")]
    #[inline]
    pub fn draw_texture_rigid(&mut self, texture: &Texture, x: f32, y: f32) -> DrawResult{
        self.texture(texture).pos((x, y)).draw()
    }
    /// Returns an object for drawing texture to the screen
    pub fn texture<'b>(&'b mut self, texture: &'b Texture) -> TextureDrawer<'b>{
        TextureDrawer::new(self, self.graphics, texture)
    }
}

impl<'a> Deref for Drawer<'a>{
    type Target = Frame;
    #[inline]
    fn deref(&self) -> &Frame{
        &self.target
    }
}

impl<'a> DerefMut for Drawer<'a>{
    #[inline]
    fn deref_mut(&mut self) -> &mut Frame{
        &mut self.target
    }
}

impl<'a> Drop for Drawer<'a>{
    #[inline]
    fn drop(&mut self){
        self.target.set_finish().unwrap()
    }
}

/// Object for drawing textures to the screen using the builder pattern
pub struct TextureDrawer<'a>{
    /// The position on the screen where the texture will be drawn
    pub pos: (f32, f32),
    sin_cos: (f32, f32),
    /// The colour the texture will drawn with
    pub colour: [f32; 4],
    target: &'a mut Frame,
    graphics: &'a Graphics<'a>,
    texture: &'a Texture
}

impl<'a> TextureDrawer<'a> {
    #[inline(always)]
    fn new(target: &'a mut Frame, graphics: &'a Graphics, texture: &'a Texture) -> Self {
        TextureDrawer{
            pos: (0., 0.),
            sin_cos: (0., 1.),
            colour: [1., 1., 1., 1.],
            target: target,
            graphics: graphics,
            texture: texture
        }
    }
    /// Sets the position the texture will be drawn at
    #[inline]
    pub fn pos(self, pos: (f32, f32)) -> Self{
        TextureDrawer{
            pos: pos,
            .. self
        }
    }
    /// Sets the colours the texture will be drawn with
    #[inline]
    pub fn colour(self, colour: [f32; 4]) -> Self{
        TextureDrawer{
            colour: colour,
            .. self
        }
    }
    #[inline]
    /// Sets the rotation of the texture to be drawn on the screen
    pub fn rotation(self, rot: f32) -> Self{
        TextureDrawer{
            sin_cos: rot.sin_cos(),
            .. self
        }
    }
    /// Consumes self and draws the texture to the screen with the given options
    pub fn draw(self) -> Result<(), ::glium::DrawError>{
        let TextureDrawer{pos: (x, y), sin_cos: (sin, cos), colour, target, graphics, texture} = self;

        let uniforms = uniform! {
            h_size: graphics.h_size,
            tex   : &texture.tex,
            colour: colour,
            matrix: [
                [ cos, sin, 0., 0.],
                [-sin, cos, 0., 0.],
                [  0.,  0., 1., 0.],
                [  x ,  y , 0., 1.],
            ]
        };

        target.draw(&texture.vertex_buffer, &graphics.indices, &graphics.program, &uniforms, &graphics.params)
    }
}
<commit_msg>Make `TextureDrawer` must_use<commit_after>use image;
use image::RgbaImage;

use glium::{DisplayBuild, VertexBuffer, Program, DrawParameters, Display, Surface};
use glium::{IndexBuffer, Frame, Blend};
use glium::index::PrimitiveType;
use glium::texture::{Texture2d, RawImage2d};
use glium::glutin::WindowBuilder;

use std::path::Path;
use std::ops::{Deref, DerefMut};

use super::{DrawResult, TextureResult};

#[derive(Copy, Clone)]
struct Vertex {
    position  : [f32; 2],
    tex_coords: [f32; 2]
}

implement_vertex!(Vertex, position, tex_coords);

impl Vertex{
    #[inline]
    fn new(position: [f32; 2], tex_coords: [f32; 2]) -> Self{
        Vertex{
            position  : position,
            tex_coords: tex_coords,
        }
    }
}

/// A 2D texture that is ready to be drawn
pub struct Texture{
    tex: Texture2d,
    vertex_buffer: VertexBuffer<Vertex>,
}

impl Texture {
    #[inline]
    /// Creates a `Texture` from a PNG-encoded byte slice
    pub fn from_png_bytes(display: &Display, bytes: &[u8]) -> TextureResult{
        Texture::new(display,
            try!(
                image::load_from_memory_with_format(bytes, image::PNG)
            ).to_rgba()
        )
    }
    #[inline]
    /// Creates a `Texture` from a file
    pub fn from_file<P: AsRef<Path>>(display: &Display, path: P) -> TextureResult{
        Texture::new(display,
            try!(
                image::open(path)
            ).to_rgba()
        )
    }

    /// Creates a `Texture` from an `image::RgbaImage`
    pub fn new(display: &Display, image: RgbaImage) -> TextureResult{
        let (width, height) = image.dimensions();
        let image = RawImage2d::from_raw_rgba_reversed(image.into_raw(), (width, height));

        let (w, h) = (width as f32 / 2.0, height as f32 / 2.0);

        let vb = try!(VertexBuffer::new(display, &[
            Vertex::new([-w, -h], [0.0, 0.0]),
            Vertex::new([ w, -h], [1.0, 0.0]),
            Vertex::new([ w,  h], [1.0, 1.0]),
            Vertex::new([-w,  h], [0.0, 1.0])
        ]));

        Ok(Texture {
            tex: try!(Texture2d::new(display, image)),
            vertex_buffer: vb,
        })
    }
}

/// Loads a texture, by loading the bytes at compile-time
#[macro_export]
macro_rules! include_texture {
    ($graphics:expr, $texture:tt) => {
        $crate::Texture::from_png_bytes(&$graphics, include_bytes!($texture))
    };
}

quick_error! {
    /// Wraps together errors that could occur creating a `Graphics` context
    #[derive(Debug)]
    pub enum GraphicsCreationError{
        /// A `glium::GliumCreationError<::glium::glutin::CreationError>`
        WindowBuilderError(err: ::glium::GliumCreationError<::glium::glutin::CreationError>){
            from()
            cause(err)
            description(err.description())
        }
        /// This shouldn't occur often
        IndexBufferCreationError(err: ::glium::index::BufferCreationError){
            from()
            cause(err)
            description(err.description())
        }
    }
}

/// Contains the display and handles most of the graphics
pub struct Graphics<'a> {
    display: Display,
    program: Program,
    h_size : (f32, f32),
    indices: IndexBuffer<u8>,
    params : DrawParameters<'a>
}

impl<'a> Graphics<'a> {
    /// Creates a new `Graphics` from a `Display` made using the arguments
    pub fn new(title: &str, width: u32, height: u32) -> Result<Self, GraphicsCreationError> {
        WindowBuilder::new()
            .with_title(title.to_string())
            .with_dimensions(width, height)
            .with_vsync()
            .build_glium()
            .map_err(Into::into)
            .and_then(Self::from_display)
    }

    /// Creates a new `Graphics` instance using the given display
    pub fn from_display(display: Display) -> Result<Self, GraphicsCreationError> {
        let (w, h) = display.get_window().unwrap().get_inner_size().unwrap();
        let (w, h) = (w as f32 / 2.0, h as f32 / 2.0);

        let params = DrawParameters{
            blend : Blend::alpha_blending(),
            .. Default::default()
        };

        let indices = try!(IndexBuffer::new(&display, PrimitiveType::TriangleStrip, &[0u8, 1, 3, 2]));

        Ok(Graphics{
            // Unwrap should be safe
            program: Program::from_source(&display, include_str!("shaders/texture.vs"), include_str!("shaders/texture.fs"), None).unwrap(),
            display: display,
            params : params,
            indices: indices,
            h_size : (w, h)
        })
    }

    #[inline]
    /// Returns half of the size of the window
    pub fn get_h_size(&self) -> (f32, f32){
        self.h_size
    }
}

#[inline(always)]
// This function is only used inside `FrameInfo` when Event::Resized occurs
pub fn resize(graphics: &mut Graphics, width: u32, height: u32){
    graphics.h_size = (width as f32 / 2.0, height as f32 / 2.0);
}

impl<'a> Deref for Graphics<'a>{
    type Target = Display;

    #[inline]
    fn deref(&self) -> &Display{
        &self.display
    }
}

/// Provides functionality for drawing.
///
/// Can also be dereferenced into a `glium::Frame`.
pub struct Drawer<'a>{
    target: Frame,
    /// Reference to the `Graphics` object
    pub graphics: &'a Graphics<'a>
}

impl<'a> Drawer<'a>{
    #[inline]
    /// Creates a new `Drawer` to draw the next frame
    pub fn new(graphics: &'a Graphics<'a>) -> Self{
        Drawer{
            target: graphics.draw(),
            graphics: graphics
        }
    }

    #[inline]
    /// Clears the screen with the specified colour
    pub fn clear(&mut self, red: f32, green: f32, blue: f32){
        self.clear_color(red, green, blue, 1.)
    }
    /// Draws a texture onto the screen
    #[deprecated(since = "0.11.1", note="use Drawer::texture() instead")]
    #[inline]
    pub fn draw_texture(&mut self, texture: &Texture, x: f32, y: f32, rotation: f32) -> DrawResult{
        self.texture(texture).pos((x, y)).rotation(rotation).draw()
    }
    /// Draws a texture onto the screen without rotation
    #[deprecated(since = "0.11.1", note="use Drawer::texture() instead")]
    #[inline]
    pub fn draw_texture_rigid(&mut self, texture: &Texture, x: f32, y: f32) -> DrawResult{
        self.texture(texture).pos((x, y)).draw()
    }
    /// Returns an object for drawing texture to the screen
    pub fn texture<'b>(&'b mut self, texture: &'b Texture) -> TextureDrawer<'b>{
        TextureDrawer::new(self, self.graphics, texture)
    }
}

impl<'a> Deref for Drawer<'a>{
    type Target = Frame;
    #[inline]
    fn deref(&self) -> &Frame{
        &self.target
    }
}

impl<'a> DerefMut for Drawer<'a>{
    #[inline]
    fn deref_mut(&mut self) -> &mut Frame{
        &mut self.target
    }
}

impl<'a> Drop for Drawer<'a>{
    #[inline]
    fn drop(&mut self){
        self.target.set_finish().unwrap()
    }
}

/// Object for drawing textures to the screen using the builder pattern
#[must_use = "`TextureDrawer` is lazy and does nothing until consumed"]
pub struct TextureDrawer<'a>{
    /// The position on the screen where the texture will be drawn
    pub pos: (f32, f32),
    sin_cos: (f32, f32),
    /// The colour the texture will drawn with
    pub colour: [f32; 4],
    target: &'a mut Frame,
    graphics: &'a Graphics<'a>,
    texture: &'a Texture
}

impl<'a> TextureDrawer<'a> {
    #[inline(always)]
    fn new(target: &'a mut Frame, graphics: &'a Graphics, texture: &'a Texture) -> Self {
        TextureDrawer{
            pos: (0., 0.),
            sin_cos: (0., 1.),
            colour: [1., 1., 1., 1.],
            target: target,
            graphics: graphics,
            texture: texture
        }
    }
    /// Sets the position the texture will be drawn at
    #[inline]
    pub fn pos(self, pos: (f32, f32)) -> Self{
        TextureDrawer{
            pos: pos,
            .. self
        }
    }
    /// Sets the colours the texture will be drawn with
    #[inline]
    pub fn colour(self, colour: [f32; 4]) -> Self{
        TextureDrawer{
            colour: colour,
            .. self
        }
    }
    #[inline]
    /// Sets the rotation of the texture to be drawn on the screen
    pub fn rotation(self, rot: f32) -> Self{
        TextureDrawer{
            sin_cos: rot.sin_cos(),
            .. self
        }
    }
    /// Consumes self and draws the texture to the screen with the given options
    pub fn draw(self) -> Result<(), ::glium::DrawError>{
        let TextureDrawer{pos: (x, y), sin_cos: (sin, cos), colour, target, graphics, texture} = self;

        let uniforms = uniform! {
            h_size: graphics.h_size,
            tex   : &texture.tex,
            colour: colour,
            matrix: [
                [ cos, sin, 0., 0.],
                [-sin, cos, 0., 0.],
                [  0.,  0., 1., 0.],
                [  x ,  y , 0., 1.],
            ]
        };

        target.draw(&texture.vertex_buffer, &graphics.indices, &graphics.program, &uniforms, &graphics.params)
    }
}
<|endoftext|>


<commit_before>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

macro_rules! vi_repeat {
    ( $ctx:ident, $x:expr ) => {
        match $ctx.vi_count {
            0 => { $x; }
            _ => for _ in 0..$ctx.vi_count { $x; }
        }
        $ctx.vi_count = 0;
    };
    ( $ctx:ident, $operation:expr, $step:expr ) => {
        match $ctx.vi_count {
            0 => { $operation; }
            _ => {
                $operation;
                for _ in 1..$ctx.vi_count { $step; $operation; }
            }
        }
        $ctx.vi_count = 0;
    };
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_left_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    vi_repeat!(ctx, ctx.buf.move_left());
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    vi_repeat!(ctx, ctx.buf.move_right());
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.buf.move_end();
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.incr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.decr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_back());
                    Cont(false)
                }
                instr::Instr::MoveWordWsLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws_back());
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    vi_repeat!(
                        ctx,
                        ctx.buf.replace_chars_at_cursor(text.clone()),
                        {
                            ctx.buf.move_right();
                            ctx.buf.exclude_eol();
                        }
                    );
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<commit_msg>reset count for move start and end commands<commit_after>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

macro_rules! vi_repeat {
    ( $ctx:ident, $x:expr ) => {
        match $ctx.vi_count {
            0 => { $x; }
            _ => for _ in 0..$ctx.vi_count { $x; }
        }
        $ctx.vi_count = 0;
    };
    ( $ctx:ident, $operation:expr, $step:expr ) => {
        match $ctx.vi_count {
            0 => { $operation; }
            _ => {
                $operation;
                for _ in 1..$ctx.vi_count { $step; $operation; }
            }
        }
        $ctx.vi_count = 0;
    };
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_left_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    vi_repeat!(ctx, ctx.buf.move_left());
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    vi_repeat!(ctx, ctx.buf.move_right());
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.vi_count = 0;
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.vi_count = 0;
                    ctx.buf.move_end();
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.incr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.decr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_back());
                    Cont(false)
                }
                instr::Instr::MoveWordWsLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws_back());
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    vi_repeat!(
                        ctx,
                        ctx.buf.replace_chars_at_cursor(text.clone()),
                        {
                            ctx.buf.move_right();
                            ctx.buf.exclude_eol();
                        }
                    );
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<|endoftext|>


<commit_before>//! Main evaluator loop and setting up the initial stack frame.

use std::ffi::OsStr;

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};
use rustc_hir::def_id::DefId;

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking is enabled.
    pub validate: bool,
    /// Determines if Stacked Borrows is enabled.
    pub stacked_borrows: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Determines if memory leaks should be ignored.
    pub ignore_leaks: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
    /// The stacked borrow id to report about
    pub tracked_pointer_tag: Option<PtrId>,
    /// The allocation id to report about.
    pub tracked_alloc_id: Option<AllocId>,
}

impl Default for MiriConfig {
    fn default() -> MiriConfig {
        MiriConfig {
            validate: true,
            stacked_borrows: true,
            communicate: false,
            ignore_leaks: false,
            excluded_env_vars: vec![],
            args: vec![],
            seed: None,
            tracked_pointer_tag: None,
            tracked_alloc_id: None,
        }
    }
}

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(rustc_span::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate, config.validate),
        MemoryExtra::new(
            StdRng::seed_from_u64(config.seed.unwrap_or(0)),
            config.stacked_borrows,
            config.tracked_pointer_tag,
            config.tracked_alloc_id,
        ),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars)?;
    MemoryExtra::init_extern_statics(&mut ecx)?;

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;
    if main_mir.arg_count != 0 {
        bug!("main function must not take any arguments");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // Put each argument in memory, collect pointers.
        let mut argvs = Vec::<Scalar<Tag>>::new();
        for arg in config.args.iter() {
            // Make space for `0` terminator.
            let size = arg.len() as u64 + 1;
            let arg_type = tcx.mk_array(tcx.types.u8, size);
            let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into());
            ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
            argvs.push(arg_place.ptr);
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout =
            ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(arg, place.into())?;
        }
        ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the 3rd argument for main.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place =
                ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into());
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Machine.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            // Construct a command string with all the aguments.
            let mut cmd = String::new();
            for arg in config.args.iter() {
                if !cmd.is_empty() {
                    cmd.push(' ');
                }
                cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
            }
            // Don't forget `0` terminator.
            cmd.push(std::char::from_u32(0).unwrap());

            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into());
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc.into(), argv.into()],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    // FIXME: We always ignore leaks on some platforms where we do not
    // correctly implement TLS destructors.
    let target_os = tcx.sess.target.target.target_os.as_str();
    let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos";

    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialziation error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        while ecx.step()? {
            ecx.process_diagnostics();
        }
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            Some(return_code)
        }
        Err(e) => report_diagnostic(&ecx, e),
    }
}
<commit_msg>Auto merge of #1231 - JOE1994:patch-1, r=RalfJung<commit_after>//! Main evaluator loop and setting up the initial stack frame.

use std::ffi::OsStr;

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};
use rustc_hir::def_id::DefId;

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking is enabled.
    pub validate: bool,
    /// Determines if Stacked Borrows is enabled.
    pub stacked_borrows: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Determines if memory leaks should be ignored.
    pub ignore_leaks: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
    /// The stacked borrow id to report about
    pub tracked_pointer_tag: Option<PtrId>,
    /// The allocation id to report about.
    pub tracked_alloc_id: Option<AllocId>,
}

impl Default for MiriConfig {
    fn default() -> MiriConfig {
        MiriConfig {
            validate: true,
            stacked_borrows: true,
            communicate: false,
            ignore_leaks: false,
            excluded_env_vars: vec![],
            args: vec![],
            seed: None,
            tracked_pointer_tag: None,
            tracked_alloc_id: None,
        }
    }
}

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(rustc_span::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate, config.validate),
        MemoryExtra::new(
            StdRng::seed_from_u64(config.seed.unwrap_or(0)),
            config.stacked_borrows,
            config.tracked_pointer_tag,
            config.tracked_alloc_id,
        ),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars)?;
    MemoryExtra::init_extern_statics(&mut ecx)?;

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;
    if main_mir.arg_count != 0 {
        bug!("main function must not take any arguments");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // Put each argument in memory, collect pointers.
        let mut argvs = Vec::<Scalar<Tag>>::new();
        for arg in config.args.iter() {
            // Make space for `0` terminator.
            let size = arg.len() as u64 + 1;
            let arg_type = tcx.mk_array(tcx.types.u8, size);
            let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into());
            ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
            argvs.push(arg_place.ptr);
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout =
            ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(arg, place.into())?;
        }
        ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the 3rd argument for main.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place =
                ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into());
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Machine.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            // Construct a command string with all the aguments.
            let mut cmd = String::new();
            for arg in config.args.iter() {
                if !cmd.is_empty() {
                    cmd.push(' ');
                }
                cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
            }
            // Don't forget `0` terminator.
            cmd.push(std::char::from_u32(0).unwrap());

            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into());
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc.into(), argv.into()],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    // FIXME: We always ignore leaks on some platforms where we do not
    // correctly implement TLS destructors.
    let target_os = tcx.sess.target.target.target_os.as_str();
    let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos";

    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialization error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        while ecx.step()? {
            ecx.process_diagnostics();
        }
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            Some(return_code)
        }
        Err(e) => report_diagnostic(&ecx, e),
    }
}
<|endoftext|>