<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift, self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

/// Function to return the character associated with the scancode, and the layout
fn char_for_scancode(scancode: u8, shift: bool, layout: usize) -> char {
    if scancode >= 58 {
        '\x00'
    }
    let character =
        match layout {
            0 => SCANCODES_EN[scancode as usize],
            1 => SCANCODES_FR[scancode as usize],
        };
    if shift {
        character = characters[1]
    } else {
        character = characters[scancode as usize][0]
    }
}

static SCANCODES_EN: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<commit_msg>debugging char_for_scancode<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift, self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

/// Function to return the character associated with the scancode, and the layout
fn char_for_scancode(scancode: u8, shift: bool, layout: usize) -> char {
    if scancode >= 58 {
        '\x00'
    }
    let characters =
        match layout {
            0 => SCANCODES_EN[scancode as usize],
            1 => SCANCODES_FR[scancode as usize],
        };
    if shift {
        character = characters[1]
    } else {
        character = characters[scancode as usize][0]
    }
}

static SCANCODES_EN: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Debug callback called by validation layers.
//!
//! When working on an application, it is recommended to register a debug callback. This callback
//! will be called by validation layers whenever necessary to warn you about invalid API usages
//! or performance problems.
//!
//! Note that the vulkano library can also emit messages to warn you about performance issues.
//!
//! # Example
//!
//! ```no_run
//! # use vulkano::instance::Instance;
//! # use std::sync::Arc;
//! # let instance: Arc<Instance> = unsafe { ::std::mem::uninitialized() };
//! use vulkano::instance::debug::DebugCallback;
//!
//! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
//!     println!("Debug callback: {:?}", msg.description);
//! }).ok();
//! ```

use std::error;
use std::ffi::CStr;
use std::fmt;
use std::mem;
use std::os::raw::{c_void, c_char};
use std::ptr;
use std::sync::Arc;

use instance::Instance;

use check_errors;
use Error;
use VulkanObject;
use VulkanPointers;
use vk;

/// Registration of a callback called by validation layers.
///
/// The callback can be called as long as this object is alive.
pub struct DebugCallback {
    instance: Arc<Instance>,
    debug_report_callback: vk::DebugReportCallbackEXT,
    user_callback: Box<Box<Fn(&Message)>>,
}

impl DebugCallback {
    /// Initializes a debug callback.
    pub fn new<F>(instance: &Arc<Instance>, messages: MessageTypes, user_callback: F)
                  -> Result<DebugCallback, DebugCallbackCreationError>
        where F: Fn(&Message) + 'static
    {
        if !instance.loaded_extensions().ext_debug_report {
            return Err(DebugCallbackCreationError::MissingExtension);
        }

        // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
        // that can't be casted to a `*const c_void`.
        let user_callback = Box::new(Box::new(user_callback) as Box<_>);

        extern "system" fn callback(ty: vk::DebugReportFlagsEXT,
                                    _: vk::DebugReportObjectTypeEXT, _: u64, _: usize,
                                    _: i32, layer_prefix: *const c_char,
                                    description: *const c_char, user_data: *mut c_void) -> u32
        {
            // FIXME: use panic::recover

            unsafe {
                let user_callback = user_data as *mut Box<Fn()> as *const _;
                let user_callback: &Box<Fn(&Message)> = &*user_callback;

                let layer_prefix = CStr::from_ptr(layer_prefix).to_str()
                                                               .expect("debug callback message \
                                                                        not utf-8");
                let description = CStr::from_ptr(description).to_str()
                                                             .expect("debug callback message \
                                                                      not utf-8");

                let message = Message {
                    ty: MessageTypes {
                        information: (ty & vk::DEBUG_REPORT_INFORMATION_BIT_EXT) != 0,
                        warning: (ty & vk::DEBUG_REPORT_WARNING_BIT_EXT) != 0,
                        performance_warning: (ty & vk::DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0,
                        error: (ty & vk::DEBUG_REPORT_ERROR_BIT_EXT) != 0,
                        debug: (ty & vk::DEBUG_REPORT_DEBUG_BIT_EXT) != 0,
                    },
                    layer_prefix: layer_prefix,
                    description: description,
                };

                user_callback(&message);

                vk::FALSE
            }
        }

        let flags = {
            let mut flags = 0;
            if messages.information { flags |= vk::DEBUG_REPORT_INFORMATION_BIT_EXT; }
            if messages.warning { flags |= vk::DEBUG_REPORT_WARNING_BIT_EXT; }
            if messages.performance_warning { flags |= vk::DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; }
            if messages.error { flags |= vk::DEBUG_REPORT_ERROR_BIT_EXT; }
            if messages.debug { flags |= vk::DEBUG_REPORT_DEBUG_BIT_EXT; }
            flags
        };

        let infos = vk::DebugReportCallbackCreateInfoEXT {
            sType: vk::STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
            pNext: ptr::null(),
            flags: flags,
            pfnCallback: callback,
            pUserData: &*user_callback as &Box<_> as *const Box<_> as *const c_void as *mut _,
        };

        let vk = instance.pointers();

        let debug_report_callback = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDebugReportCallbackEXT(instance.internal_object(), &infos,
                                                              ptr::null(), &mut output)));
            output
        };

        Ok(DebugCallback {
            instance: instance.clone(),
            debug_report_callback: debug_report_callback,
            user_callback: user_callback,
        })
    }

    /// Initializes a debug callback with errors and warnings.
    ///
    /// Shortcut for `new(instance, MessageTypes::errors_and_warnings(), user_callback)`.
    #[inline]
    pub fn errors_and_warnings<F>(instance: &Arc<Instance>, user_callback: F)
                                  -> Result<DebugCallback, DebugCallbackCreationError>
        where F: Fn(&Message) + 'static
    {
        DebugCallback::new(instance, MessageTypes::errors_and_warnings(), user_callback)
    }
}

impl Drop for DebugCallback {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.instance.pointers();
            vk.DestroyDebugReportCallbackEXT(self.instance.internal_object(),
                                             self.debug_report_callback, ptr::null());
        }
    }
}

/// A message received by the callback.
pub struct Message<'a> {
    /// Type of message.
    pub ty: MessageTypes,
    /// Prefix of the layer that reported this message.
    pub layer_prefix: &'a str,
    /// Description of the message.
    pub description: &'a str,
}

