<commit_before>use std::str;
use rustc_serialize::hex::FromHex;
use std::path::PathBuf;
use rustbox::{RustBox};
use rustbox::keyboard::Key;

use rex_utils;
use rex_utils::rect::Rect;
use super::RustBoxEx::{RustBoxEx, Style};
use super::input::Input;

use super::common::Canceled;

pub enum BaseInputLineActions {
    Edit(char),
    Ctrl(char),
    MoveLeft,
    MoveRight,
    DeleteWithMove,
    Ok,
    Cancel
}

pub trait InputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool;
    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool);
}

struct BaseInputLine {
    prefix: String,
    data: Vec<u8>,
    input_pos: isize,
}

impl BaseInputLine {
    fn new(prefix: String) -> BaseInputLine {
        BaseInputLine {
            prefix: prefix,
            data: vec!(),
            input_pos: 0,
        }
    }
}

impl InputLine for BaseInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::MoveLeft => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                }
            }
            BaseInputLineActions::MoveRight => {
                if self.input_pos < self.data.len() as isize {
                    self.input_pos += 1;
                }
            }
            BaseInputLineActions::Edit(ch) => {
                if ch.len_utf8() == 1 && ch.is_alphanumeric() {
                    self.data.insert(self.input_pos as usize, ch as u8);
                    self.input_pos += 1;
                } else {
                    // TODO: MAke it printable rather than alphanumeric
                }
            }
            BaseInputLineActions::DeleteWithMove => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                    self.data.remove(self.input_pos as usize);
                }
            }
            _ => return false
        };

        return true;
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        rb.print_style(area.left as usize, area.top as usize, Style::InputLine,
                 &rex_utils::string_with_repeat(' ', area.width as usize));
        rb.print_style(area.left as usize, area.top as usize, Style::InputLine,
                 &format!("{}{}", self.prefix, str::from_utf8(&self.data).unwrap()));
        if has_focus {
            rb.set_cursor(self.prefix.len() as isize + self.input_pos, (area.top as isize));
        }
    }
}

enum RadixType {
    DecRadix,
    HexRadix,
    OctRadix,
}

signal_decl!{GotoEvent(isize)}

pub struct GotoInputLine {
    base: BaseInputLine,
    radix: RadixType,
    pub on_done: GotoEvent,
    pub on_cancel: Canceled,
}

impl GotoInputLine {
    pub fn new() -> GotoInputLine {
        GotoInputLine {
            base: BaseInputLine::new("Goto (Dec):".to_string()),
            radix: RadixType::DecRadix,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_radix(&mut self, r: RadixType) {
        self.radix = r;
        self.base.prefix = match self.radix {
            RadixType::DecRadix => "Goto (Dec):".to_string(),
            RadixType::HexRadix => "Goto (Hex):".to_string(),
            RadixType::OctRadix => "Goto (Oct):".to_string(),
        }
    }

    fn do_goto(&mut self) {
        let radix = match self.radix {
            RadixType::DecRadix => 10,
            RadixType::HexRadix => 16,
            RadixType::OctRadix => 8,
        };

        let pos: Option<isize> = match str::from_utf8(&self.base.data) {
            Ok(gs) => isize::from_str_radix(&gs, radix).ok(),
            Err(_) => None
        };

        match pos {
            Some(pos) => {
                self.on_done.signal(pos)
            }
            None => {
                self.on_cancel.signal(Some(format!("Bad position!")));
            }
        };

    }
}

impl InputLine for GotoInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        if self.base.input(input, key) { return true }

        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.do_goto();
                // self.done_state = Some(true);
                true
            }
            BaseInputLineActions::Cancel => {
                self.on_cancel.signal(None);
                // self.done_state = Some(false);
                true
            }

            BaseInputLineActions::Ctrl('d') => {
                self.set_radix(RadixType::DecRadix);
                true
            }
            BaseInputLineActions::Ctrl('h') => {
                self.set_radix(RadixType::HexRadix);
                true
            }
            BaseInputLineActions::Ctrl('o') => {
                self.set_radix(RadixType::OctRadix);
                true
            }

            _ => false
        }
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        self.base.draw(rb, area, has_focus)
    }
}

enum DataType {
    AsciiStr,
    UnicodeStr,
    HexStr,
}

signal_decl!{FindEvent(Vec<u8>)}

pub struct FindInputLine {
    base: BaseInputLine,
    data_type: DataType,
    pub on_find: FindEvent,
    pub on_cancel: Canceled,
}

impl FindInputLine {
    pub fn new() -> FindInputLine {
        FindInputLine {
            base: BaseInputLine::new("Find(Ascii): ".to_string()),
            data_type: DataType::AsciiStr,
            on_find: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_search_data_type(&mut self, dt: DataType) {
        self.data_type = dt;
        self.base.prefix = match self.data_type {
            DataType::AsciiStr => "Find(Ascii): ".to_string(),
            DataType::UnicodeStr => "Find(Uni): ".to_string(),
            DataType::HexStr => "Find(Hex): ".to_string(),
        }
    }

    fn do_find(&mut self) {
        let ll = str::from_utf8(&self.base.data).unwrap().from_hex();

        let needle: Vec<u8> = match self.data_type {
            DataType::AsciiStr => self.base.data.clone().into(),
            DataType::UnicodeStr => self.base.data.clone().into(),
            DataType::HexStr => {
                match ll {
                    Ok(n) => n,
                    Err(_) => {
                        self.on_cancel.signal(Some(format!("Bad hex value")));
                        return;
                    }
                }
            }
        };

        self.on_find.signal(needle);
    }
}

impl InputLine for FindInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        if self.base.input(input, key) { return true }

        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.do_find();
                // self.done_state = Some(true);
                true
            }
            BaseInputLineActions::Cancel => {
                // self.done_state = Some(false);
                self.on_cancel.signal(None);
                true
            }

            BaseInputLineActions::Ctrl('a') => {
                self.set_search_data_type(DataType::AsciiStr);
                true
            }
            BaseInputLineActions::Ctrl('u') => {
                self.set_search_data_type(DataType::UnicodeStr);
                true
            }
            BaseInputLineActions::Ctrl('h') => {
                self.set_search_data_type(DataType::HexStr);
                true
            }

            _ => false
        }
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        self.base.draw(rb, area, has_focus)
    }
}

signal_decl!{PathEvent(PathBuf)}

pub struct PathInputLine {
    base: BaseInputLine,
    pub on_done: PathEvent,
    pub on_cancel: Canceled,
}

impl PathInputLine {
    pub fn new(prefix: String) -> PathInputLine {
        PathInputLine {
            base: BaseInputLine::new(prefix),
            on_done: Default::default(),
            on_cancel: Default::default()
        }
    }
}

impl InputLine for PathInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        if self.base.input(input, key) { return true }

        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.on_done.signal(PathBuf::from(str::from_utf8(&self.base.data).unwrap()));
                true
            }
            BaseInputLineActions::Cancel => {
                self.on_cancel.signal(None);
                true
            }
            _ => false
        }
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        self.base.draw(rb, area, has_focus)
    }
}
<commit_msg>Fix not being able to have certain chars in filenames saved/opened<commit_after>use std::str;
use rustc_serialize::hex::FromHex;
use std::path::PathBuf;
use rustbox::{RustBox};
use rustbox::keyboard::Key;

use rex_utils;
use rex_utils::rect::Rect;
use super::RustBoxEx::{RustBoxEx, Style};
use super::input::Input;

use super::common::Canceled;

pub enum BaseInputLineActions {
    Edit(char),
    Ctrl(char),
    MoveLeft,
    MoveRight,
    DeleteWithMove,
    Ok,
    Cancel
}

pub trait InputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool;
    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool);
}

struct BaseInputLine {
    prefix: String,
    data: Vec<u8>,
    input_pos: isize,
}

impl BaseInputLine {
    fn new(prefix: String) -> BaseInputLine {
        BaseInputLine {
            prefix: prefix,
            data: vec!(),
            input_pos: 0,
        }
    }
}

impl InputLine for BaseInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::MoveLeft => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                }
            }
            BaseInputLineActions::MoveRight => {
                if self.input_pos < self.data.len() as isize {
                    self.input_pos += 1;
                }
            }
            BaseInputLineActions::Edit(ch) => {
                if ch.len_utf8() == 1 {
                    self.data.insert(self.input_pos as usize, ch as u8);
                    self.input_pos += 1;
                } else {
                    // TODO: Make it printable rather than alphanumeric
                }
            }
            BaseInputLineActions::DeleteWithMove => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                    self.data.remove(self.input_pos as usize);
                }
            }
            _ => return false
        };

        return true;
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        rb.print_style(area.left as usize, area.top as usize, Style::InputLine,
                 &rex_utils::string_with_repeat(' ', area.width as usize));
        rb.print_style(area.left as usize, area.top as usize, Style::InputLine,
                 &format!("{}{}", self.prefix, str::from_utf8(&self.data).unwrap()));
        if has_focus {
            rb.set_cursor(self.prefix.len() as isize + self.input_pos, (area.top as isize));
        }
    }
}