/// Type of message.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct MessageTypes {
    /// An error that may cause undefined results, including an application crash.
    pub error: bool,
    /// An unexpected use.
    pub warning: bool,
    /// A potential non-optimal use.
    pub performance_warning: bool,
    /// An informational message that may be handy when debugging an application.
    pub information: bool,
    /// Diagnostic information from the loader and layers.
    pub debug: bool,
}

impl MessageTypes {
    /// Builds a `MessageTypes` with all fields set to `false` expect `error`.
    #[inline]
    pub fn errors() -> MessageTypes {
        MessageTypes {
            error: true,
            .. MessageTypes::none()
        }
    }

    /// Builds a `MessageTypes` with all fields set to `false` expect `error`, `warning`
    /// and `performance_warning`.
    #[inline]
    pub fn errors_and_warnings() -> MessageTypes {
        MessageTypes {
            error: true,
            warning: true,
            performance_warning: true,
            .. MessageTypes::none()
        }
    }

    /// Builds a `MessageTypes` with all fields set to `false`.
    #[inline]
    pub fn none() -> MessageTypes {
        MessageTypes {
            error: false,
            warning: false,
            performance_warning: false,
            information: false,
            debug: false,
        }
    }
}

/// Error that can happen when creating a debug callback.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugCallbackCreationError {
    /// The `EXT_debug_report` extension was not enabled.
    MissingExtension,
}

impl error::Error for DebugCallbackCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DebugCallbackCreationError::MissingExtension => "the `EXT_debug_report` extension was \
                                                             not enabled",
        }
    }
}

impl fmt::Display for DebugCallbackCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for DebugCallbackCreationError {
    #[inline]
    fn from(err: Error) -> DebugCallbackCreationError {
        panic!("unexpected error: {:?}", err)
    }
}
<commit_msg>Catch when the debug callback panicks<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Debug callback called by validation layers.
//!
//! When working on an application, it is recommended to register a debug callback. This callback
//! will be called by validation layers whenever necessary to warn you about invalid API usages
//! or performance problems.
//!
//! Note that the vulkano library can also emit messages to warn you about performance issues.
//!
//! # Example
//!
//! ```no_run
//! # use vulkano::instance::Instance;
//! # use std::sync::Arc;
//! # let instance: Arc<Instance> = unsafe { ::std::mem::uninitialized() };
//! use vulkano::instance::debug::DebugCallback;
//!
//! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
//!     println!("Debug callback: {:?}", msg.description);
//! }).ok();
//! ```

use std::error;
use std::ffi::CStr;
use std::fmt;
use std::mem;
use std::os::raw::{c_void, c_char};
use std::panic;
use std::ptr;
use std::sync::Arc;

use instance::Instance;

use check_errors;
use Error;
use VulkanObject;
use VulkanPointers;
use vk;

/// Registration of a callback called by validation layers.
///
/// The callback can be called as long as this object is alive.
pub struct DebugCallback {
    instance: Arc<Instance>,
    debug_report_callback: vk::DebugReportCallbackEXT,
    user_callback: Box<Box<Fn(&Message)>>,
}

impl DebugCallback {
    /// Initializes a debug callback.
    ///
    /// Panicks generated by calling `user_callback` are ignored.
    pub fn new<F>(instance: &Arc<Instance>, messages: MessageTypes, user_callback: F)
                  -> Result<DebugCallback, DebugCallbackCreationError>
        where F: Fn(&Message) + 'static + panic::RefUnwindSafe
    {
        if !instance.loaded_extensions().ext_debug_report {
            return Err(DebugCallbackCreationError::MissingExtension);
        }

        // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
        // that can't be casted to a `*const c_void`.
        let user_callback = Box::new(Box::new(user_callback) as Box<_>);

        extern "system" fn callback(ty: vk::DebugReportFlagsEXT,
                                    _: vk::DebugReportObjectTypeEXT, _: u64, _: usize,
                                    _: i32, layer_prefix: *const c_char,
                                    description: *const c_char, user_data: *mut c_void) -> u32
        {
            unsafe {
                let user_callback = user_data as *mut Box<Fn()> as *const _;
                let user_callback: &Box<Fn(&Message)> = &*user_callback;

                let layer_prefix = CStr::from_ptr(layer_prefix).to_str()
                                                               .expect("debug callback message \
                                                                        not utf-8");
                let description = CStr::from_ptr(description).to_str()
                                                             .expect("debug callback message \
                                                                      not utf-8");

                let message = Message {
                    ty: MessageTypes {
                        information: (ty & vk::DEBUG_REPORT_INFORMATION_BIT_EXT) != 0,
                        warning: (ty & vk::DEBUG_REPORT_WARNING_BIT_EXT) != 0,
                        performance_warning: (ty & vk::DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0,
                        error: (ty & vk::DEBUG_REPORT_ERROR_BIT_EXT) != 0,
                        debug: (ty & vk::DEBUG_REPORT_DEBUG_BIT_EXT) != 0,
                    },
                    layer_prefix: layer_prefix,
                    description: description,
                };

                // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
                // bound is enforced. Therefore we enforce it manually.
                let _ = panic::catch_unwind(panic::AssertUnwindSafe(move || {
                    user_callback(&message);
                }));

                vk::FALSE
            }
        }

        let flags = {
            let mut flags = 0;
            if messages.information { flags |= vk::DEBUG_REPORT_INFORMATION_BIT_EXT; }
            if messages.warning { flags |= vk::DEBUG_REPORT_WARNING_BIT_EXT; }
            if messages.performance_warning { flags |= vk::DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; }
            if messages.error { flags |= vk::DEBUG_REPORT_ERROR_BIT_EXT; }
            if messages.debug { flags |= vk::DEBUG_REPORT_DEBUG_BIT_EXT; }
            flags
        };

        let infos = vk::DebugReportCallbackCreateInfoEXT {
            sType: vk::STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
            pNext: ptr::null(),
            flags: flags,
            pfnCallback: callback,
            pUserData: &*user_callback as &Box<_> as *const Box<_> as *const c_void as *mut _,
        };

        let vk = instance.pointers();

        let debug_report_callback = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDebugReportCallbackEXT(instance.internal_object(), &infos,
                                                              ptr::null(), &mut output)));
            output
        };

        Ok(DebugCallback {
            instance: instance.clone(),
            debug_report_callback: debug_report_callback,
            user_callback: user_callback,
        })
    }

    /// Initializes a debug callback with errors and warnings.
    ///
    /// Shortcut for `new(instance, MessageTypes::errors_and_warnings(), user_callback)`.
    #[inline]
    pub fn errors_and_warnings<F>(instance: &Arc<Instance>, user_callback: F)
                                  -> Result<DebugCallback, DebugCallbackCreationError>
        where F: Fn(&Message) + 'static + panic::RefUnwindSafe
    {
        DebugCallback::new(instance, MessageTypes::errors_and_warnings(), user_callback)
    }
}