enum RadixType {
    DecRadix,
    HexRadix,
    OctRadix,
}

signal_decl!{GotoEvent(isize)}

pub struct GotoInputLine {
    base: BaseInputLine,
    radix: RadixType,
    pub on_done: GotoEvent,
    pub on_cancel: Canceled,
}

impl GotoInputLine {
    pub fn new() -> GotoInputLine {
        GotoInputLine {
            base: BaseInputLine::new("Goto (Dec):".to_string()),
            radix: RadixType::DecRadix,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_radix(&mut self, r: RadixType) {
        self.radix = r;
        self.base.prefix = match self.radix {
            RadixType::DecRadix => "Goto (Dec):".to_string(),
            RadixType::HexRadix => "Goto (Hex):".to_string(),
            RadixType::OctRadix => "Goto (Oct):".to_string(),
        }
    }

    fn do_goto(&mut self) {
        let radix = match self.radix {
            RadixType::DecRadix => 10,
            RadixType::HexRadix => 16,
            RadixType::OctRadix => 8,
        };

        let pos: Option<isize> = match str::from_utf8(&self.base.data) {
            Ok(gs) => isize::from_str_radix(&gs, radix).ok(),
            Err(_) => None
        };

        match pos {
            Some(pos) => {
                self.on_done.signal(pos)
            }
            None => {
                self.on_cancel.signal(Some(format!("Bad position!")));
            }
        };

    }
}

impl InputLine for GotoInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        if self.base.input(input, key) { return true }

        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.do_goto();
                // self.done_state = Some(true);
                true
            }
            BaseInputLineActions::Cancel => {
                self.on_cancel.signal(None);
                // self.done_state = Some(false);
                true
            }

            BaseInputLineActions::Ctrl('d') => {
                self.set_radix(RadixType::DecRadix);
                true
            }
            BaseInputLineActions::Ctrl('h') => {
                self.set_radix(RadixType::HexRadix);
                true
            }
            BaseInputLineActions::Ctrl('o') => {
                self.set_radix(RadixType::OctRadix);
                true
            }

            _ => false
        }
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        self.base.draw(rb, area, has_focus)
    }
}

enum DataType {
    AsciiStr,
    UnicodeStr,
    HexStr,
}

signal_decl!{FindEvent(Vec<u8>)}

pub struct FindInputLine {
    base: BaseInputLine,
    data_type: DataType,
    pub on_find: FindEvent,
    pub on_cancel: Canceled,
}

impl FindInputLine {
    pub fn new() -> FindInputLine {
        FindInputLine {
            base: BaseInputLine::new("Find(Ascii): ".to_string()),
            data_type: DataType::AsciiStr,
            on_find: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_search_data_type(&mut self, dt: DataType) {
        self.data_type = dt;
        self.base.prefix = match self.data_type {
            DataType::AsciiStr => "Find(Ascii): ".to_string(),
            DataType::UnicodeStr => "Find(Uni): ".to_string(),
            DataType::HexStr => "Find(Hex): ".to_string(),
        }
    }

    fn do_find(&mut self) {
        let ll = str::from_utf8(&self.base.data).unwrap().from_hex();

        let needle: Vec<u8> = match self.data_type {
            DataType::AsciiStr => self.base.data.clone().into(),
            DataType::UnicodeStr => self.base.data.clone().into(),
            DataType::HexStr => {
                match ll {
                    Ok(n) => n,
                    Err(_) => {
                        self.on_cancel.signal(Some(format!("Bad hex value")));
                        return;
                    }
                }
            }
        };

        self.on_find.signal(needle);
    }
}

impl InputLine for FindInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        if self.base.input(input, key) { return true }

        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.do_find();
                // self.done_state = Some(true);
                true
            }
            BaseInputLineActions::Cancel => {
                // self.done_state = Some(false);
                self.on_cancel.signal(None);
                true
            }

            BaseInputLineActions::Ctrl('a') => {
                self.set_search_data_type(DataType::AsciiStr);
                true
            }
            BaseInputLineActions::Ctrl('u') => {
                self.set_search_data_type(DataType::UnicodeStr);
                true
            }
            BaseInputLineActions::Ctrl('h') => {
                self.set_search_data_type(DataType::HexStr);
                true
            }

            _ => false
        }
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        self.base.draw(rb, area, has_focus)
    }
}

signal_decl!{PathEvent(PathBuf)}

pub struct PathInputLine {
    base: BaseInputLine,
    pub on_done: PathEvent,
    pub on_cancel: Canceled,
}

impl PathInputLine {
    pub fn new(prefix: String) -> PathInputLine {
        PathInputLine {
            base: BaseInputLine::new(prefix),
            on_done: Default::default(),
            on_cancel: Default::default()
        }
    }
}

impl InputLine for PathInputLine {
    fn input(&mut self, input: &Input, key: Key) -> bool {
        if self.base.input(input, key) { return true }

        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.on_done.signal(PathBuf::from(str::from_utf8(&self.base.data).unwrap()));
                true
            }
            BaseInputLineActions::Cancel => {
                self.on_cancel.signal(None);
                true
            }
            _ => false
        }
    }

    fn draw(&mut self, rb: &RustBox, area: Rect<isize>, has_focus: bool) {
        self.base.draw(rb, area, has_focus)
    }
}
<|endoftext|>


<commit_before><commit_msg>[hal] Add debug printing to `Adapter`<commit_after><|endoftext|>


<commit_before>// revisions: rpass cfail

trait Tr {
    type Arr;

    const C: usize = 0;
}

impl Tr for str {
    #[cfg(rpass)]
    type Arr = [u8; 8];
    #[cfg(cfail)]
    type Arr = [u8; Self::C];
    //[cfail]~^ ERROR cycle detected when const-evaluating
}

fn main() {}
<commit_msg>Update incremental tests<commit_after>// revisions: rpass cfail

trait Tr {
    type Arr;

    const C: usize = 0;
}

impl Tr for str {
    #[cfg(rpass)]
    type Arr = [u8; 8];
    #[cfg(cfail)]
    type Arr = [u8; Self::C];
    //[cfail]~^ ERROR cycle detected when simplifying constant
}

fn main() {}
<|endoftext|>


<commit_before><commit_msg>wip : prepare scrollbar<commit_after><|endoftext|>


<commit_before>use ::anyhow::Result;
use ::async_std::net::{TcpListener, TcpStream};
use ::async_std::prelude::*;
use ::async_std::task;

use ::pueue::message::{create_success_message, Message};
use ::pueue::protocol::*;

#[async_std::test]
async fn test_single_huge_payload() -> Result<()> {
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let addr = listener.local_addr()?;

    // The message that should be sent
    let payload = "a".repeat(100_000);
    let message = create_success_message(payload);
    let original_bytes = serde_json::to_string(&message)
        .expect("Failed to serialize message.")
        .into_bytes();

    // Spawn a sub thread that:
    // 1. Accepts a new connection
    // 2. Reads a message
    // 3. Sends the same message back
    task::spawn(async move {
        let mut incoming = listener.incoming();
        let mut socket = incoming.next().await.unwrap().unwrap();
        let message_bytes = receive_bytes(&mut socket).await.unwrap();

        let message = String::from_utf8(message_bytes).unwrap();
        let message: Message = serde_json::from_str(&message).unwrap();

        send_message(&message, &mut socket).await.unwrap();
    });

    let mut client = TcpStream::connect(&addr).await?;
    // Create a client that sends a message and instantly receives it
    send_message(&message, &mut client).await?;
    let response_bytes = receive_bytes(&mut client).await?;
    let message = String::from_utf8(response_bytes.clone())?;
    let _message: Message = serde_json::from_str(&message)?;

    assert_eq!(response_bytes, original_bytes);

    Ok(())
}
<commit_msg>Adjust tests for new bincode serialization<commit_after>use ::anyhow::Result;
use ::async_std::net::{TcpListener, TcpStream};
use ::async_std::prelude::*;
use ::async_std::task;

use ::pueue::message::{create_success_message, Message};
use ::pueue::protocol::*;