impl Drop for DebugCallback {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.instance.pointers();
            vk.DestroyDebugReportCallbackEXT(self.instance.internal_object(),
                                             self.debug_report_callback, ptr::null());
        }
    }
}

/// A message received by the callback.
pub struct Message<'a> {
    /// Type of message.
    pub ty: MessageTypes,
    /// Prefix of the layer that reported this message.
    pub layer_prefix: &'a str,
    /// Description of the message.
    pub description: &'a str,
}

/// Type of message.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct MessageTypes {
    /// An error that may cause undefined results, including an application crash.
    pub error: bool,
    /// An unexpected use.
    pub warning: bool,
    /// A potential non-optimal use.
    pub performance_warning: bool,
    /// An informational message that may be handy when debugging an application.
    pub information: bool,
    /// Diagnostic information from the loader and layers.
    pub debug: bool,
}

impl MessageTypes {
    /// Builds a `MessageTypes` with all fields set to `false` expect `error`.
    #[inline]
    pub fn errors() -> MessageTypes {
        MessageTypes {
            error: true,
            .. MessageTypes::none()
        }
    }

    /// Builds a `MessageTypes` with all fields set to `false` expect `error`, `warning`
    /// and `performance_warning`.
    #[inline]
    pub fn errors_and_warnings() -> MessageTypes {
        MessageTypes {
            error: true,
            warning: true,
            performance_warning: true,
            .. MessageTypes::none()
        }
    }

    /// Builds a `MessageTypes` with all fields set to `false`.
    #[inline]
    pub fn none() -> MessageTypes {
        MessageTypes {
            error: false,
            warning: false,
            performance_warning: false,
            information: false,
            debug: false,
        }
    }
}

/// Error that can happen when creating a debug callback.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugCallbackCreationError {
    /// The `EXT_debug_report` extension was not enabled.
    MissingExtension,
}

impl error::Error for DebugCallbackCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DebugCallbackCreationError::MissingExtension => "the `EXT_debug_report` extension was \
                                                             not enabled",
        }
    }
}

impl fmt::Display for DebugCallbackCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for DebugCallbackCreationError {
    #[inline]
    fn from(err: Error) -> DebugCallbackCreationError {
        panic!("unexpected error: {:?}", err)
    }
}
<|endoftext|>


<commit_before>#[link(name = "rusp",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/rusp")];

#[comment = "A minimal Lisp dialect for Rust."];
#[license = "ASL2"];
#[crate_type = "lib"];

// Inspired by Peter Norvig's [Lis.py](http://norvig.com/lispy.html)

use std::hashmap::*;

pub mod parse;
pub mod pprint;

/// Symbol identifier
pub type Ident = ~str;

/// Holds a typed value
pub enum Value {
    /// The unit type: `()`
    Unit,
    /// A boolean value: either `true` or `false`
    Bool(bool),
    /// An integer value
    Int(int),
    /// A floating point value
    Float(float),
    /// String value: `"<value>"`
    Str(~str),
    /// Quoted expression: `(quote <expr>)`
    Quote(~Expr),
    /// A Rust function
    Rust(~fn(params: ~[Ident], env: &Env) -> Value),
    /// Anonymous function: `(fn (<ident>*) <expr>)`
    Fn(~[Ident], ~Expr),
}

impl Eq for Value {
    fn eq(&self, other: &Value) -> bool {
        macro_rules! cmp_other(
            ($cmp_pat:pat => $cmp_expr:expr) => (
                match *other { $cmp_pat => $cmp_expr, _ => false, }
            )
        );
        match *self {
            Unit => cmp_other!(Unit => true),
            Bool(b0) => cmp_other!(Bool(b1) => b0 == b1),
            Int(i0) => cmp_other!(Int(i1) => i0 == i1),
            Float(f0) => cmp_other!(Float(f1) => f0 == f1),
            Str(ref s0) => cmp_other!(Str(ref s1) => *s0 == *s1),
            Quote(ref expr0) => cmp_other!(Quote(ref expr1) => *expr0 == *expr1),
            Rust(_) => cmp_other!(Rust(_) => fail!("Cannot test equality of Rust functions (yet?).")),
            Fn(ref params0, ref expr0) => cmp_other!(Fn(ref params1, ref expr1) => {
                (*params0 == *params1) && (*expr0 == *expr1)
            }),
        }
    }
    fn ne(&self, other: &Value) -> bool { !self.eq(other) }
}

impl Clone for Value {
    fn clone(&self) -> Value {
        match *self {
            Unit => Unit,
            Bool(b) => Bool(b),
            Int(i) => Int(i),
            Float(f) => Float(f),
            Str(ref s) => Str(s.clone()),
            Quote(ref expr) => Quote(expr.clone()),
            Rust(_) => fail!("Cannot test the equality of Rust functions (yet?)"),
            Fn(ref params, ref expr) => Fn(params.clone(), expr.clone()),
        }
    }
}

///
/// Primitive language expressions
///
#[deriving(Eq, Clone)]
pub enum Expr {
    /// Symbol reference: `<ident>`
    Symbol(Ident),
    /// Constant literal: `<val>`
    Literal(Value),
    /// Conditional expression: `(if <test> <conseq> <alt>)`
    If(~Expr, ~Expr, ~Expr),
    /// Symbol definition: `(let <ident> <expr>)`
    Let(Ident, ~Expr),
    /// Do expression: `(do <expr>+)`
    Do(~[~Expr]),
    /// Procedure call: `(<expr> <expr>+)`
    Call(~Expr, ~[~Expr]),
}

#[deriving(Eq)]
pub struct Env {
    values: HashMap<Ident, Value>,
    outer: Option<@mut Env>,
}

impl Env {
    /// Initializes an empty environment
    pub fn empty() -> @mut Env {
        @mut Env {
            values: HashMap::new(),
            outer: None,
        }
    }

    /// Initializes a new environment with the specified values
    pub fn new(outer: @mut Env) -> @mut Env {
        @mut Env {
            values: HashMap::new(),
            outer: Some(outer),
        }
    }

    /// Defines a new identifier/value pair
    pub fn define(&mut self, ident: Ident, val: Value) -> bool {
        self.values.insert(ident, val)
    }

    /// Attempts to find a value corresponding to the supplied identifier
    pub fn find(&self, ident: &Ident) -> Option<Value> {
        match self.values.find(ident) {
            Some(val) => Some(val.clone()),
            None => self.outer.chain(|env| env.find(ident)),
        }
    }
}

pub type EvalResult = Result<Value, ~str>;

impl Expr {
    /// Evaluates a Rusp expression
    pub fn eval(&self, env: @mut Env) -> EvalResult {
        match *self {
            Symbol(ref id) =>{
                match env.find(id) {
                    Some(val) => Ok(val),
                    None => Err(fmt!("The value of `%s` was not defined in this environment", id.to_str())),
                }
            }
            Literal(ref val) => {
                Ok(val.clone())
            }
            If(ref test, ref conseq, ref alt) => {
                do test.eval(env).chain |val| {
                    match val {
                        Bool(true) => conseq.eval(env),
                        Bool(false) => alt.eval(env),
                        _ => Err(fmt!("expected boolean expression, found: %s", val.to_str())),
                    }
                }
            }
            Let(ref id, ref expr) => {
                do expr.eval(env).chain |val| {
                    if env.define(id.clone(), val) {
                        Ok(Unit)
                    } else {
                        Err(fmt!("`%s` was already defined in this environment.", id.to_str()))
                    }
                }
            }
            Do(ref exprs) => {
                for uint::range(0, exprs.len() - 1) |i| {
                    match exprs[i].eval(env) {
                        Ok(Unit) => (),
                        Ok(val) => return Err(fmt!("expected unit expression, found: %s", val.to_str())),
                        Err(err) => return Err(err),
                    }
                }
                exprs[exprs.len() - 1].eval(env)
            }
            Call(_,_) => fail!("Not yet implemented"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_env() {
        let outer = Env::empty();
        outer.define(~"a", Int(0));
        outer.define(~"b", Float(1.0));
        outer.define(~"c", Str(~"hi"));

        let inner = Env::new(outer);
        inner.define(~"a", Int(3));
        inner.define(~"b", Int(4));

        assert_eq!(outer.find(&~"a"), Some(Int(0)));
        assert_eq!(outer.find(&~"b"), Some(Float(1.0)));
        assert_eq!(outer.find(&~"c"), Some(Str(~"hi")));
        assert_eq!(inner.find(&~"a"), Some(Int(3)));
        assert_eq!(inner.find(&~"b"), Some(Int(4)));
        assert_eq!(inner.find(&~"c"), Some(Str(~"hi")));
    }

    #[test]
    fn test_eval_symbol() {
        let env = Env::empty();
        env.define(~"a", Int(0));
        env.define(~"b", Float(1.0));
        env.define(~"c", Str(~"hi"));

        assert_eq!(Symbol(~"a").eval(env).get(), Int(0));
        assert_eq!(Symbol(~"b").eval(env).get(), Float(1.0));
        assert_eq!(Symbol(~"c").eval(env).get(), Str(~"hi"));
        assert!(Symbol(~"d").eval(env).is_err());
    }

    #[test]
    fn test_eval_literal() {
        assert_eq!(Literal(Unit).eval(Env::empty()).get(), Unit);
        assert_eq!(Literal(Int(1)).eval(Env::empty()).get(), Int(1));
        assert_eq!(Literal(Float(1.0)).eval(Env::empty()).get(), Float(1.0));
        assert_eq!(Literal(Str(~"hi")).eval(Env::empty()).get(), Str(~"hi"));
        assert_eq!(Literal(Quote(~Literal(Unit))).eval(Env::empty()).get(),
                   Quote(~Literal(Unit)));
    }

    #[test]
    fn test_eval_if() {
        fn not(test: Value) -> EvalResult {
            If(
                ~Literal(test),
                ~Literal(Bool(false)),
                ~Literal(Bool(true))
            ).eval(Env::empty())
        }

        assert_eq!(not(Bool(true)).get(), Bool(false));
        assert_eq!(not(Bool(false)).get(), Bool(true));
        assert!(not(Str(~"hi")).is_err());
    }

    #[test]
    fn test_eval_let() {
        let env = Env::empty();
        assert!(Let(~"a", ~Literal(Int(0))).eval(env).is_ok());
        assert!(Let(~"b", ~Literal(Float(1.0))).eval(env).is_ok());
        assert!(Let(~"c", ~Literal(Str(~"hi"))).eval(env).is_ok());

        assert_eq!(env.find(&~"a"), Some(Int(0)));
        assert_eq!(env.find(&~"b"), Some(Float(1.0)));
        assert_eq!(env.find(&~"c"), Some(Str(~"hi")));

        assert!(Let(~"c", ~Literal(Unit)).eval(env).is_err());
    }

    #[test]
    fn test_eval_do() {
        assert_eq!(Do(~[~Literal(Str(~"hi"))]).eval(Env::empty()).get(), Str(~"hi"));
        assert_eq!(
            Do(~[
                ~Literal(Unit),
                ~Do(~[~Literal(Unit)]),
                ~Literal(Str(~"hi"))
            ]).eval(Env::empty()).get(),
            Str(~"hi")
        );

        assert!(Do(~[~Literal(Str(~"hi")),~Literal(Unit)]).eval(Env::empty()).is_err());
    }

    #[test]
    fn test_eval_call() {

    }
}<commit_msg>Make eval a method of Env as opposed to Expr<commit_after>#[link(name = "rusp",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/rusp")];

#[comment = "A minimal Lisp dialect for Rust."];
#[license = "ASL2"];
#[crate_type = "lib"];

// Inspired by Peter Norvig's [Lis.py](http://norvig.com/lispy.html)

use std::hashmap::*;

pub mod parse;
pub mod pprint;

/// Symbol identifier
pub type Ident = ~str;

/// Holds a typed value
pub enum Value {
    /// The unit type: `()`
    Unit,
    /// A boolean value: either `true` or `false`
    Bool(bool),
    /// An integer value
    Int(int),
    /// A floating point value
    Float(float),
    /// String value: `"<value>"`
    Str(~str),
    /// Quoted expression: `(quote <expr>)`
    Quote(~Expr),
    /// A Rust function
    Rust(~fn(params: ~[Ident], env: &Env) -> Value),
    /// Anonymous function: `(fn (<ident>*) <expr>)`
    Fn(~[Ident], ~Expr),
}

impl Eq for Value {
    fn eq(&self, other: &Value) -> bool {
        macro_rules! cmp_other(
            ($cmp_pat:pat => $cmp_expr:expr) => (
                match *other { $cmp_pat => $cmp_expr, _ => false, }
            )
        );
        match *self {
            Unit => cmp_other!(Unit => true),
            Bool(b0) => cmp_other!(Bool(b1) => b0 == b1),
            Int(i0) => cmp_other!(Int(i1) => i0 == i1),
            Float(f0) => cmp_other!(Float(f1) => f0 == f1),
            Str(ref s0) => cmp_other!(Str(ref s1) => *s0 == *s1),
            Quote(ref expr0) => cmp_other!(Quote(ref expr1) => *expr0 == *expr1),
            Rust(_) => cmp_other!(Rust(_) => fail!("Cannot test equality of Rust functions (yet?).")),
            Fn(ref params0, ref expr0) => cmp_other!(Fn(ref params1, ref expr1) => {
                (*params0 == *params1) && (*expr0 == *expr1)
            }),
        }
    }
    fn ne(&self, other: &Value) -> bool { !self.eq(other) }
}

impl Clone for Value {
    fn clone(&self) -> Value {
        match *self {
            Unit => Unit,
            Bool(b) => Bool(b),
            Int(i) => Int(i),
            Float(f) => Float(f),
            Str(ref s) => Str(s.clone()),
            Quote(ref expr) => Quote(expr.clone()),
            Rust(_) => fail!("Cannot test the equality of Rust functions (yet?)"),
            Fn(ref params, ref expr) => Fn(params.clone(), expr.clone()),
        }
    }
}

///
/// Primitive language expressions
///
#[deriving(Eq, Clone)]
pub enum Expr {
    /// Symbol reference: `<ident>`
    Symbol(Ident),
    /// Constant literal: `<val>`
    Literal(Value),
    /// Conditional expression: `(if <test> <conseq> <alt>)`
    If(~Expr, ~Expr, ~Expr),
    /// Symbol definition: `(let <ident> <expr>)`
    Let(Ident, ~Expr),
    /// Do expression: `(do <expr>+)`
    Do(~[~Expr]),
    /// Procedure call: `(<expr> <expr>+)`
    Call(~Expr, ~[~Expr]),
}

#[deriving(Eq)]
pub struct Env {
    values: HashMap<Ident, Value>,
    outer: Option<@mut Env>,
}

pub type EvalResult = Result<Value, ~str>;

impl Env {
    /// Initializes an empty environment
    pub fn empty() -> @mut Env {
        @mut Env {
            values: HashMap::new(),
            outer: None,
        }
    }

    /// Initializes a new environment with the specified values
    pub fn new(outer: @mut Env) -> @mut Env {
        @mut Env {
            values: HashMap::new(),
            outer: Some(outer),
        }
    }

    /// Defines a new identifier/value pair
    pub fn define(&mut self, ident: Ident, val: Value) -> bool {
        self.values.insert(ident, val)
    }

    /// Attempts to find a value corresponding to the supplied identifier
    pub fn find(&self, ident: &Ident) -> Option<Value> {
        match self.values.find(ident) {
            Some(val) => Some(val.clone()),
            None => self.outer.chain(|env| env.find(ident)),
        }
    }

    /// Evaluates a Rusp expression in the environment
    pub fn eval(&mut self, expr: &Expr) -> EvalResult {
        match *expr {
            Symbol(ref id) =>{
                match self.find(id) {
                    Some(val) => Ok(val),
                    None => Err(fmt!("The value of `%s` was not defined in this environment", id.to_str())),
                }
            }
            Literal(ref val) => {
                Ok(val.clone())
            }
            If(ref test, ref conseq, ref alt) => {
                do self.eval(*test).chain |val| {
                    match val {
                        Bool(true) => self.eval(*conseq),
                        Bool(false) => self.eval(*alt),
                        _ => Err(fmt!("expected boolean expression, found: %s", val.to_str())),
                    }
                }
            }
            Let(ref id, ref expr) => {
                do self.eval(*expr).chain |val| {
                    if self.define(id.clone(), val) {
                        Ok(Unit)
                    } else {
                        Err(fmt!("`%s` was already defined in this environment.", id.to_str()))
                    }
                }
            }
            Do(ref exprs) => {
                for uint::range(0, exprs.len() - 1) |i| {
                    match self.eval(exprs[i]) {
                        Ok(Unit) => (),
                        Ok(val) => return Err(fmt!("expected unit expression, found: %s", val.to_str())),
                        Err(err) => return Err(err),
                    }
                }
                self.eval(exprs[exprs.len() - 1])
            }
            Call(_,_) => fail!("Not yet implemented"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_env() {
        let outer = Env::empty();
        outer.define(~"a", Int(0));
        outer.define(~"b", Float(1.0));
        outer.define(~"c", Str(~"hi"));

        let inner = Env::new(outer);
        inner.define(~"a", Int(3));
        inner.define(~"b", Int(4));

        assert_eq!(outer.find(&~"a"), Some(Int(0)));
        assert_eq!(outer.find(&~"b"), Some(Float(1.0)));
        assert_eq!(outer.find(&~"c"), Some(Str(~"hi")));
        assert_eq!(inner.find(&~"a"), Some(Int(3)));
        assert_eq!(inner.find(&~"b"), Some(Int(4)));
        assert_eq!(inner.find(&~"c"), Some(Str(~"hi")));
    }

    #[test]
    fn test_eval_symbol() {
        let env = Env::empty();
        env.define(~"a", Int(0));
        env.define(~"b", Float(1.0));
        env.define(~"c", Str(~"hi"));

        assert_eq!(env.eval(&Symbol(~"a")).get(), Int(0));
        assert_eq!(env.eval(&Symbol(~"b")).get(), Float(1.0));
        assert_eq!(env.eval(&Symbol(~"c")).get(), Str(~"hi"));
        assert!(env.eval(&Symbol(~"d")).is_err());
    }

    #[test]
    fn test_eval_literal() {
        assert_eq!(Env::empty().eval(&Literal(Unit)).get(), Unit);
        assert_eq!(Env::empty().eval(&Literal(Int(1))).get(), Int(1));
        assert_eq!(Env::empty().eval(&Literal(Float(1.0))).get(), Float(1.0));
        assert_eq!(Env::empty().eval(&Literal(Str(~"hi"))).get(), Str(~"hi"));
        assert_eq!(Env::empty().eval(&Literal(Quote(~Literal(Unit)))).get(),
                   Quote(~Literal(Unit)));
    }

    #[test]
    fn test_eval_if() {
        fn not(test: Value) -> EvalResult {
            Env::empty().eval(&If(
                ~Literal(test),
                ~Literal(Bool(false)),
                ~Literal(Bool(true))
            ))
        }

        assert_eq!(not(Bool(true)).get(), Bool(false));
        assert_eq!(not(Bool(false)).get(), Bool(true));
        assert!(not(Str(~"hi")).is_err());
    }

    #[test]
    fn test_eval_let() {
        let env = Env::empty();
        assert!(env.eval(&Let(~"a", ~Literal(Int(0)))).is_ok());
        assert!(env.eval(&Let(~"b", ~Literal(Float(1.0)))).is_ok());
        assert!(env.eval(&Let(~"c", ~Literal(Str(~"hi")))).is_ok());

        assert_eq!(env.find(&~"a"), Some(Int(0)));
        assert_eq!(env.find(&~"b"), Some(Float(1.0)));
        assert_eq!(env.find(&~"c"), Some(Str(~"hi")));

        assert!(env.eval(&Let(~"c", ~Literal(Unit))).is_err());
    }

    #[test]
    fn test_eval_do() {
        assert_eq!(Env::empty().eval(&Do(~[~Literal(Str(~"hi"))])).get(), Str(~"hi"));
        assert_eq!(
            Env::empty().eval(&Do(~[
                ~Literal(Unit),
                ~Do(~[~Literal(Unit)]),
                ~Literal(Str(~"hi"))
            ])).get(),
            Str(~"hi")
        );

        assert!(Env::empty().eval(&Do(~[~Literal(Str(~"hi")),~Literal(Unit)])).is_err());
    }

    #[test]
    fn test_eval_call() {

    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate env_logger;
extern crate failure;
extern crate log;
extern crate pb_rs;

use clap::{App, Arg};
use pb_rs::types::FileDescriptor;
use pb_rs::ConfigBuilder;
use std::path::{Path, PathBuf};

fn run() -> Result<(), ::failure::Error> {
    let matches = App::new(crate_name!())
        .about(crate_description!())
        .author(crate_authors!("\n"))
        .version(crate_version!())
        .arg(
            Arg::with_name("OUTPUT")
                .required(false)
                .long("output")
                .short("o")
                .takes_value(true)
                .help("Generated file name, defaults to INPUT with 'rs' extension, cannot be used with --output_directory")
                .validator(|x| extension_matches(x, "rs")),
        ).arg(
            Arg::with_name("OUTPUT_DIR")
                .required(false)
                .long("output_directory")
                .short("d")
                .takes_value(true)
                .help("Output directory of generated code, cannot be used with --output"),
        ).arg(
            Arg::with_name("INCLUDE_PATH")
                .required(false)
                .long("include")
                .short("I")
                .takes_value(true)
                .help("Path to search for imported protobufs"),
        ).arg(
            Arg::with_name("SINGLE_MOD")
                .required(false)
                .long("single-mod")
                .short("s")
                .help("Omit generation of modules for each package when there is only one package"),
        ).arg(
            Arg::with_name("NO_OUTPUT")
                .required(false)
                .long("no-output")
                .short("n")
                .help(
                    "Show enums and messages in this .proto file, including those imported. \
                     No code generated",
                ),
        ).arg(
            Arg::with_name("INPUT")
                .multiple(true)
                .help("The .proto files used to generate quick-protobuf code")
                .validator(|x| extension_matches(x, "proto")),
        ).arg(
            Arg::with_name("CYCLE")
                .long("error-cycle")
                .short("e")
                .required(false)
                .help("Error out if recursive messages do not have optional fields"),
        ).arg(
            Arg::with_name("HEADERS")
                .long("no-headers")
                .short("H")
                .required(false)
                .help("Do not add module comments and module attributes in generated file"),
        ).arg(
            Arg::with_name("CUSTOMSTRUCTDERIVE")
                .long("custom_struct_derive")
                .short("C")
                .required(false)
                .help("The comma separated values to add to #[derive(...)] for every struct"),
        .get_matches();

    let in_files = path_vec(values_t!(matches, "INPUT", String));
    let include_paths = path_vec(values_t!(matches, "INCLUDE_PATH", String));
    let out_file = matches.value_of("OUTPUT").map(|o| PathBuf::from(o));
    let out_dir = matches.value_of("OUTPUT_DIR").map(|o| PathBuf::from(o));
    let custom_struct_derive: Vec<String> = matches.value_of("CUSTOMSTRUCTDERIVE").map(|o| o.split(","));

    let compiler = ConfigBuilder::new(
        &in_files,
        out_file.as_ref(),
        out_dir.as_ref(),
        &include_paths,
    )?.single_module(matches.is_present("SINGLE_MOD"))
    .no_output(matches.is_present("NO_OUTPUT"))
    .error_cycle(matches.is_present("CYCLE"))
    .headers(matches.is_present("HEADERS"));
    .custom_struct_derive(custom_struct_derive)

    FileDescriptor::run(&compiler.build()).map_err(|e| e.into())
}

fn extension_matches<P: AsRef<Path>>(path: P, expected: &str) -> std::result::Result<(), String> {
    match path.as_ref().extension() {
        Some(x) if x == expected => Ok(()),
        Some(x) => Err(format!(
            "Expected path with extension '{}', not: '{}'",
            expected,
            x.to_string_lossy()
        )),
        None => Err(format!("Expected path with extension '{}'", expected)),
    }
}

fn path_vec(maybe_vec: std::result::Result<Vec<String>, clap::Error>) -> Vec<PathBuf> {
    maybe_vec
        .unwrap_or_else(|_| Vec::new())
        .iter()
        .map(|s| s.into())
        .collect()
}

fn main() {
    env_logger::init();
    ::std::process::exit({
        if let Err(e) = run() {
            eprintln!("pb-rs fatal error");
            for e in e.iter_chain() {
                eprintln!("  - {}", e);
            }
            1
        } else {
            0
        }
    });
}
<commit_msg>Fixed compile error<commit_after>#[macro_use]
extern crate clap;
extern crate env_logger;
extern crate failure;
extern crate log;
extern crate pb_rs;

use clap::{App, Arg};
use pb_rs::types::FileDescriptor;
use pb_rs::ConfigBuilder;
use std::path::{Path, PathBuf};

fn run() -> Result<(), ::failure::Error> {
    let matches = App::new(crate_name!())
        .about(crate_description!())
        .author(crate_authors!("\n"))
        .version(crate_version!())
        .arg(
            Arg::with_name("OUTPUT")
                .required(false)
                .long("output")
                .short("o")
                .takes_value(true)
                .help("Generated file name, defaults to INPUT with 'rs' extension, cannot be used with --output_directory")
                .validator(|x| extension_matches(x, "rs")),
        ).arg(
            Arg::with_name("OUTPUT_DIR")
                .required(false)
                .long("output_directory")
                .short("d")
                .takes_value(true)
                .help("Output directory of generated code, cannot be used with --output"),
        ).arg(
            Arg::with_name("INCLUDE_PATH")
                .required(false)
                .long("include")
                .short("I")
                .takes_value(true)
                .help("Path to search for imported protobufs"),
        ).arg(
            Arg::with_name("SINGLE_MOD")
                .required(false)
                .long("single-mod")
                .short("s")
                .help("Omit generation of modules for each package when there is only one package"),
        ).arg(
            Arg::with_name("NO_OUTPUT")
                .required(false)
                .long("no-output")
                .short("n")
                .help(
                    "Show enums and messages in this .proto file, including those imported. \
                     No code generated",
                ),
        ).arg(
            Arg::with_name("INPUT")
                .multiple(true)
                .help("The .proto files used to generate quick-protobuf code")
                .validator(|x| extension_matches(x, "proto")),
        ).arg(
            Arg::with_name("CYCLE")
                .long("error-cycle")
                .short("e")
                .required(false)
                .help("Error out if recursive messages do not have optional fields"),
        ).arg(
            Arg::with_name("HEADERS")
                .long("no-headers")
                .short("H")
                .required(false)
                .help("Do not add module comments and module attributes in generated file"),
        ).arg(
            Arg::with_name("CUSTOMSTRUCTDERIVE")
                .long("custom_struct_derive")
                .short("C")
                .required(false)
                .help("The comma separated values to add to #[derive(...)] for every struct"),
        ).get_matches();

    let in_files = path_vec(values_t!(matches, "INPUT", String));
    let include_paths = path_vec(values_t!(matches, "INCLUDE_PATH", String));
    let out_file = matches.value_of("OUTPUT").map(|o| PathBuf::from(o));
    let out_dir = matches.value_of("OUTPUT_DIR").map(|o| PathBuf::from(o));
    let custom_struct_derive: Vec<String> = matches.value_of("CUSTOMSTRUCTDERIVE").unwrap_or("")
        .split(",").map(|s| s.to_string()).collect();

    let compiler = ConfigBuilder::new(
        &in_files,
        out_file.as_ref(),
        out_dir.as_ref(),
        &include_paths,
    )?.single_module(matches.is_present("SINGLE_MOD"))
    .no_output(matches.is_present("NO_OUTPUT"))
    .error_cycle(matches.is_present("CYCLE"))
    .headers(matches.is_present("HEADERS"))
    .custom_struct_derive(custom_struct_derive);

    FileDescriptor::run(&compiler.build()).map_err(|e| e.into())
}

fn extension_matches<P: AsRef<Path>>(path: P, expected: &str) -> std::result::Result<(), String> {
    match path.as_ref().extension() {
        Some(x) if x == expected => Ok(()),
        Some(x) => Err(format!(
            "Expected path with extension '{}', not: '{}'",
            expected,
            x.to_string_lossy()
        )),
        None => Err(format!("Expected path with extension '{}'", expected)),
    }
}

fn path_vec(maybe_vec: std::result::Result<Vec<String>, clap::Error>) -> Vec<PathBuf> {
    maybe_vec
        .unwrap_or_else(|_| Vec::new())
        .iter()
        .map(|s| s.into())
        .collect()
}

fn main() {
    env_logger::init();
    ::std::process::exit({
        if let Err(e) = run() {
            eprintln!("pb-rs fatal error");
            for e in e.iter_chain() {
                eprintln!("  - {}", e);
            }
            1
        } else {
            0
        }
    });
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::{Path, PathBuf};

use crate::config::Config;
use crate::parser::{Expr, Loop, Macro, Node};
use crate::CompileError;

pub(crate) struct Heritage<'a> {
    pub(crate) root: &'a Context<'a>,
    pub(crate) blocks: BlockAncestry<'a>,
}

impl Heritage<'_> {
    pub(crate) fn new<'n, S: std::hash::BuildHasher>(
        mut ctx: &'n Context<'n>,
        contexts: &'n HashMap<&'n Path, Context<'n>, S>,
    ) -> Heritage<'n> {
        let mut blocks: BlockAncestry<'n> = ctx
            .blocks
            .iter()
            .map(|(name, def)| (*name, vec![(ctx, *def)]))
            .collect();

        while let Some(ref path) = ctx.extends {
            ctx = &contexts[path.as_path()];
            for (name, def) in &ctx.blocks {
                blocks.entry(name).or_insert_with(Vec::new).push((ctx, def));
            }
        }

        Heritage { root: ctx, blocks }
    }
}

type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>;

pub(crate) struct Context<'a> {
    pub(crate) nodes: &'a [Node<'a>],
    pub(crate) extends: Option<PathBuf>,
    pub(crate) blocks: HashMap<&'a str, &'a Node<'a>>,
    pub(crate) macros: HashMap<&'a str, &'a Macro<'a>>,
    pub(crate) imports: HashMap<&'a str, PathBuf>,
}

impl Context<'_> {
    pub(crate) fn new<'n>(
        config: &Config<'_>,
        path: &Path,
        nodes: &'n [Node<'n>],
    ) -> Result<Context<'n>, CompileError> {
        let mut extends = None;
        let mut blocks = Vec::new();
        let mut macros = HashMap::new();
        let mut imports = HashMap::new();
        let mut nested = vec![nodes];
        let mut top = true;

        while let Some(nodes) = nested.pop() {
            for n in nodes {
                match n {
                    Node::Extends(Expr::StrLit(extends_path)) if top => match extends {
                        Some(_) => return Err("multiple extend blocks found".into()),
                        None => {
                            extends = Some(config.find_template(extends_path, Some(path))?);
                        }
                    },
                    Node::Macro(name, m) if top => {
                        macros.insert(*name, m);
                    }
                    Node::Import(_, import_path, scope) if top => {
                        let path = config.find_template(import_path, Some(path))?;
                        imports.insert(*scope, path);
                    }
                    Node::Extends(_) | Node::Macro(_, _) | Node::Import(_, _, _) if !top => {
                        return Err(
                            "extends, macro or import blocks not allowed below top level".into(),
                        );
                    }
                    def @ Node::BlockDef(_, _, _, _) => {
                        blocks.push(def);
                        if let Node::BlockDef(_, _, nodes, _) = def {
                            nested.push(nodes);
                        }
                    }
                    Node::Cond(branches, _) => {
                        for (_, _, nodes) in branches {
                            nested.push(nodes);
                        }
                    }
                    Node::Loop(Loop {
                        body, else_block, ..
                    }) => {
                        nested.push(body);
                        nested.push(else_block);
                    }
                    Node::Match(_, _, arms, _) => {
                        for (_, _, arm) in arms {
                            nested.push(arm);
                        }
                    }
                    _ => {}
                }
            }
            top = false;
        }

        let blocks: HashMap<_, _> = blocks
            .iter()
            .map(|def| {
                if let Node::BlockDef(_, name, _, _) = def {
                    (*name, *def)
                } else {
                    unreachable!()
                }
            })
            .collect();

        Ok(Context {
            nodes,
            extends,
            blocks,
            macros,
            imports,
        })
    }
}
<commit_msg>Remove BuildHasher from Heritage, too<commit_after>use std::collections::HashMap;
use std::path::{Path, PathBuf};