#[async_std::test]
async fn test_single_huge_payload() -> Result<()> {
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let addr = listener.local_addr()?;

    // The message that should be sent
    let payload = "a".repeat(100_000);
    let message = create_success_message(payload);
    let original_bytes = bincode::serialize(&message).expect("Failed to serialize message.");

    // Spawn a sub thread that:
    // 1. Accepts a new connection
    // 2. Reads a message
    // 3. Sends the same message back
    task::spawn(async move {
        let mut incoming = listener.incoming();
        let mut socket = incoming.next().await.unwrap().unwrap();
        let message_bytes = receive_bytes(&mut socket).await.unwrap();

        let message: Message = bincode::deserialize(&message_bytes).unwrap();

        send_message(message, &mut socket).await.unwrap();
    });

    let mut client = TcpStream::connect(&addr).await?;
    // Create a client that sends a message and instantly receives it
    send_message(message, &mut client).await?;
    let response_bytes = receive_bytes(&mut client).await?;
    let _message: Message = bincode::deserialize(&response_bytes)?;

    assert_eq!(response_bytes, original_bytes);

    Ok(())
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::collections::hash_map::{HashMap, Entry};
use std::borrow::BorrowMut;
use gl;
use gl::types::*;
use context::{AContext, ContextOf};
use renderbuffer::{Renderbuffer, RenderbufferTarget};
use texture::{Texture, TextureType, ImageTargetType,
              Texture2d, Tx2dImageTarget};
use types::{BufferBits, GLError, GLFramebufferError};

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub unsafe fn from_gl(id: GLuint) -> Self {
        Framebuffer { gl_id: id }
    }

    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

enum BuilderAttachment<'a> {
    Texture2d(&'a mut Texture2d, i32),
    Renderbuffer(&'a mut Renderbuffer)
}

pub struct FramebufferBuilder<'a, C>
    where C: FramebufferContext
{
    gl: C,
    attachments: HashMap<FramebufferAttachment, BuilderAttachment<'a>>
}

impl<'a, C> FramebufferBuilder<'a, C>
    where C: FramebufferContext
{
    fn new(gl: C) -> Self {
        FramebufferBuilder {
            gl: gl,
            attachments: HashMap::new()
        }
    }

    pub fn texture_2d(mut self,
                      attachment: FramebufferAttachment,
                      texture: &'a mut Texture2d,
                      level: i32)
        -> Self
    {
        let attached = BuilderAttachment::Texture2d(texture, level);
        match self.attachments.entry(attachment) {
            Entry::Occupied(mut e) => { e.insert(attached); },
            Entry::Vacant(e) => { e.insert(attached); }
        };

        self
    }

    pub fn renderbuffer(mut self,
                        attachment: FramebufferAttachment,
                        renderbuffer: &'a mut Renderbuffer)
        -> Self
    {
        let attached = BuilderAttachment::Renderbuffer(renderbuffer);
        match self.attachments.entry(attachment) {
            Entry::Occupied(mut e) => { e.insert(attached); },
            Entry::Vacant(e) => { e.insert(attached); }
        };

        self
    }

    pub fn try_unwrap(self) -> Result<Framebuffer, GLError> {
        let gl = self.gl;
        let mut fbo = unsafe { gl.gen_framebuffer() };
        let fbo_status = {
            let (mut gl_fbo, gl) = gl.bind_framebuffer(&mut fbo);

            for (attachment, attached) in self.attachments.into_iter() {
                match attached {
                    BuilderAttachment::Texture2d(texture, level) => {
                        gl.framebuffer_texture2d(&mut gl_fbo,
                                                 attachment,
                                                 Tx2dImageTarget::Texture2d,
                                                 texture,
                                                 level);
                    },
                    BuilderAttachment::Renderbuffer(renderbuffer) => {
                        gl.framebuffer_renderbuffer(&mut gl_fbo,
                                                    attachment,
                                                    renderbuffer);
                    }
                }
            }

            gl.check_framebuffer_status(&mut gl_fbo)
        };

        match fbo_status {
            Some(err) => { Err(err.into()) },
            None => { Ok(fbo) }
        }
    }

    pub fn unwrap(self) -> Framebuffer {
        self.try_unwrap().unwrap()
    }
}

pub trait ContextFramebufferBuilderExt: FramebufferContext + Sized {
    fn build_framebuffer<'a>(self) -> FramebufferBuilder<'a, Self>;
}

impl<'b, C: 'b> ContextFramebufferBuilderExt for &'b mut C
    where &'b mut C: FramebufferContext
{
    fn build_framebuffer<'a>(self) -> FramebufferBuilder<'a, &'b mut C> {
        FramebufferBuilder::new(self)
    }
}

pub unsafe trait ContextFramebufferExt {
    unsafe fn gen_framebuffer(&self) -> Framebuffer {
        let mut id : GLuint = 0;

        gl::GenFramebuffers(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Framebuffer {
            gl_id: id
        }
    }

    fn check_framebuffer_status(&self, gl_fbo: &FramebufferBinding)
        -> Option<GLFramebufferError>
    {
        unsafe {
            match gl::CheckFramebufferStatus(gl_fbo.target().gl_enum()) {
                gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => {
                    Some(GLFramebufferError::IncompleteAttachment)
                },
                // gl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => {
                //     Some(GLFramebufferError::IncompleteDimensions)
                // },
                gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
                    Some(GLFramebufferError::IncompleteMissingAttachment)
                },
                gl::FRAMEBUFFER_UNSUPPORTED => {
                    Some(GLFramebufferError::Unsupported)
                },
                _ => { None }
            }
        }
    }

    fn framebuffer_renderbuffer(&self,
                                gl_fbo: &mut FramebufferBinding,
                                attachment: FramebufferAttachment,
                                renderbuffer: &mut Renderbuffer)
    {
        let renderbuffer_target = RenderbufferTarget::Renderbuffer;
        unsafe {
            gl::FramebufferRenderbuffer(gl_fbo.target().gl_enum(),
                                        attachment.gl_enum(),
                                        renderbuffer_target.gl_enum(),
                                        renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not a valid attachment point, or `renderbuffer` is not `GL_RENDERBUFFER` and `renderbuffer` is not 0",
                GLError::InvalidOperation => "Framebuffer 0 is bound, or `renderbuffer` is neither 0 nor the name of an existing renderbuffer object",
                _ => "Unknown error"
            }
        }
    }

    fn framebuffer_texture2d<I, T>(&self,
                                   gl_fbo: &mut FramebufferBinding,
                                   attachment: FramebufferAttachment,
                                   tex_target: I,
                                   texture: &mut Texture<T>,
                                   level: i32)
        where I: Into<T::ImageTargetType>,
              T: TextureType,
    {
        debug_assert!(level == 0);

        unsafe {
            gl::FramebufferTexture2D(gl_fbo.target().gl_enum(),
                                     attachment.gl_enum(),
                                     tex_target.into().gl_enum(),
                                     texture.gl_id(),
                                     level as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not an accepted attachment point, or `textarget` is not an accepted texture target and texture is not 0",
                GLError::InvalidValue => "`level` is not 0 and `texture` is not 0",
                GLError::InvalidOperation => "Framebuffer object 0 is bound, `texture` is neither 0 nor the name of an existing texture object, or `textarget` is not a valid target for `texture`",
                _ => "Unknown error"
            }
        }
    }

    // TODO: Think about this function signature harder.
    // Should this require a &mut FramebufferBinding, to prevent a
    // no-op glClear()?
    fn clear(&self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }
}

unsafe impl<B, F, P, R, T> ContextFramebufferExt for ContextOf<B, F, P, R, T> {

}

unsafe impl<'a, B, F, P, R, T> ContextFramebufferExt
    for &'a mut ContextOf<B, F, P, R, T>
{

}

gl_enum! {
    pub gl_enum FramebufferTarget {
        Framebuffer as FRAMEBUFFER = gl::FRAMEBUFFER
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub trait FramebufferContext: AContext {
    type Rest: AContext;

    fn bind_framebuffer<'a>(self, fbo: &'a mut Framebuffer)
        -> (FramebufferBinding<'a>, Self::Rest);
}

impl<B, F, P, R, T> FramebufferContext for ContextOf<B, F, P, R, T>
    where F: BorrowMut<FramebufferBinder>
{
    type Rest = ContextOf<B, (), P, R, T>;

    fn bind_framebuffer<'a>(self, fbo: &'a mut Framebuffer)
        -> (FramebufferBinding<'a>, Self::Rest)
    {
        let (mut fbo_binder, rest) = self.split_framebuffer();
        (fbo_binder.borrow_mut().bind(fbo), rest)
    }
}

impl<'b, B, F, P, R, T> FramebufferContext for &'b mut ContextOf<B, F, P, R, T>
    where F: BorrowMut<FramebufferBinder>
{
    type Rest = ContextOf<&'b mut B, (), &'b mut P, &'b mut R, &'b mut T>;

    fn bind_framebuffer<'a>(self, fbo: &'a mut Framebuffer)
        -> (FramebufferBinding<'a>, Self::Rest)
    {
        let gl = self.mut_into();
        let (framebuffer_binder, rest): (&mut F, _) = gl.split_framebuffer();
        (framebuffer_binder.borrow_mut().bind(fbo), rest)
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> FramebufferTarget {
        FramebufferTarget::Framebuffer
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub unsafe fn current_binding(&mut self) -> FramebufferBinding {
        FramebufferBinding { phantom: PhantomData }
    }

    pub fn bind<'a>(&mut self, fbo: &'a mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target().gl_enum(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<commit_msg>Clean up the `framebuffer` module<commit_after>use std::marker::PhantomData;
use std::collections::hash_map::{HashMap, Entry};
use std::borrow::BorrowMut;
use gl;
use gl::types::*;
use context::{AContext, ContextOf};
use renderbuffer::{Renderbuffer, RenderbufferTarget};
use texture::{Texture, TextureType, ImageTargetType,
              Texture2d, Tx2dImageTarget};
use types::{BufferBits, GLError, GLFramebufferError};

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub unsafe fn from_gl(id: GLuint) -> Self {
        Framebuffer { gl_id: id }
    }

    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

pub unsafe trait ContextFramebufferExt {
    unsafe fn gen_framebuffer(&self) -> Framebuffer {
        let mut id : GLuint = 0;

        gl::GenFramebuffers(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Framebuffer {
            gl_id: id
        }
    }

    fn check_framebuffer_status(&self, gl_fbo: &FramebufferBinding)
        -> Option<GLFramebufferError>
    {
        unsafe {
            match gl::CheckFramebufferStatus(gl_fbo.target().gl_enum()) {
                gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => {
                    Some(GLFramebufferError::IncompleteAttachment)
                },
                // gl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => {
                //     Some(GLFramebufferError::IncompleteDimensions)
                // },
                gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
                    Some(GLFramebufferError::IncompleteMissingAttachment)
                },
                gl::FRAMEBUFFER_UNSUPPORTED => {
                    Some(GLFramebufferError::Unsupported)
                },
                _ => { None }
            }
        }
    }

    fn framebuffer_renderbuffer(&self,
                                gl_fbo: &mut FramebufferBinding,
                                attachment: FramebufferAttachment,
                                renderbuffer: &mut Renderbuffer)
    {
        let renderbuffer_target = RenderbufferTarget::Renderbuffer;
        unsafe {
            gl::FramebufferRenderbuffer(gl_fbo.target().gl_enum(),
                                        attachment.gl_enum(),
                                        renderbuffer_target.gl_enum(),
                                        renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not a valid attachment point, or `renderbuffer` is not `GL_RENDERBUFFER` and `renderbuffer` is not 0",
                GLError::InvalidOperation => "Framebuffer 0 is bound, or `renderbuffer` is neither 0 nor the name of an existing renderbuffer object",
                _ => "Unknown error"
            }
        }
    }

    fn framebuffer_texture_2d<I, T>(&self,
                                    gl_fbo: &mut FramebufferBinding,
                                    attachment: FramebufferAttachment,
                                    tex_target: I,
                                    texture: &mut Texture<T>,
                                    level: i32)
        where I: Into<T::ImageTargetType>,
              T: TextureType,
    {
        debug_assert!(level == 0);

        unsafe {
            gl::FramebufferTexture2D(gl_fbo.target().gl_enum(),
                                     attachment.gl_enum(),
                                     tex_target.into().gl_enum(),
                                     texture.gl_id(),
                                     level as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not an accepted attachment point, or `textarget` is not an accepted texture target and texture is not 0",
                GLError::InvalidValue => "`level` is not 0 and `texture` is not 0",
                GLError::InvalidOperation => "Framebuffer object 0 is bound, `texture` is neither 0 nor the name of an existing texture object, or `textarget` is not a valid target for `texture`",
                _ => "Unknown error"
            }
        }
    }

    // TODO: Think about this function signature harder (and all draw calls).
    // Should this require a &mut FramebufferBinding, to prevent a
    // no-op glClear(), and for (future) multi-threaded safety?
    fn clear(&self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }
}

unsafe impl<B, F, P, R, T> ContextFramebufferExt for ContextOf<B, F, P, R, T> {

}

unsafe impl<'a, B, F, P, R, T> ContextFramebufferExt
    for &'a mut ContextOf<B, F, P, R, T>
{

}

enum BuilderAttachment<'a> {
    Texture2d(&'a mut Texture2d, i32),
    Renderbuffer(&'a mut Renderbuffer)
}

pub struct FramebufferBuilder<'a, C>
    where C: FramebufferContext
{
    gl: C,
    attachments: HashMap<FramebufferAttachment, BuilderAttachment<'a>>
}

impl<'a, C> FramebufferBuilder<'a, C>
    where C: FramebufferContext
{
    fn new(gl: C) -> Self {
        FramebufferBuilder {
            gl: gl,
            attachments: HashMap::new()
        }
    }

    pub fn texture_2d(mut self,
                      attachment: FramebufferAttachment,
                      texture: &'a mut Texture2d,
                      level: i32)
        -> Self
    {
        let attached = BuilderAttachment::Texture2d(texture, level);
        match self.attachments.entry(attachment) {
            Entry::Occupied(mut e) => { e.insert(attached); },
            Entry::Vacant(e) => { e.insert(attached); }
        };

        self
    }

    pub fn renderbuffer(mut self,
                        attachment: FramebufferAttachment,
                        renderbuffer: &'a mut Renderbuffer)
        -> Self
    {
        let attached = BuilderAttachment::Renderbuffer(renderbuffer);
        match self.attachments.entry(attachment) {
            Entry::Occupied(mut e) => { e.insert(attached); },
            Entry::Vacant(e) => { e.insert(attached); }
        };

        self
    }

    pub fn try_unwrap(self) -> Result<Framebuffer, GLError> {
        let gl = self.gl;
        let mut fbo = unsafe { gl.gen_framebuffer() };
        let fbo_status = {
            let (mut gl_fbo, gl) = gl.bind_framebuffer(&mut fbo);

            for (attachment, attached) in self.attachments.into_iter() {
                match attached {
                    BuilderAttachment::Texture2d(texture, level) => {
                        gl.framebuffer_texture_2d(&mut gl_fbo,
                                                  attachment,
                                                  Tx2dImageTarget::Texture2d,
                                                  texture,
                                                  level);
                    },
                    BuilderAttachment::Renderbuffer(renderbuffer) => {
                        gl.framebuffer_renderbuffer(&mut gl_fbo,
                                                    attachment,
                                                    renderbuffer);
                    }
                }
            }

            gl.check_framebuffer_status(&mut gl_fbo)
        };

        match fbo_status {
            Some(err) => { Err(err.into()) },
            None => { Ok(fbo) }
        }
    }

    pub fn unwrap(self) -> Framebuffer {
        self.try_unwrap().unwrap()
    }
}

pub trait ContextFramebufferBuilderExt: FramebufferContext + Sized {
    fn build_framebuffer<'a>(self) -> FramebufferBuilder<'a, Self>;
}

impl<'b, C: 'b> ContextFramebufferBuilderExt for &'b mut C
    where &'b mut C: FramebufferContext
{
    fn build_framebuffer<'a>(self) -> FramebufferBuilder<'a, &'b mut C> {
        FramebufferBuilder::new(self)
    }
}

gl_enum! {
    pub gl_enum FramebufferTarget {
        Framebuffer as FRAMEBUFFER = gl::FRAMEBUFFER
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub trait FramebufferContext: AContext {
    type Rest: AContext;

    fn bind_framebuffer<'a>(self, fbo: &'a mut Framebuffer)
        -> (FramebufferBinding<'a>, Self::Rest);
}

impl<B, F, P, R, T> FramebufferContext for ContextOf<B, F, P, R, T>
    where F: BorrowMut<FramebufferBinder>
{
    type Rest = ContextOf<B, (), P, R, T>;

    fn bind_framebuffer<'a>(self, fbo: &'a mut Framebuffer)
        -> (FramebufferBinding<'a>, Self::Rest)
    {
        let (mut fbo_binder, rest) = self.split_framebuffer();
        (fbo_binder.borrow_mut().bind(fbo), rest)
    }
}

impl<'b, B, F, P, R, T> FramebufferContext for &'b mut ContextOf<B, F, P, R, T>
    where F: BorrowMut<FramebufferBinder>
{
    type Rest = ContextOf<&'b mut B, (), &'b mut P, &'b mut R, &'b mut T>;

    fn bind_framebuffer<'a>(self, fbo: &'a mut Framebuffer)
        -> (FramebufferBinding<'a>, Self::Rest)
    {
        let gl = self.mut_into();
        let (framebuffer_binder, rest): (&mut F, _) = gl.split_framebuffer();
        (framebuffer_binder.borrow_mut().bind(fbo), rest)
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> FramebufferTarget {
        FramebufferTarget::Framebuffer
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub unsafe fn current_binding(&mut self) -> FramebufferBinding {
        FramebufferBinding { phantom: PhantomData }
    }

    pub fn bind<'a>(&mut self, fbo: &'a mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target().gl_enum(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use renderbuffer::Renderbuffer;
use texture::{Texture, TextureType, ImageTargetType};
use types::{BufferBits, GLError};

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub unsafe fn from_gl(id: GLuint) -> Self {
        Framebuffer { gl_id: id }
    }

    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_framebuffer(&self) -> Framebuffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenFramebuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Framebuffer {
                gl_id: id
            }
        }
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> GLenum {
        gl::FRAMEBUFFER
    }

    pub fn renderbuffer(&mut self,
                        attachment: FramebufferAttachment,
                        renderbuffer: &mut Renderbuffer)
    {
        unsafe {
            gl::FramebufferRenderbuffer(self.target(),
                                        attachment.gl_enum(),
                                        gl::RENDERBUFFER,
                                        renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not a valid attachment point, or `renderbuffer` is not `GL_RENDERBUFFER` and `renderbuffer` is not 0",
                GLError::InvalidOperation => "Framebuffer 0 is bound, or `renderbuffer` is neither 0 nor the name of an existing renderbuffer object",
                _ => "Unknown error"
            }
        }
    }

    pub fn texture2d<T: TextureType>(&mut self,
                                     attachment: FramebufferAttachment,
                                     tex_target: T::ImageTargetType,
                                     texture: &mut Texture<T>,
                                     level: i32)
    {
        debug_assert!(level == 0);

        unsafe {
            gl::FramebufferTexture2D(self.target(),
                                     attachment.gl_enum(),
                                     tex_target.gl_enum(),
                                     texture.gl_id(),
                                     level as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not an accepted attachment point, or `textarget` is not an accepted texture target and texture is not 0",
                GLError::InvalidValue => "`level` is not 0 and `texture` is not 0",
                GLError::InvalidOperation => "Framebuffer object 0 is bound, `texture` is neither 0 nor the name of an existing texture object, or `textarget` is not a valid target for `texture`",
                _ => "Unknown error"
            }
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub unsafe fn current_binding<'a>(&'a mut self) -> FramebufferBinding<'a> {
        FramebufferBinding { phantom: PhantomData }
    }

    pub fn bind<'a>(&'a mut self, fbo: &mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<commit_msg>Rename `FramebufferBinder.texture2d` to `texture_2d`<commit_after>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use renderbuffer::Renderbuffer;
use texture::{Texture, TextureType, ImageTargetType};
use types::{BufferBits, GLError};

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub unsafe fn from_gl(id: GLuint) -> Self {
        Framebuffer { gl_id: id }
    }

    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_framebuffer(&self) -> Framebuffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenFramebuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Framebuffer {
                gl_id: id
            }
        }
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> GLenum {
        gl::FRAMEBUFFER
    }

    pub fn renderbuffer(&mut self,
                        attachment: FramebufferAttachment,
                        renderbuffer: &mut Renderbuffer)
    {
        unsafe {
            gl::FramebufferRenderbuffer(self.target(),
                                        attachment.gl_enum(),
                                        gl::RENDERBUFFER,
                                        renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not a valid attachment point, or `renderbuffer` is not `GL_RENDERBUFFER` and `renderbuffer` is not 0",
                GLError::InvalidOperation => "Framebuffer 0 is bound, or `renderbuffer` is neither 0 nor the name of an existing renderbuffer object",
                _ => "Unknown error"
            }
        }
    }

    pub fn texture_2d<T: TextureType>(&mut self,
                                      attachment: FramebufferAttachment,
                                      tex_target: T::ImageTargetType,
                                      texture: &mut Texture<T>,
                                      level: i32)
    {
        debug_assert!(level == 0);

        unsafe {
            gl::FramebufferTexture2D(self.target(),
                                     attachment.gl_enum(),
                                     tex_target.gl_enum(),
                                     texture.gl_id(),
                                     level as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not an accepted attachment point, or `textarget` is not an accepted texture target and texture is not 0",
                GLError::InvalidValue => "`level` is not 0 and `texture` is not 0",
                GLError::InvalidOperation => "Framebuffer object 0 is bound, `texture` is neither 0 nor the name of an existing texture object, or `textarget` is not a valid target for `texture`",
                _ => "Unknown error"
            }
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub unsafe fn current_binding<'a>(&'a mut self) -> FramebufferBinding<'a> {
        FramebufferBinding { phantom: PhantomData }
    }

    pub fn bind<'a>(&'a mut self, fbo: &mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<|endoftext|>


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

//! Helpers for reading directory structures from the local filesystem.

use std::sync;
use std::os::{last_os_error};
use std::io::{TypeDirectory};
use std::io::fs::{lstat};

use std::c_str::CString;
use libc::funcs::posix88::dirent;
use libc::types::common::posix88::{DIR,dirent_t};
use libc::types::os::arch::c95::c_char;
use libc::{c_int};

pub struct DirIterator {
  fd: *mut DIR,
}

impl DirIterator {
  pub fn new(path: Path) -> Result<DirIterator, String> {
    let fd = path.with_c_str(|c_str| unsafe { dirent::opendir(c_str) });

    if fd as int > 0 { Ok(DirIterator{fd:fd}) }
    else { Err(last_os_error()) }
  }

  fn read(&mut self) -> String {
    extern {
      fn rust_dirent_t_size() -> c_int;
      fn rust_list_dir_val(ptr: *mut dirent_t) -> *const c_char;
    }

    let mut entry_ptr = 0 as *mut dirent_t;

    let size = unsafe { rust_dirent_t_size() };
    let mut buf = Vec::<u8>::with_capacity(size as uint);
    let buf_ptr = buf.as_mut_ptr() as *mut dirent_t;

    let retval = unsafe { dirent::readdir_r(self.fd, buf_ptr, &mut entry_ptr) };

    if retval == 0 && !entry_ptr.is_null() {
      let cstr = unsafe { CString::new(rust_list_dir_val(entry_ptr), false) };
      cstr.as_str().expect("Path not UTF8.").into_string()
    } else { "".to_string() }

  }

}

impl Drop for DirIterator {
  fn drop(&mut self) {
    unsafe {
      dirent::closedir(self.fd)
    };
  }
}

impl Iterator<String> for DirIterator {
  fn next(&mut self) -> Option<String> {
    let name = self.read();
    if name.len() == 0 { None }
    else { Some(name) }
  }
}

pub trait PathHandler<D> {
  fn handle_path(&mut self, D, Path) -> Option<D>;
}

pub fn iterate_recursively<P: Send + Clone, W: PathHandler<P> + Send + Clone>
  (root: (Path, P), worker: &mut W)
{
  let threads = 10;

  let queue = sync::Arc::new(sync::Mutex::new(vec!(root)));
  let in_progress = sync::Arc::new(sync::Mutex::new(0u));
  let done = sync::Arc::new(sync::Mutex::new(0u));

  for _ in range(0u, threads) {
    let t_in_progress = in_progress.clone();
    let t_queue = queue.clone();
    let t_done = done.clone();
    let t_worker_imm = worker.clone();

    spawn(proc() {
      let mut t_worker = t_worker_imm;

      loop {
        let mut next = None;
        let task_count = {
          let mut guarded_tasks = t_in_progress.lock();
          let mut guarded_queue = t_queue.lock();
          if guarded_queue.len() > 0 {
            next = guarded_queue.pop();
            *guarded_tasks += 1;
          }
          *guarded_tasks
        };

        match next {
          None => {
            if task_count == 0 {
              break;  // Stop when all workers are idle
            }
          },
          Some((root_, payload)) => {
            let mut root = root_;
            let res = DirIterator::new(root.clone());
            if res.is_ok() {
              let mut it = res.unwrap();
              for file in it {
                if file != ".".into_string() && file != "..".into_string() {
                  let rel_path = Path::new(file);
                  root.push(rel_path);
                  let dir_opt = t_worker.handle_path(payload.clone(), root.clone());
                  if dir_opt.is_some() {
                    let mut guarded_queue = t_queue.lock();
                    guarded_queue.push((root.clone(), dir_opt.unwrap()));
                  }
                  root.pop();
                }
              }
            }

            // Tell waiting threads that will not produce more
            {
              let mut guarded_tasks = t_in_progress.lock();
              *guarded_tasks -= 1;
            }
          }
        }
      }

      // Loop is over, thread is stopping
      {
        let mut guarded_tasks_done = t_done.lock();
        *guarded_tasks_done += 1;
        guarded_tasks_done.cond.signal();
      }
    });
  }

  // Wait for threads to complete
  {
    let guarded_done = done.lock();
    while *guarded_done < threads {
      guarded_done.cond.wait();
    }
  }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
  fn clone(&self) -> PrintPathHandler { PrintPathHandler }
}

impl PathHandler<()> for PrintPathHandler {
  fn handle_path(&mut self, _: (), path: Path) -> Option<()> {
    let filename_opt = path.filename_str();
    println!("{}", path.display());
    match filename_opt {
      Some(".") | Some("..") | None => None,
      Some(_) =>
      match lstat(&path) {
        Ok(ref st) if st.kind == TypeDirectory => Some(()),
        _ => None,
      }
    }
  }
}
<commit_msg>Use TaskPool to simplify listdir.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers for reading directory structures from the local filesystem.

use std::sync;
use std::sync::atomic;
use std::os::{last_os_error};
use std::io::{TypeDirectory};
use std::io::fs::{lstat};
use std::io::timer;
use std::time;

use std::c_str::CString;
use libc::funcs::posix88::dirent;
use libc::types::common::posix88::{DIR,dirent_t};
use libc::types::os::arch::c95::c_char;
use libc::{c_int};

pub struct DirIterator {
  fd: *mut DIR,
}

impl DirIterator {
  pub fn new(path: Path) -> Result<DirIterator, String> {
    let fd = path.with_c_str(|c_str| unsafe { dirent::opendir(c_str) });

    if fd as int > 0 { Ok(DirIterator{fd:fd}) }
    else { Err(last_os_error()) }
  }

  fn read(&mut self) -> String {
    extern {
      fn rust_dirent_t_size() -> c_int;
      fn rust_list_dir_val(ptr: *mut dirent_t) -> *const c_char;
    }

    let mut entry_ptr = 0 as *mut dirent_t;

    let size = unsafe { rust_dirent_t_size() };
    let mut buf = Vec::<u8>::with_capacity(size as uint);
    let buf_ptr = buf.as_mut_ptr() as *mut dirent_t;

    let retval = unsafe { dirent::readdir_r(self.fd, buf_ptr, &mut entry_ptr) };

    if retval == 0 && !entry_ptr.is_null() {
      let cstr = unsafe { CString::new(rust_list_dir_val(entry_ptr), false) };
      cstr.as_str().expect("Path not UTF8.").into_string()
    } else { "".to_string() }

  }

}

impl Drop for DirIterator {
  fn drop(&mut self) {
    unsafe {
      dirent::closedir(self.fd)
    };
  }
}

impl Iterator<String> for DirIterator {
  fn next(&mut self) -> Option<String> {
    let name = self.read();
    if name.len() == 0 { None }
    else { Some(name) }
  }
}

pub trait PathHandler<D> {
  fn handle_path(&mut self, D, Path) -> Option<D>;
}

pub fn iterate_recursively<P: Send + Clone, W: PathHandler<P> + Send + Clone>
  (root: (Path, P), worker: &mut W)
{
  let threads = 5;
  let (push_ch, work_ch) = sync_channel(threads);
  let mut pool = sync::TaskPool::new(threads, || proc(_){()});

  let seq_cst = atomic::SeqCst;  // Sequential consistency access mode
  let running_workers = sync::Arc::new(atomic::AtomicInt::new(0));

  let mut timer = timer::Timer::new().unwrap();
  let timeout = timer.periodic(time::Duration::microseconds(100));

  // Insert the root dir into the queue:
  push_ch.send(root);

  // Master thread:
  loop {
    select! {
      () = timeout.recv() => {},  // Queue is empty: fall-through to see if we are done.
      (root, payload) = work_ch.recv() => {
        let t_worker = worker.clone();
        let t_push_ch = push_ch.clone();

        // Count the pool thread as active:
        let t_running_workers = running_workers.clone();
        t_running_workers.fetch_add(1, seq_cst);

        // Execute the task in a pool thread:
        pool.execute(proc(&()) {
          let mut root = root;
          let mut t_worker = t_worker;
          let res = DirIterator::new(root.clone());
          if res.is_ok() {
            let mut it = res.unwrap();
            for file in it {
              if file != ".".into_string() && file != "..".into_string() {
                let rel_path = Path::new(file);
                root.push(rel_path);
                let dir_opt = t_worker.handle_path(payload.clone(), root.clone());
                if dir_opt.is_some() {
                  t_push_ch.send((root.clone(), dir_opt.unwrap()));
                }
                root.pop();
              }
            }
          }

          // Count this pool thread as idle:
          t_running_workers.fetch_sub(1, seq_cst);
        });
      }
    }
    // We are done when no workers are active (i.e. all tasks are done):
    if running_workers.load(seq_cst) == 0 { break }
  }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
  fn clone(&self) -> PrintPathHandler { PrintPathHandler }
}

impl PathHandler<()> for PrintPathHandler {
  fn handle_path(&mut self, _: (), path: Path) -> Option<()> {
    let filename_opt = path.filename_str();
    println!("{}", path.display());
    match filename_opt {
      Some(".") | Some("..") | None => None,
      Some(_) =>
      match lstat(&path) {
        Ok(ref st) if st.kind == TypeDirectory => Some(()),
        _ => None,
      }
    }
  }
}
<|endoftext|>


<commit_before>use std;
use std::convert::From;
use std::io::{Read, Write};
use std::num::wrapping::OverflowingOps;

#[derive(Debug, Clone, PartialEq)]
pub enum Opcode {
    Add(u8),
    Sub(u8),
    Left(usize),
    Right(usize),
    Loop(Program),
    In,
    Out,
}

impl Opcode {
    pub fn size(&self) -> usize {
        match *self {
            Opcode::Loop(ref p) => p.size(),
            _ => 1,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Program {
    opcodes: Vec<Opcode>,
}

impl Program {
    /// Count the number of opcodes
    pub fn size(&self) -> usize {
        self.opcodes.iter().map(|op| op.size()).sum()
    }

    /// Reduce repeated opcodes
    ///
    /// Using the first opcodes as a starting point, look at the following
    /// opcodes. While they are of the same category as the current
    /// opcodes (i.e. both either Add/Sub), combine them.
    ///
    /// Before: Add(1), Add(1), Add(1), Sub(1), Right(1), Right(1)...
    /// After:  Add(2), Right(2) ...
    pub fn reduce(&mut self) {
        use self::Opcode::*;
        let mut reduced = Vec::new();
        {
            let mut iter = self.opcodes.drain(..);
            let mut curr = match iter.next() {
                Some(o) => o,
                None => { return },
            };
            while let Some(opcode) = iter.next() {
                curr = match (opcode, curr) {
                    // TODO deal with overflows here
                    (Add(a), Add(b)) => { Add(a + b) },
                    (Add(a), Sub(b)) => { Sub(b - a) },
                    (Sub(a), Add(b)) => { Add(b - a) },
                    (Sub(a), Sub(b)) => { Sub(a + b) },
                    (Left(a), Left(b)) => { Left(a + b) },
                    (Left(a), Right(b)) => { Right(b - a) },
                    (Right(a), Left(b)) => { Left(b - a) },
                    (Right(a), Right(b)) => { Right(a + b) },
                    (Loop(mut p), prev) => {
                        reduced.push(prev);
                        p.reduce();
                        Loop(p)
                    }
                    (instr, prev) => {
                        reduced.push(prev);
                        instr
                    },
                }
            }
            reduced.push(curr);
        }
        self.opcodes = reduced;
    }
}

impl From<String> for Program {
    fn from(s: String) -> Program {
        Program { opcodes: Builder::new(&s).parse() }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Interpreter {
    stack: Vec<u8>,
    /// Stack pointer
    sp: usize,
    /// Instruction counter
    ic: usize,
}

impl Interpreter {
    pub fn new() -> Interpreter {
        Interpreter {
            stack: vec![0],
            sp: 0,
            ic: 0,
        }
    }

    pub fn reset(&mut self) {
        self.sp = 0;
        self.ic = 0;
        self.stack.clear();
        self.stack.push(0);
    }

    pub fn exec<S: Into<Program>>(&mut self, source: S) {
        let program = source.into();
        debug!("Interpreter::exec(p) where p.size() = {}", program.size());
        self.exec_r(&program)
    }
    fn exec_r(&mut self, program: &Program) {
        use self::Opcode::*;
        for opcode in &program.opcodes {
            self.ic += 1;
            match *opcode {
                Add(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_add(n).0 },
                Sub(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_sub(n).0 },
                // TODO underflow
                Left(n) => { self.sp -= n },
                Right(n) => {
                    // grow stack if necessary
                    self.sp += n;
                    while self.sp >= self.stack.len() { self.stack.push(0) }
                },
                Loop(ref os) => {
                    while self.stack[self.sp] != 0 {
                        self.exec_r(os);
                    }
                },
                In => {
                    self.stack[self.sp] = match std::io::stdin().take(1).bytes().next() {
                        Some(Ok(c)) => c,
                        _ => 0,
                    };
                },
                Out => {
                    let mut stdout = std::io::stdout();
                    write!(stdout, "{}", self.stack[self.sp] as char).ok();
                    stdout.flush().ok();
                }
            }
        }
    }
}

struct Builder<'a> {
    chars: std::str::Chars<'a>,
}

impl<'a> Builder<'a> {
    pub fn new(source: &'a String) -> Builder<'a> {
        Builder {
            chars: source.chars(),
        }
    }

    pub fn parse(&mut self) -> Vec<Opcode> {
        let mut opcodes = Vec::new();
        while let Some(c) = self.chars.next() {
            let opcode = match c {
                '+' => { Opcode::Add(1) },
                '-' => { Opcode::Sub(1) },
                '<' => { Opcode::Left(1) },
                '>' => { Opcode::Right(1) },
                '[' => { Opcode::Loop(Program { opcodes: self.parse() }) },
                ']' => { break },
                ',' => { Opcode::In },
                '.' => { Opcode::Out },
                _ => { continue },
            };
            opcodes.push(opcode);
        }
        opcodes
    }
}

<commit_msg>Fix Opcode::size()<commit_after>use std;
use std::convert::From;
use std::io::{Read, Write};
use std::num::wrapping::OverflowingOps;

#[derive(Debug, Clone, PartialEq)]
pub enum Opcode {
    Add(u8),
    Sub(u8),
    Left(usize),
    Right(usize),
    Loop(Program),
    In,
    Out,
}

impl Opcode {
    pub fn size(&self) -> usize {
        match *self {
            Opcode::Loop(ref p) => 1 + p.size(),
            _ => 1,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Program {
    opcodes: Vec<Opcode>,
}

impl Program {
    /// Count the number of opcodes
    pub fn size(&self) -> usize {
        self.opcodes.iter().map(|op| op.size()).sum()
    }

    /// Reduce repeated opcodes
    ///
    /// Using the first opcodes as a starting point, look at the following
    /// opcodes. While they are of the same category as the current
    /// opcodes (i.e. both either Add/Sub), combine them.
    ///
    /// Before: Add(1), Add(1), Add(1), Sub(1), Right(1), Right(1)...
    /// After:  Add(2), Right(2) ...
    pub fn reduce(&mut self) {
        use self::Opcode::*;
        let mut reduced = Vec::new();
        {
            let mut iter = self.opcodes.drain(..);
            let mut curr = match iter.next() {
                Some(o) => o,
                None => { return },
            };
            while let Some(opcode) = iter.next() {
                curr = match (opcode, curr) {
                    // TODO deal with overflows here
                    (Add(a), Add(b)) => { Add(a + b) },
                    (Add(a), Sub(b)) => { Sub(b - a) },
                    (Sub(a), Add(b)) => { Add(b - a) },
                    (Sub(a), Sub(b)) => { Sub(a + b) },
                    (Left(a), Left(b)) => { Left(a + b) },
                    (Left(a), Right(b)) => { Right(b - a) },
                    (Right(a), Left(b)) => { Left(b - a) },
                    (Right(a), Right(b)) => { Right(a + b) },
                    (Loop(mut p), prev) => {
                        reduced.push(prev);
                        p.reduce();
                        Loop(p)
                    }
                    (instr, prev) => {
                        reduced.push(prev);
                        instr
                    },
                }
            }
            reduced.push(curr);
        }
        self.opcodes = reduced;
    }
}

impl From<String> for Program {
    fn from(s: String) -> Program {
        Program { opcodes: Builder::new(&s).parse() }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Interpreter {
    stack: Vec<u8>,
    /// Stack pointer
    sp: usize,
    /// Instruction counter
    ic: usize,
}

impl Interpreter {
    pub fn new() -> Interpreter {
        Interpreter {
            stack: vec![0],
            sp: 0,
            ic: 0,
        }
    }

    pub fn reset(&mut self) {
        self.sp = 0;
        self.ic = 0;
        self.stack.clear();
        self.stack.push(0);
    }

    pub fn exec<S: Into<Program>>(&mut self, source: S) {
        let program = source.into();
        debug!("Interpreter::exec(p) where p.size() = {}", program.size());
        self.exec_r(&program)
    }
    fn exec_r(&mut self, program: &Program) {
        use self::Opcode::*;
        for opcode in &program.opcodes {
            self.ic += 1;
            match *opcode {
                Add(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_add(n).0 },
                Sub(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_sub(n).0 },
                // TODO underflow
                Left(n) => { self.sp -= n },
                Right(n) => {
                    // grow stack if necessary
                    self.sp += n;
                    while self.sp >= self.stack.len() { self.stack.push(0) }
                },
                Loop(ref os) => {
                    while self.stack[self.sp] != 0 {
                        self.exec_r(os);
                    }
                },
                In => {
                    self.stack[self.sp] = match std::io::stdin().take(1).bytes().next() {
                        Some(Ok(c)) => c,
                        _ => 0,
                    };
                },
                Out => {
                    let mut stdout = std::io::stdout();
                    write!(stdout, "{}", self.stack[self.sp] as char).ok();
                    stdout.flush().ok();
                }
            }
        }
    }
}

struct Builder<'a> {
    chars: std::str::Chars<'a>,
}

impl<'a> Builder<'a> {
    pub fn new(source: &'a String) -> Builder<'a> {
        Builder {
            chars: source.chars(),
        }
    }

    pub fn parse(&mut self) -> Vec<Opcode> {
        let mut opcodes = Vec::new();
        while let Some(c) = self.chars.next() {
            let opcode = match c {
                '+' => { Opcode::Add(1) },
                '-' => { Opcode::Sub(1) },
                '<' => { Opcode::Left(1) },
                '>' => { Opcode::Right(1) },
                '[' => { Opcode::Loop(Program { opcodes: self.parse() }) },
                ']' => { break },
                ',' => { Opcode::In },
                '.' => { Opcode::Out },
                _ => { continue },
            };
            opcodes.push(opcode);
        }
        opcodes
    }
}

<|endoftext|>


<commit_before>use std;
use std::convert::From;
use std::io::{Read, Write};
use std::num::wrapping::OverflowingOps;

#[derive(Debug, Clone, PartialEq)]
pub enum Opcode {
    Add(u8),
    Sub(u8),
    Left(usize),
    Right(usize),
    Loop(Program),
    In,
    Out,
}

impl Opcode {
    pub fn size(&self) -> usize {
        match *self {
            Opcode::Loop(ref p) => p.size(),
            _ => 1,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Program {
    opcodes: Vec<Opcode>,
}

impl Program {
    /// Count the number of opcodes
    pub fn size(&self) -> usize {
        self.opcodes.iter().map(|op| op.size()).sum()
    }

    /// Reduce repeated opcodes
    ///
    /// Using the first opcodes as a starting point, look at the following
    /// opcodes. While they are of the same category as the current
    /// opcodes (i.e. both either Add/Sub), combine them.
    ///
    /// Before: Add(1), Add(1), Add(1), Sub(1), Right(1), Right(1)...
    /// After:  Add(2), Right(2) ...
    pub fn reduce(&mut self) {
        use self::Opcode::*;
        let mut reduced = Vec::new();
        {
            let mut iter = self.opcodes.drain(..);
            let mut curr = match iter.next() {
                Some(o) => o,
                None => { return },
            };
            while let Some(opcode) = iter.next() {
                curr = match (opcode, curr) {
                    // TODO deal with overflows here
                    (Add(a), Add(b)) => { Add(a + b) },
                    (Add(a), Sub(b)) => { Sub(b - a) },
                    (Sub(a), Add(b)) => { Add(b - a) },
                    (Sub(a), Sub(b)) => { Sub(a + b) },
                    (Left(a), Left(b)) => { Left(a + b) },
                    (Left(a), Right(b)) => { Right(b - a) },
                    (Right(a), Left(b)) => { Left(b - a) },
                    (Right(a), Right(b)) => { Right(a + b) },
                    (Loop(mut p), prev) => {
                        reduced.push(prev);
                        p.reduce();
                        Loop(p)
                    }
                    (instr, prev) => {
                        reduced.push(prev);
                        instr
                    },
                }
            }
            reduced.push(curr);
        }
        self.opcodes = reduced;
    }
}

impl From<String> for Program {
    fn from(s: String) -> Program {
        Program { opcodes: Builder::new(&s).parse() }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Interpreter {
    stack: Vec<u8>,
    /// Stack pointer
    sp: usize,
    /// Instruction counter
    ic: usize,
}

impl Interpreter {
    pub fn new() -> Interpreter {
        Interpreter {
            stack: vec![0],
            sp: 0,
            ic: 0,
        }
    }

    pub fn reset(&mut self) {
        self.sp = 0;
        self.ic = 0;
        self.stack.clear();
        self.stack.push(0);
    }

    pub fn exec<S: Into<Program>>(&mut self, source: S) {
        let program = source.into();
        debug!("Interpreter::exec(p) where p.size() = {}", program.size());
        self.exec_r(&program)
    }
    fn exec_r(&mut self, program: &Program) {
        use self::Opcode::*;
        for opcode in &program.opcodes {
            trace!("Interpreter::exec_r() opcode = {:?}", opcode);
            self.ic += 1;
            match *opcode {
                Add(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_add(n).0 },
                Sub(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_sub(n).0 },
                // TODO underflow
                Left(n) => { self.sp -= n },
                Right(n) => {
                    // grow stack if necessary
                    self.sp += n;
                    while self.sp >= self.stack.len() { self.stack.push(0) }
                },
                Loop(ref os) => {
                    while self.stack[self.sp] != 0 {
                        self.exec_r(os);
                    }
                },
                In => {
                    self.stack[self.sp] = match std::io::stdin().take(1).bytes().next() {
                        Some(Ok(c)) => c,
                        _ => 0,
                    };
                },
                Out => {
                    let mut stdout = std::io::stdout();
                    write!(stdout, "{}", self.stack[self.sp] as char).ok();
                    stdout.flush().ok();
                }
            }
        }
    }
}

struct Builder<'a> {
    chars: std::str::Chars<'a>,
}

impl<'a> Builder<'a> {
    pub fn new(source: &'a String) -> Builder<'a> {
        Builder {
            chars: source.chars(),
        }
    }

    pub fn parse(&mut self) -> Vec<Opcode> {
        let mut opcodes = Vec::new();
        while let Some(c) = self.chars.next() {
            let opcode = match c {
                '+' => { Opcode::Add(1) },
                '-' => { Opcode::Sub(1) },
                '<' => { Opcode::Left(1) },
                '>' => { Opcode::Right(1) },
                '[' => { Opcode::Loop(Program { opcodes: self.parse() }) },
                ']' => { break },
                ',' => { Opcode::In },
                '.' => { Opcode::Out },
                _ => { continue },
            };
            opcodes.push(opcode);
        }
        opcodes
    }
}

<commit_msg>Remove trace!() in interpreter loop<commit_after>use std;
use std::convert::From;
use std::io::{Read, Write};
use std::num::wrapping::OverflowingOps;

#[derive(Debug, Clone, PartialEq)]
pub enum Opcode {
    Add(u8),
    Sub(u8),
    Left(usize),
    Right(usize),
    Loop(Program),
    In,
    Out,
}

impl Opcode {
    pub fn size(&self) -> usize {
        match *self {
            Opcode::Loop(ref p) => p.size(),
            _ => 1,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Program {
    opcodes: Vec<Opcode>,
}

impl Program {
    /// Count the number of opcodes
    pub fn size(&self) -> usize {
        self.opcodes.iter().map(|op| op.size()).sum()
    }

    /// Reduce repeated opcodes
    ///
    /// Using the first opcodes as a starting point, look at the following
    /// opcodes. While they are of the same category as the current
    /// opcodes (i.e. both either Add/Sub), combine them.
    ///
    /// Before: Add(1), Add(1), Add(1), Sub(1), Right(1), Right(1)...
    /// After:  Add(2), Right(2) ...
    pub fn reduce(&mut self) {
        use self::Opcode::*;
        let mut reduced = Vec::new();
        {
            let mut iter = self.opcodes.drain(..);
            let mut curr = match iter.next() {
                Some(o) => o,
                None => { return },
            };
            while let Some(opcode) = iter.next() {
                curr = match (opcode, curr) {
                    // TODO deal with overflows here
                    (Add(a), Add(b)) => { Add(a + b) },
                    (Add(a), Sub(b)) => { Sub(b - a) },
                    (Sub(a), Add(b)) => { Add(b - a) },
                    (Sub(a), Sub(b)) => { Sub(a + b) },
                    (Left(a), Left(b)) => { Left(a + b) },
                    (Left(a), Right(b)) => { Right(b - a) },
                    (Right(a), Left(b)) => { Left(b - a) },
                    (Right(a), Right(b)) => { Right(a + b) },
                    (Loop(mut p), prev) => {
                        reduced.push(prev);
                        p.reduce();
                        Loop(p)
                    }
                    (instr, prev) => {
                        reduced.push(prev);
                        instr
                    },
                }
            }
            reduced.push(curr);
        }
        self.opcodes = reduced;
    }
}

impl From<String> for Program {
    fn from(s: String) -> Program {
        Program { opcodes: Builder::new(&s).parse() }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Interpreter {
    stack: Vec<u8>,
    /// Stack pointer
    sp: usize,
    /// Instruction counter
    ic: usize,
}

impl Interpreter {
    pub fn new() -> Interpreter {
        Interpreter {
            stack: vec![0],
            sp: 0,
            ic: 0,
        }
    }

    pub fn reset(&mut self) {
        self.sp = 0;
        self.ic = 0;
        self.stack.clear();
        self.stack.push(0);
    }

    pub fn exec<S: Into<Program>>(&mut self, source: S) {
        let program = source.into();
        debug!("Interpreter::exec(p) where p.size() = {}", program.size());
        self.exec_r(&program)
    }
    fn exec_r(&mut self, program: &Program) {
        use self::Opcode::*;
        for opcode in &program.opcodes {
            self.ic += 1;
            match *opcode {
                Add(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_add(n).0 },
                Sub(n) => { self.stack[self.sp] = self.stack[self.sp].overflowing_sub(n).0 },
                // TODO underflow
                Left(n) => { self.sp -= n },
                Right(n) => {
                    // grow stack if necessary
                    self.sp += n;
                    while self.sp >= self.stack.len() { self.stack.push(0) }
                },
                Loop(ref os) => {
                    while self.stack[self.sp] != 0 {
                        self.exec_r(os);
                    }
                },
                In => {
                    self.stack[self.sp] = match std::io::stdin().take(1).bytes().next() {
                        Some(Ok(c)) => c,
                        _ => 0,
                    };
                },
                Out => {
                    let mut stdout = std::io::stdout();
                    write!(stdout, "{}", self.stack[self.sp] as char).ok();
                    stdout.flush().ok();
                }
            }
        }
    }
}

struct Builder<'a> {
    chars: std::str::Chars<'a>,
}

impl<'a> Builder<'a> {
    pub fn new(source: &'a String) -> Builder<'a> {
        Builder {
            chars: source.chars(),
        }
    }

    pub fn parse(&mut self) -> Vec<Opcode> {
        let mut opcodes = Vec::new();
        while let Some(c) = self.chars.next() {
            let opcode = match c {
                '+' => { Opcode::Add(1) },
                '-' => { Opcode::Sub(1) },
                '<' => { Opcode::Left(1) },
                '>' => { Opcode::Right(1) },
                '[' => { Opcode::Loop(Program { opcodes: self.parse() }) },
                ']' => { break },
                ',' => { Opcode::In },
                '.' => { Opcode::Out },
                _ => { continue },
            };
            opcodes.push(opcode);
        }
        opcodes
    }
}

<|endoftext|>