use crate::config::Config;
use crate::parser::{Expr, Loop, Macro, Node};
use crate::CompileError;

pub(crate) struct Heritage<'a> {
    pub(crate) root: &'a Context<'a>,
    pub(crate) blocks: BlockAncestry<'a>,
}

impl Heritage<'_> {
    pub(crate) fn new<'n>(
        mut ctx: &'n Context<'n>,
        contexts: &'n HashMap<&'n Path, Context<'n>>,
    ) -> Heritage<'n> {
        let mut blocks: BlockAncestry<'n> = ctx
            .blocks
            .iter()
            .map(|(name, def)| (*name, vec![(ctx, *def)]))
            .collect();

        while let Some(ref path) = ctx.extends {
            ctx = &contexts[path.as_path()];
            for (name, def) in &ctx.blocks {
                blocks.entry(name).or_insert_with(Vec::new).push((ctx, def));
            }
        }

        Heritage { root: ctx, blocks }
    }
}

type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>;

pub(crate) struct Context<'a> {
    pub(crate) nodes: &'a [Node<'a>],
    pub(crate) extends: Option<PathBuf>,
    pub(crate) blocks: HashMap<&'a str, &'a Node<'a>>,
    pub(crate) macros: HashMap<&'a str, &'a Macro<'a>>,
    pub(crate) imports: HashMap<&'a str, PathBuf>,
}

impl Context<'_> {
    pub(crate) fn new<'n>(
        config: &Config<'_>,
        path: &Path,
        nodes: &'n [Node<'n>],
    ) -> Result<Context<'n>, CompileError> {
        let mut extends = None;
        let mut blocks = Vec::new();
        let mut macros = HashMap::new();
        let mut imports = HashMap::new();
        let mut nested = vec![nodes];
        let mut top = true;

        while let Some(nodes) = nested.pop() {
            for n in nodes {
                match n {
                    Node::Extends(Expr::StrLit(extends_path)) if top => match extends {
                        Some(_) => return Err("multiple extend blocks found".into()),
                        None => {
                            extends = Some(config.find_template(extends_path, Some(path))?);
                        }
                    },
                    Node::Macro(name, m) if top => {
                        macros.insert(*name, m);
                    }
                    Node::Import(_, import_path, scope) if top => {
                        let path = config.find_template(import_path, Some(path))?;
                        imports.insert(*scope, path);
                    }
                    Node::Extends(_) | Node::Macro(_, _) | Node::Import(_, _, _) if !top => {
                        return Err(
                            "extends, macro or import blocks not allowed below top level".into(),
                        );
                    }
                    def @ Node::BlockDef(_, _, _, _) => {
                        blocks.push(def);
                        if let Node::BlockDef(_, _, nodes, _) = def {
                            nested.push(nodes);
                        }
                    }
                    Node::Cond(branches, _) => {
                        for (_, _, nodes) in branches {
                            nested.push(nodes);
                        }
                    }
                    Node::Loop(Loop {
                        body, else_block, ..
                    }) => {
                        nested.push(body);
                        nested.push(else_block);
                    }
                    Node::Match(_, _, arms, _) => {
                        for (_, _, arm) in arms {
                            nested.push(arm);
                        }
                    }
                    _ => {}
                }
            }
            top = false;
        }

        let blocks: HashMap<_, _> = blocks
            .iter()
            .map(|def| {
                if let Node::BlockDef(_, name, _, _) = def {
                    (*name, *def)
                } else {
                    unreachable!()
                }
            })
            .collect();

        Ok(Context {
            nodes,
            extends,
            blocks,
            macros,
            imports,
        })
    }
}
<|endoftext|>