<commit_before>use sdl2::render::RendererContext;
use sdl2::render::Canvas;
use sdl2::video::Window;
use graphicsdevice::GraphicsDevice;
use spritebatchitem::SpriteBatchItem;
use spritebatch::SpriteSortMode;
use spritebatch::SpriteBatch;
use renderstate::RenderState;
use texture::Texture;
use std::i32;
use std::vec;
use vertexpositioncolortexture::VertexPositionColorTexture;

pub struct SpriteBatcher<'a> {
    initial_batch_size: i32,
    max_batch_size: i32,
    initial_vertex_array_size: i32,
    renderer: &'a Canvas<Window>,
    graphics_device: GraphicsDevice,
    batch_item_list: Vec<SpriteBatchItem<'a>>, /// The list of batch items to process.
    batch_item_count: i32, /// Index pointer to the next available SpriteBatchItem in _batchItemList.
    index: Vec<i32>, /// Vertex index array. The values in this array never change.
    vertex_array: Vec<VertexPositionColorTexture>,
}

impl<'a> SpriteBatcher<'a> {
    pub fn new(renderer: &'a Canvas<Window>, graphics_device: GraphicsDevice) -> SpriteBatcher<'a> {
        let mut bil = Vec::new();
        for i in 0..256 {
            bil.push(SpriteBatchItem::new());
        }

        let mut sb = SpriteBatcher {
            initial_batch_size: 256,
            max_batch_size: i32::MAX / 6, // 6 = 4 vertices unique and 2 shared, per quad
            initial_vertex_array_size: 256,
            renderer: renderer,
            graphics_device: graphics_device,
            batch_item_list: bil,
            batch_item_count: 0,
            index: Vec::new(),
            vertex_array: Vec::new(),
        };

        sb.ensure_array_capacity(256);

        sb
    }

    pub fn create_batch_item() -> SpriteBatchItem<'a> {
        SpriteBatchItem::new()
    }

    pub fn ensure_array_capacity(&mut self, num_batch_items: i32) {
        let neededCapacity = 6 * num_batch_items;
        if neededCapacity <= self.index.len() as i32 {
            // Short circuit out of here because we have enough capacity.
            return;
        }

        let mut newIndex: Vec<i32> = Vec::with_capacity(neededCapacity as usize);
        let start = 0;

        for i in 0..self.index.len() as usize {
            newIndex.push(self.index[i]);
        }

        let start = self.index.len() / 6;

        for i in start..num_batch_items as usize {
            /*
            *  TL    TR
            *   0----1 0,1,2,3 = index offsets for vertex indices
            *   |   /| TL,TR,BL,BR are vertex references in SpriteBatchItem.
            *   |  / |
            *   | /  |
            *   |/   |
            *   2----3
            *  BL    BR
            */
            // Triangle 1
            newIndex.insert((i * 6 + 0) as usize, (i * 4) as i32);
            newIndex.insert((i * 6 + 1) as usize, (i * 4 + 1) as i32);
            newIndex.insert((i * 6 + 2) as usize, (i * 4 + 2) as i32);
            // Triangle 2
            newIndex.insert((i * 6 + 3) as usize, (i * 4 + 1) as i32);
            newIndex.insert((i * 6 + 4) as usize, (i * 4 + 3) as i32);
            newIndex.insert((i * 6 + 5) as usize, (i * 4 + 2) as i32);
        }
        self.index = newIndex;

        self.vertex_array.resize(neededCapacity as usize, VertexPositionColorTexture::new());
    }

    pub fn draw_batch(&'a mut self, sort_mode: SpriteSortMode/*, Effect effect*/, render_state: &'a mut RenderState<'a>) {
        // nothing to do
        if self.batch_item_count == 0 {
            return;
        }

        // sort the batch items
        match sort_mode {
            SpriteSortMode::SpriteSortModeTexture => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
            SpriteSortMode::SpriteSortModeFrontToBack => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
            SpriteSortMode::SpriteSortModeBackToFront => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
            _ => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
        }

        // Determine how many iterations through the drawing code we need to make
        let mut batch_index: i32 = 0;
        let mut batch_count: i32 = self.batch_item_count;

        // Iterate through the batches, doing short.MaxValue sets of vertices only.
        while batch_count > 0 {
            // setup the vertexArray array
            let mut startIndex: i32 = 0;
            let mut index: i32 = 0;
            let mut tex: Option<&Texture> = None;

            let mut numBatchesToProcess: i32 = batch_count;
            if numBatchesToProcess > self.max_batch_size {
                numBatchesToProcess = self.max_batch_size;
            }

            {
                self.ensure_array_capacity(numBatchesToProcess);
            }

            // Draw the batches
            for i in 0..numBatchesToProcess {
                // if the texture changed, we need to flush and bind the new texture
                let shouldFlush: bool = &**self.batch_item_list[batch_index as usize].texture.as_ref().unwrap() as *const _ != &**tex.as_ref().unwrap() as *const _;
                if shouldFlush {
                    self.flush_vertex_array(startIndex, index /*, effect*/, tex, render_state);

                    tex = self.batch_item_list[batch_index as usize].texture;
                    startIndex = 0;
                    index = 0;
                }

                let mut item = &mut self.batch_item_list[batch_index as usize];
                // store the SpriteBatchItem data in our vertexArray
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexTL;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexTR;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexBL;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexTR;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexBR;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexBL;

                // Release the texture.
                item.set_texture(None);
            }
            // flush the remaining vertexArray data
            self.flush_vertex_array(startIndex, index /*, effect*/, tex, render_state);
            // Update our batch count to continue the process of culling down
            // large batches
            batch_count -= numBatchesToProcess;
        }
        // return items to the pool.
        self.batch_item_count = 0;
    }

    pub fn flush_vertex_array(&mut self, start: i32, end: i32 /*, Effect effect*/, texture: Option<&'a Texture<'a>>, render_state: &'a mut RenderState<'a>) {
        if start == end {
            return;
        }

        let vertexCount: i32 = end - start;
        render_state.set_texture(texture);

        self.graphics_device.draw(&self.vertex_array, vertexCount, render_state);
    }

}<commit_msg>Still trying to get things working<commit_after>use sdl2::render::RendererContext;
use sdl2::render::Canvas;
use sdl2::video::Window;
use graphicsdevice::GraphicsDevice;
use spritebatchitem::SpriteBatchItem;
use spritebatch::SpriteSortMode;
use spritebatch::SpriteBatch;
use renderstate::RenderState;
use texture::Texture;
use std::i32;
use std::vec;
use vertexpositioncolortexture::VertexPositionColorTexture;

pub struct SpriteBatcher<'a> {
    initial_batch_size: i32,
    max_batch_size: i32,
    initial_vertex_array_size: i32,
    renderer: &'a Canvas<Window>,
    graphics_device: GraphicsDevice,
    batch_item_list: Vec<SpriteBatchItem<'a>>, /// The list of batch items to process.
    batch_item_count: i32, /// Index pointer to the next available SpriteBatchItem in _batchItemList.
    index: Vec<i32>, /// Vertex index array. The values in this array never change.
    vertex_array: Vec<VertexPositionColorTexture>,
}

impl<'a> SpriteBatcher<'a> {
    pub fn new(renderer: &'a Canvas<Window>, graphics_device: GraphicsDevice) -> SpriteBatcher<'a> {
        let mut bil = Vec::new();
        for i in 0..256 {
            bil.push(SpriteBatchItem::new());
        }

        let mut sb = SpriteBatcher {
            initial_batch_size: 256,
            max_batch_size: i32::MAX / 6, // 6 = 4 vertices unique and 2 shared, per quad
            initial_vertex_array_size: 256,
            renderer: renderer,
            graphics_device: graphics_device,
            batch_item_list: bil,
            batch_item_count: 0,
            index: Vec::new(),
            vertex_array: Vec::new(),
        };

        sb.ensure_array_capacity(256);

        sb
    }

    pub fn create_batch_item() -> SpriteBatchItem<'a> {
        SpriteBatchItem::new()
    }

    pub fn ensure_array_capacity(&mut self, num_batch_items: i32) {
        let neededCapacity = 6 * num_batch_items;
        if neededCapacity <= self.index.len() as i32 {
            // Short circuit out of here because we have enough capacity.
            return;
        }

        let mut newIndex: Vec<i32> = Vec::with_capacity(neededCapacity as usize);
        let start = 0;

        for i in 0..self.index.len() as usize {
            newIndex.push(self.index[i]);
        }

        let start = self.index.len() / 6;

        for i in start..num_batch_items as usize {
            /*
            *  TL    TR
            *   0----1 0,1,2,3 = index offsets for vertex indices
            *   |   /| TL,TR,BL,BR are vertex references in SpriteBatchItem.
            *   |  / |
            *   | /  |
            *   |/   |
            *   2----3
            *  BL    BR
            */
            // Triangle 1
            newIndex.insert((i * 6 + 0) as usize, (i * 4) as i32);
            newIndex.insert((i * 6 + 1) as usize, (i * 4 + 1) as i32);
            newIndex.insert((i * 6 + 2) as usize, (i * 4 + 2) as i32);
            // Triangle 2
            newIndex.insert((i * 6 + 3) as usize, (i * 4 + 1) as i32);
            newIndex.insert((i * 6 + 4) as usize, (i * 4 + 3) as i32);
            newIndex.insert((i * 6 + 5) as usize, (i * 4 + 2) as i32);
        }
        self.index = newIndex;

        self.vertex_array.resize(neededCapacity as usize, VertexPositionColorTexture::new());
    }

    pub fn draw_batch(&'a mut self, sort_mode: SpriteSortMode/*, Effect effect*/, render_state: &'a mut RenderState<'a>) {
        // nothing to do
        if self.batch_item_count == 0 {
            return;
        }

        // sort the batch items
        match sort_mode {
            SpriteSortMode::SpriteSortModeTexture => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
            SpriteSortMode::SpriteSortModeFrontToBack => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
            SpriteSortMode::SpriteSortModeBackToFront => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
            _ => self.batch_item_list.sort_by(|a, b| a.cmp(b)),
        }

        // Determine how many iterations through the drawing code we need to make
        let mut batch_index: i32 = 0;
        let mut batch_count: i32 = self.batch_item_count;

        // Iterate through the batches, doing short.MaxValue sets of vertices only.
        while batch_count > 0 {
            // setup the vertexArray array
            let mut startIndex: i32 = 0;
            let mut index: i32 = 0;
            let mut tex: Option<&'a Texture<'a>> = None;

            let mut numBatchesToProcess: i32 = batch_count;
            if numBatchesToProcess > self.max_batch_size {
                numBatchesToProcess = self.max_batch_size;
            }

            {
                self.ensure_array_capacity(numBatchesToProcess);
            }

            // Draw the batches
            for i in 0..numBatchesToProcess {
                // if the texture changed, we need to flush and bind the new texture
                let shouldFlush: bool = &**self.batch_item_list[batch_index as usize].texture.as_ref().unwrap() as *const _ != &**tex.as_ref().unwrap() as *const _;
                if shouldFlush {
                    self.flush_vertex_array(startIndex, index /*, effect*/, tex, render_state);

                    tex = self.batch_item_list[batch_index as usize].texture;
                    startIndex = 0;
                    index = 0;
                }

                let mut item = &mut self.batch_item_list[batch_index as usize];
                // store the SpriteBatchItem data in our vertexArray
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexTL;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexTR;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexBL;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexTR;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexBR;
                index = index + 1;
                self.vertex_array[index as usize] = item.vertexBL;

                // Release the texture.
                item.set_texture(None);
            }
            // flush the remaining vertexArray data
            self.flush_vertex_array(startIndex, index /*, effect*/, tex, render_state);
            // Update our batch count to continue the process of culling down
            // large batches
            batch_count -= numBatchesToProcess;
        }
        // return items to the pool.
        self.batch_item_count = 0;
    }

    pub fn flush_vertex_array(&mut self, start: i32, end: i32 /*, Effect effect*/, texture: Option<&'a Texture<'a>>, render_state: &'a mut RenderState<'a>) {
        if start == end {
            return;
        }

        let vertexCount: i32 = end - start;
        render_state.set_texture(texture);

        self.graphics_device.draw(&self.vertex_array, vertexCount, render_state);
    }

}<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(asm)]
#![feature(const_fn)]
#![cfg_attr(not(target_os = "redox"), feature(process_try_wait))]

extern crate orbclient;
extern crate orbfont;

#[cfg(not(target_os = "redox"))]
extern crate libc;

#[cfg(target_os = "redox")]
extern crate syscall;

use orbclient::event;
use std::{env, str};
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{self, Result, Read, Write};
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
use std::os::unix::process::CommandExt;
use std::process::{Child, Command, Stdio};

use console::Console;
use getpty::getpty;

mod console;
mod getpty;

#[cfg(not(target_os="redox"))]
pub fn before_exec() -> Result<()> {
    use libc;
    unsafe {
        if libc::setsid() < 0 {
            panic!("setsid: {:?}", io::Error::last_os_error());
        }
        if libc::ioctl(0, libc::TIOCSCTTY, 1) < 0 {
            panic!("ioctl: {:?}", io::Error::last_os_error());
        }
    }
    Ok(())
}

#[cfg(target_os="redox")]
pub fn before_exec() -> Result<()> {
    Ok(())
}

#[cfg(target_os = "redox")]
fn handle(console: &mut Console, master_fd: RawFd, process: &mut Child) {
    extern crate syscall;

    use std::os::unix::io::AsRawFd;

    let mut event_file = File::open("event:").expect("terminal: failed to open event file");

    let window_fd = console.window.as_raw_fd();
    syscall::fevent(window_fd, syscall::flag::EVENT_READ).expect("terminal: failed to fevent console window");

    let mut master = unsafe { File::from_raw_fd(master_fd) };
    syscall::fevent(master_fd, syscall::flag::EVENT_READ).expect("terminal: failed to fevent master PTY");

    let mut handle_event = |event_id: usize, event_count: usize| -> bool {
        if event_id == window_fd {
            for event in console.window.events() {
                if event.code == event::EVENT_QUIT {
                    return false;
                }

                console.input(&event);
            }

            if ! console.input.is_empty()  {
                if let Err(err) = master.write(&console.input) {
                    let term_stderr = io::stderr();
                    let mut term_stderr = term_stderr.lock();

                    let _ = term_stderr.write(b"failed to write stdin: ");
                    let _ = term_stderr.write(err.description().as_bytes());
                    let _ = term_stderr.write(b"\n");
                    return false;
                }
                let _ = master.flush();
                console.input.clear();
            }
        } else if event_id == master_fd {
            let mut packet = [0; 4096];
            let count = master.read(&mut packet).expect("terminal: failed to read master PTY");
            if count == 0 {
                if event_count == 0 {
                    return false;
                }
            } else {
                console.write(&packet[1..count], true).expect("terminal: failed to write to console");

                //if packet[0] & 1 == 1
                {
                    console.redraw();
                }
            }
        } else {
            println!("Unknown event {}", event_id);
        }

        true
    };

    handle_event(window_fd, 0);
    handle_event(master_fd, 0);

    'events: loop {
        let mut sys_event = syscall::Event::default();
        event_file.read(&mut sys_event).expect("terminal: failed to read event file");
        if ! handle_event(sys_event.id, sys_event.data) {
            break 'events;
        }
    }

    let _ = process.kill();
    process.wait().expect("terminal: failed to wait on shell");
}

#[cfg(not(target_os = "redox"))]
fn handle(console: &mut Console, master_fd: RawFd, process: &mut Child) {
    use libc;
    use std::io::ErrorKind;
    use std::thread;
    use std::time::Duration;

    unsafe {
        let size = libc::winsize {
            ws_row: console.console.h as libc::c_ushort,
            ws_col: console.console.w as libc::c_ushort,
            ws_xpixel: 0,
            ws_ypixel: 0
        };
        if libc::ioctl(master_fd, libc::TIOCSWINSZ, &size as *const libc::winsize) < 0 {
            panic!("ioctl: {:?}", io::Error::last_os_error());
        }
    }

    console.console.raw_mode = true;

    let mut master = unsafe { File::from_raw_fd(master_fd) };

    'events: loop {
        for event in console.window.events() {
            if event.code == event::EVENT_QUIT {
                break 'events;
            }

            console.input(&event);
        }

        if ! console.input.is_empty()  {
            if let Err(err) = master.write(&console.input) {
                let term_stderr = io::stderr();
                let mut term_stderr = term_stderr.lock();

                let _ = term_stderr.write(b"failed to write stdin: ");
                let _ = term_stderr.write(err.description().as_bytes());
                let _ = term_stderr.write(b"\n");
                break 'events;
            }
            let _ = master.flush();
            console.input.clear();
        }

        let mut packet = [0; 4096];
        match master.read(&mut packet) {
            Ok(0) => break 'events,
            Ok(count) => {
                console.write(&packet[..count], true).expect("terminal: failed to write to console");
                console.redraw();
            },
            Err(err) => match err.kind() {
                ErrorKind::WouldBlock => (),
                _ => panic!("terminal: failed to read master PTY: {:?}", err)
            }
        }

        match process.try_wait() {
            Ok(_status) => break 'events,
            Err(err) => match err.kind() {
                ErrorKind::WouldBlock => (),
                _ => panic!("terminal: failed to wait on child: {:?}", err)
            }
        }

        thread::sleep(Duration::new(0, 100));
    }

    let _ = process.kill();
    process.wait().expect("terminal: failed to wait on shell");
}

fn main() {
    let shell = env::args().nth(1).unwrap_or("sh".to_string());

    let (master_fd, tty_path) = getpty();

    let slave_stdin = OpenOptions::new().read(true).write(false).open(&tty_path).unwrap();
    let slave_stdout = OpenOptions::new().read(false).write(true).open(&tty_path).unwrap();
    let slave_stderr = OpenOptions::new().read(false).write(true).open(&tty_path).unwrap();

    let width = 800;
    let height = 576;

    env::set_var("COLUMNS", format!("{}", width / 8));
    env::set_var("LINES", format!("{}", height / 16));
    env::set_var("TERM", "linux");
    env::set_var("TTY", format!("{}", tty_path.display()));

    match unsafe {
        Command::new(&shell)
            .stdin(Stdio::from_raw_fd(slave_stdin.into_raw_fd()))
            .stdout(Stdio::from_raw_fd(slave_stdout.into_raw_fd()))
            .stderr(Stdio::from_raw_fd(slave_stderr.into_raw_fd()))
            .before_exec(|| {
                before_exec()
            })
            .spawn()
    } {
        Ok(mut process) => {
            let mut console = Console::new(width, height);
            handle(&mut console, master_fd, &mut process);
        },
        Err(err) => {
            let term_stderr = io::stderr();
            let mut term_stderr = term_stderr.lock();
            let _ = term_stderr.write(b"failed to execute '");
            let _ = term_stderr.write(shell.as_bytes());
            let _ = term_stderr.write(b"': ");
            let _ = term_stderr.write(err.description().as_bytes());
            let _ = term_stderr.write(b"\n");
        }
    }
}
<commit_msg>Do not break when status from try_wait is Ok(None)<commit_after>#![deny(warnings)]
#![feature(asm)]
#![feature(const_fn)]
#![cfg_attr(not(target_os = "redox"), feature(process_try_wait))]

extern crate orbclient;
extern crate orbfont;

#[cfg(not(target_os = "redox"))]
extern crate libc;

#[cfg(target_os = "redox")]
extern crate syscall;

use orbclient::event;
use std::{env, str};
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{self, Result, Read, Write};
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
use std::os::unix::process::CommandExt;
use std::process::{Child, Command, Stdio};

use console::Console;
use getpty::getpty;

mod console;
mod getpty;

#[cfg(not(target_os="redox"))]
pub fn before_exec() -> Result<()> {
    use libc;
    unsafe {
        if libc::setsid() < 0 {
            panic!("setsid: {:?}", io::Error::last_os_error());
        }
        if libc::ioctl(0, libc::TIOCSCTTY, 1) < 0 {
            panic!("ioctl: {:?}", io::Error::last_os_error());
        }
    }
    Ok(())
}

#[cfg(target_os="redox")]
pub fn before_exec() -> Result<()> {
    Ok(())
}

#[cfg(target_os = "redox")]
fn handle(console: &mut Console, master_fd: RawFd, process: &mut Child) {
    extern crate syscall;

    use std::os::unix::io::AsRawFd;

    let mut event_file = File::open("event:").expect("terminal: failed to open event file");

    let window_fd = console.window.as_raw_fd();
    syscall::fevent(window_fd, syscall::flag::EVENT_READ).expect("terminal: failed to fevent console window");

    let mut master = unsafe { File::from_raw_fd(master_fd) };
    syscall::fevent(master_fd, syscall::flag::EVENT_READ).expect("terminal: failed to fevent master PTY");

    let mut handle_event = |event_id: usize, event_count: usize| -> bool {
        if event_id == window_fd {
            for event in console.window.events() {
                if event.code == event::EVENT_QUIT {
                    return false;
                }

                console.input(&event);
            }

            if ! console.input.is_empty()  {
                if let Err(err) = master.write(&console.input) {
                    let term_stderr = io::stderr();
                    let mut term_stderr = term_stderr.lock();

                    let _ = term_stderr.write(b"failed to write stdin: ");
                    let _ = term_stderr.write(err.description().as_bytes());
                    let _ = term_stderr.write(b"\n");
                    return false;
                }
                let _ = master.flush();
                console.input.clear();
            }
        } else if event_id == master_fd {
            let mut packet = [0; 4096];
            let count = master.read(&mut packet).expect("terminal: failed to read master PTY");
            if count == 0 {
                if event_count == 0 {
                    return false;
                }
            } else {
                console.write(&packet[1..count], true).expect("terminal: failed to write to console");

                //if packet[0] & 1 == 1
                {
                    console.redraw();
                }
            }
        } else {
            println!("Unknown event {}", event_id);
        }

        true
    };

    handle_event(window_fd, 0);
    handle_event(master_fd, 0);

    'events: loop {
        let mut sys_event = syscall::Event::default();
        event_file.read(&mut sys_event).expect("terminal: failed to read event file");
        if ! handle_event(sys_event.id, sys_event.data) {
            break 'events;
        }
    }

    let _ = process.kill();
    process.wait().expect("terminal: failed to wait on shell");
}

#[cfg(not(target_os = "redox"))]
fn handle(console: &mut Console, master_fd: RawFd, process: &mut Child) {
    use libc;
    use std::io::ErrorKind;
    use std::thread;
    use std::time::Duration;

    unsafe {
        let size = libc::winsize {
            ws_row: console.console.h as libc::c_ushort,
            ws_col: console.console.w as libc::c_ushort,
            ws_xpixel: 0,
            ws_ypixel: 0
        };
        if libc::ioctl(master_fd, libc::TIOCSWINSZ, &size as *const libc::winsize) < 0 {
            panic!("ioctl: {:?}", io::Error::last_os_error());
        }
    }

    console.console.raw_mode = true;

    let mut master = unsafe { File::from_raw_fd(master_fd) };

    'events: loop {
        for event in console.window.events() {
            if event.code == event::EVENT_QUIT {
                break 'events;
            }

            console.input(&event);
        }

        if ! console.input.is_empty()  {
            if let Err(err) = master.write(&console.input) {
                let term_stderr = io::stderr();
                let mut term_stderr = term_stderr.lock();

                let _ = term_stderr.write(b"failed to write stdin: ");
                let _ = term_stderr.write(err.description().as_bytes());
                let _ = term_stderr.write(b"\n");
                break 'events;
            }
            let _ = master.flush();
            console.input.clear();
        }

        let mut packet = [0; 4096];
        match master.read(&mut packet) {
            Ok(0) => break 'events,
            Ok(count) => {
                console.write(&packet[..count], true).expect("terminal: failed to write to console");
                console.redraw();
            },
            Err(err) => match err.kind() {
                ErrorKind::WouldBlock => (),
                _ => panic!("terminal: failed to read master PTY: {:?}", err)
            }
        }

        match process.try_wait() {
            Ok(status) => match status {
                Some(_code) => break 'events,
                None => ()
            },
            Err(err) => match err.kind() {
                ErrorKind::WouldBlock => (),
                _ => panic!("terminal: failed to wait on child: {:?}", err)
            }
        }

        thread::sleep(Duration::new(0, 100));
    }

    let _ = process.kill();
    process.wait().expect("terminal: failed to wait on shell");
}

fn main() {
    let shell = env::args().nth(1).unwrap_or("sh".to_string());

    let (master_fd, tty_path) = getpty();

    let slave_stdin = OpenOptions::new().read(true).write(false).open(&tty_path).unwrap();
    let slave_stdout = OpenOptions::new().read(false).write(true).open(&tty_path).unwrap();
    let slave_stderr = OpenOptions::new().read(false).write(true).open(&tty_path).unwrap();

    let width = 800;
    let height = 576;

    env::set_var("COLUMNS", format!("{}", width / 8));
    env::set_var("LINES", format!("{}", height / 16));
    env::set_var("TERM", "linux");
    env::set_var("TTY", format!("{}", tty_path.display()));

    match unsafe {
        Command::new(&shell)
            .stdin(Stdio::from_raw_fd(slave_stdin.into_raw_fd()))
            .stdout(Stdio::from_raw_fd(slave_stdout.into_raw_fd()))
            .stderr(Stdio::from_raw_fd(slave_stderr.into_raw_fd()))
            .before_exec(|| {
                before_exec()
            })
            .spawn()
    } {
        Ok(mut process) => {
            let mut console = Console::new(width, height);
            handle(&mut console, master_fd, &mut process);
        },
        Err(err) => {
            let term_stderr = io::stderr();
            let mut term_stderr = term_stderr.lock();
            let _ = term_stderr.write(b"failed to execute '");
            let _ = term_stderr.write(shell.as_bytes());
            let _ = term_stderr.write(b"': ");
            let _ = term_stderr.write(err.description().as_bytes());
            let _ = term_stderr.write(b"\n");
        }
    }
}
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use texture::{Texture2dBinder, TextureCubeMapBinder};
use types::GLError;

unsafe fn _active_texture(idx: u32) {
    gl::ActiveTexture(gl::TEXTURE0 + (idx as GLenum));
    dbg_gl_error! {
        GLError::InvalidEnum => "`texture` is out of bounds (expected to be GL_TEXTUREi, 0 <= i < GL_MAX_TEXTURE_IMAGE_UNITS)",
        _ => "Unknown error"
    }
}

pub trait TextureUnit {
    fn idx() -> u32;

    fn active(&mut self) -> TextureUnitBinding {
        unsafe {
            _active_texture(Self::idx());
            TextureUnitBinding::current_at_idx(Self::idx())
        }
    }
}

// TODO: Use a macro, or const generic parameters:
// https://github.com/rust-lang/rfcs/issues/273
// https://github.com/rust-lang/rfcs/issues/1038
pub struct TextureUnit0;
pub struct TextureUnit1;
pub struct TextureUnit2;
pub struct TextureUnit3;
pub struct TextureUnit4;
pub struct TextureUnit5;
pub struct TextureUnit6;
pub struct TextureUnit7;

impl TextureUnit for TextureUnit0 { fn idx() -> u32 { 0 } }
impl TextureUnit for TextureUnit1 { fn idx() -> u32 { 1 } }
impl TextureUnit for TextureUnit2 { fn idx() -> u32 { 2 } }
impl TextureUnit for TextureUnit3 { fn idx() -> u32 { 3 } }
impl TextureUnit for TextureUnit4 { fn idx() -> u32 { 4 } }
impl TextureUnit for TextureUnit5 { fn idx() -> u32 { 5 } }
impl TextureUnit for TextureUnit6 { fn idx() -> u32 { 6 } }
impl TextureUnit for TextureUnit7 { fn idx() -> u32 { 7 } }

// NOTE: Ensure the number of each texture unit matches its index in the tuple
pub struct TextureUnits(pub TextureUnit0, pub TextureUnit1, pub TextureUnit2,
                        pub TextureUnit3, pub TextureUnit4, pub TextureUnit5,
                        pub TextureUnit6, pub TextureUnit7);

impl TextureUnits {
    pub unsafe fn current() -> TextureUnits {
        TextureUnits(TextureUnit0, TextureUnit1, TextureUnit2, TextureUnit3,
                     TextureUnit4, TextureUnit5, TextureUnit6, TextureUnit7)
    }

    pub unsafe fn active_nth(&self, idx: u32) -> TextureUnitBinding {
        _active_texture(idx);
        TextureUnitBinding::current_at_idx(idx)
    }
}

pub struct TextureUnitBinding {
    idx: u32,
    pub texture_2d: Texture2dBinder,
    pub texture_cube_map: TextureCubeMapBinder
}

impl TextureUnitBinding {
    unsafe fn current_at_idx(idx: u32) -> Self {
        TextureUnitBinding {
            idx: idx,
            texture_2d: Texture2dBinder,
            texture_cube_map: TextureCubeMapBinder
        }
    }

    pub fn gl_idx(&self) -> u32 {
        self.idx
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct TextureSampler { idx: i32 }

#[macro_export]
macro_rules! bind_texture_cube_map {
    ($gl_tex_unit:expr, $texture:expr) => {
        $gl_tex_unit.texture_cube_map.bind($texture)
    }
}

#[macro_export]
macro_rules! bind_texture_2d {
    ($gl_tex_unit:expr, $texture:expr) => {
        $gl_tex_unit.texture_2d.bind($texture)
    }
}
<commit_msg>Add `TextureUnitBinding.sampler()`<commit_after>use gl;
use gl::types::*;
use texture::{Texture2dBinder, TextureCubeMapBinder};
use types::GLError;

unsafe fn _active_texture(idx: u32) {
    gl::ActiveTexture(gl::TEXTURE0 + (idx as GLenum));
    dbg_gl_error! {
        GLError::InvalidEnum => "`texture` is out of bounds (expected to be GL_TEXTUREi, 0 <= i < GL_MAX_TEXTURE_IMAGE_UNITS)",
        _ => "Unknown error"
    }
}

pub trait TextureUnit {
    fn idx() -> u32;

    fn active(&mut self) -> TextureUnitBinding {
        unsafe {
            _active_texture(Self::idx());
            TextureUnitBinding::current_at_idx(Self::idx())
        }
    }
}

// TODO: Use a macro, or const generic parameters:
// https://github.com/rust-lang/rfcs/issues/273
// https://github.com/rust-lang/rfcs/issues/1038
pub struct TextureUnit0;
pub struct TextureUnit1;
pub struct TextureUnit2;
pub struct TextureUnit3;
pub struct TextureUnit4;
pub struct TextureUnit5;
pub struct TextureUnit6;
pub struct TextureUnit7;

impl TextureUnit for TextureUnit0 { fn idx() -> u32 { 0 } }
impl TextureUnit for TextureUnit1 { fn idx() -> u32 { 1 } }
impl TextureUnit for TextureUnit2 { fn idx() -> u32 { 2 } }
impl TextureUnit for TextureUnit3 { fn idx() -> u32 { 3 } }
impl TextureUnit for TextureUnit4 { fn idx() -> u32 { 4 } }
impl TextureUnit for TextureUnit5 { fn idx() -> u32 { 5 } }
impl TextureUnit for TextureUnit6 { fn idx() -> u32 { 6 } }
impl TextureUnit for TextureUnit7 { fn idx() -> u32 { 7 } }

// NOTE: Ensure the number of each texture unit matches its index in the tuple
pub struct TextureUnits(pub TextureUnit0, pub TextureUnit1, pub TextureUnit2,
                        pub TextureUnit3, pub TextureUnit4, pub TextureUnit5,
                        pub TextureUnit6, pub TextureUnit7);

impl TextureUnits {
    pub unsafe fn current() -> TextureUnits {
        TextureUnits(TextureUnit0, TextureUnit1, TextureUnit2, TextureUnit3,
                     TextureUnit4, TextureUnit5, TextureUnit6, TextureUnit7)
    }

    pub unsafe fn active_nth(&self, idx: u32) -> TextureUnitBinding {
        _active_texture(idx);
        TextureUnitBinding::current_at_idx(idx)
    }
}

pub struct TextureUnitBinding {
    idx: u32,
    pub texture_2d: Texture2dBinder,
    pub texture_cube_map: TextureCubeMapBinder
}

impl TextureUnitBinding {
    unsafe fn current_at_idx(idx: u32) -> Self {
        TextureUnitBinding {
            idx: idx,
            texture_2d: Texture2dBinder,
            texture_cube_map: TextureCubeMapBinder
        }
    }

    pub fn gl_idx(&self) -> u32 {
        self.idx
    }

    pub fn sampler(&self) -> TextureSampler {
        TextureSampler { idx: self.idx as i32 }
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct TextureSampler { idx: i32 }

#[macro_export]
macro_rules! bind_texture_cube_map {
    ($gl_tex_unit:expr, $texture:expr) => {
        $gl_tex_unit.texture_cube_map.bind($texture)
    }
}

#[macro_export]
macro_rules! bind_texture_2d {
    ($gl_tex_unit:expr, $texture:expr) => {
        $gl_tex_unit.texture_2d.bind($texture)
    }
}
<|endoftext|>


<commit_before>const TWO: u64 = 2;

pub fn square(s: u32) -> u64 {
    if s < 1 || s > 64 {
        panic!("Square must be between 1 and 64");
    }
    TWO.pow(s - 1)
}

pub fn total() -> u64 {
    (1..65).fold(0, |acc, s| acc + square(s))
}
<commit_msg>Parameterize min and max<commit_after>const TWO: u64 = 2;
const MIN: u32 = 1;
const MAX: u32 = 64;

pub fn square(s: u32) -> u64 {
    if s < MIN || s > MAX {
        panic!("Square must be between 1 and 64");
    }
    TWO.pow(s - 1)
}

pub fn total() -> u64 {
    (MIN..MAX + 1).fold(0, |acc, s| acc + square(s))
}
<|endoftext|>


<commit_before>/// Enables the ability to merge two items
pub trait Merge: Ord + Copy {
    /// Returns the result of merging self with other, if possible, and None otherwise.
    fn merge(self, other: Self) -> Option<Self>;
}

/// Enables the ability to coalesce items in a collection
/// Coalescence occurs when two items in the collection are merged
/// in lieu of inserting a new item
pub trait Coalesce {
    /// The type of element that can be coalesced.
    type Element: Ord + Copy + Merge;

    /// Inserts or merges, if possible, the item into the collection at the given index.
    fn coalesce(&mut self, index: usize, el: Self::Element);
    /// Searches for the index to insert the element in order, then coalesces at the found index;
    fn search_coalesce(&mut self, start: usize, el: Self::Element) -> usize;

    /// Inserts, in order, the elements of an ordered iterable into self.
    /// Duplicate elements are not inserted.
    fn merge_coalesce<Iter>(&mut self, iter: Iter)
        where Iter: IntoIterator<Item = Self::Element>
    {
        let mut idx = 0;
        for element in iter {
            idx = self.search_coalesce(idx, element);
        }
    }
}

impl<T: Ord + Copy + Merge> Coalesce for Vec<T> {
    type Element = T;

    fn coalesce(&mut self, index: usize, el: T) {
        let merge = T::merge;
        if self.is_empty() {
            self.insert(index, el);
        } else if index == 0 {
            if let Some(coalesced) = merge(el, self[0]) {
                self[index] = coalesced;
            } else {
                self.insert(index, el);
            }
        } else if index == self.len() {
            if let Some(coalesced) = merge(self[index - 1], el) {
                self[index - 1] = coalesced;
            } else {
                self.insert(index, el);
            }
        } else {
            if let Some(coalesced) = merge(self[index - 1], el) {
                self[index - 1] = coalesced;
                if let Some(coalesced) = merge(self[index - 1], self[index]) {
                    self[index - 1] = coalesced;
                    self.remove(index);
                }
            } else if let Some(coalesced) = merge(el, self[index]) {
                self[index ] = coalesced;
            } else {
                self.insert(index, el);
            }
        }
    }

    fn search_coalesce(&mut self, start: usize, el: T) -> usize {
        match self[start..].binary_search(&el) {
            Ok(idx) => start + idx,
            Err(idx) => {
                let idx = start + idx;
                self.coalesce(idx, el);
                idx
            }
        }
    }
}

macro_rules! impl_merge_tuples {
    ($tp:ident) => (
        impl Merge for ($tp, $tp) {
            fn merge(self, (x2, y2): ($tp, $tp))  -> Option<($tp, $tp)> {
                let (x1, y1) = self;
                if y1 >= x2 {
                    Some(if y1 < y2 { (x1, y2) } else { (x1, y1) })
                } else {
                    None
                }
            }
        }
    )
}

impl_merge_tuples!(isize);
impl_merge_tuples!(usize);
impl_merge_tuples!(u32);
impl_merge_tuples!(u16);
impl_merge_tuples!(u8);
impl_merge_tuples!(i32);
impl_merge_tuples!(i16);
impl_merge_tuples!(i8);

#[test]
fn test_coalesce_empty() {
    let mut v = vec![];
    v.coalesce(0, (0, 1));
    assert_eq!(v, [(0, 1)]);
}

#[test]
fn test_coalesce_first() {
    let mut v = vec![(1, 1)];
    v.coalesce(0, (0, 1));
    assert_eq!(v, [(0, 1)])
}

#[test]
fn test_coalesce_last() {
    let mut v = vec![(1, 1)];
    v.coalesce(1, (1, 2));
    assert_eq!(v, [(1, 2)])
}

#[test]
fn test_coalesce_both() {
    let mut v = vec![(1, 1), (2, 2)];
    v.coalesce(1, (1, 2));
    assert_eq!(v, [(1, 2)])
}

#[test]
fn test_coalesce_none() {
    let mut v = vec![(1, 1), (3, 3)];
    v.coalesce(1, (2, 2));
    assert_eq!(v, [(1, 1), (2, 2), (3, 3)])
}

#[test]
fn test_coalesce_twice() {
    let mut v = vec![];
    v.coalesce(0, (0, 1));
    v.coalesce(0, (-2, -1));
    v.coalesce(1, (-1, 0));
    assert_eq!(v, [(-2, 1)]);
}

#[test]
fn test_search_and_coalesce() {
    let mut v = vec![];
    for el in vec![(0, 1), (-2, -1), (-1, 0)] {
        let index = v.binary_search(&el).err().unwrap();
        v.coalesce(index, el);
    }
    assert_eq!(v, [(-2, 1)]);
}

#[test]
fn test_coalesce_subrange() {
    let mut v = vec![(0, 3)];
    v.coalesce(1, (1, 2));
    assert_eq!(v, [(0, 3)]);
}

#[test]
fn test_search_coalesce() {
    let mut v = vec![(0, 1), (2, 3), (4, 5), (6, 7)];
    assert_eq!(2, v.search_coalesce(1, (4, 5)));
}

#[test]
fn test_search_coalesce_2() {
    let mut v = vec![(0, 1), (2, 3), (4, 5), (6, 7)];
    assert_eq!(3, v.search_coalesce(1, (5, 6)));
    assert_eq!(v, [(0, 1), (2, 3), (4, 7)]);
}
<commit_msg>Add a sanity assertion to the impl of Merge for (num, num)<commit_after>/// Enables the ability to merge two items
pub trait Merge: Ord + Copy {
    /// Returns the result of merging self with other, if possible, and None otherwise.
    fn merge(self, other: Self) -> Option<Self>;
}

/// Enables the ability to coalesce items in a collection
/// Coalescence occurs when two items in the collection are merged
/// in lieu of inserting a new item
pub trait Coalesce {
    /// The type of element that can be coalesced.
    type Element: Ord + Copy + Merge;

    /// Inserts or merges, if possible, the item into the collection at the given index.
    fn coalesce(&mut self, index: usize, el: Self::Element);
    /// Searches for the index to insert the element in order, then coalesces at the found index;
    fn search_coalesce(&mut self, start: usize, el: Self::Element) -> usize;

    /// Inserts, in order, the elements of an ordered iterable into self.
    /// Duplicate elements are not inserted.
    fn merge_coalesce<Iter>(&mut self, iter: Iter)
        where Iter: IntoIterator<Item = Self::Element>
    {
        let mut idx = 0;
        for element in iter {
            idx = self.search_coalesce(idx, element);
        }
    }
}

impl<T: Ord + Copy + Merge> Coalesce for Vec<T> {
    type Element = T;

    fn coalesce(&mut self, index: usize, el: T) {
        let merge = T::merge;
        if self.is_empty() {
            self.insert(index, el);
        } else if index == 0 {
            if let Some(coalesced) = merge(el, self[0]) {
                self[index] = coalesced;
            } else {
                self.insert(index, el);
            }
        } else if index == self.len() {
            if let Some(coalesced) = merge(self[index - 1], el) {
                self[index - 1] = coalesced;
            } else {
                self.insert(index, el);
            }
        } else {
            if let Some(coalesced) = merge(self[index - 1], el) {
                self[index - 1] = coalesced;
                if let Some(coalesced) = merge(self[index - 1], self[index]) {
                    self[index - 1] = coalesced;
                    self.remove(index);
                }
            } else if let Some(coalesced) = merge(el, self[index]) {
                self[index ] = coalesced;
            } else {
                self.insert(index, el);
            }
        }
    }

    fn search_coalesce(&mut self, start: usize, el: T) -> usize {
        match self[start..].binary_search(&el) {
            Ok(idx) => start + idx,
            Err(idx) => {
                let idx = start + idx;
                self.coalesce(idx, el);
                idx
            }
        }
    }
}

macro_rules! impl_merge_tuples {
    ($tp:ident) => (
        impl Merge for ($tp, $tp) {
            fn merge(self, (begin2, end2): ($tp, $tp))  -> Option<($tp, $tp)> {
                let (begin1, end1) = self;
                assert!(begin2 >= begin1, "Input's begin must be >= self's begin");
                if end1 >= begin2 {
                    Some(if end1 < end2 { (begin1, end2) } else { (begin1, end1) })
                } else {
                    None
                }
            }
        }
    )
}

impl_merge_tuples!(isize);
impl_merge_tuples!(usize);
impl_merge_tuples!(u32);
impl_merge_tuples!(u16);
impl_merge_tuples!(u8);
impl_merge_tuples!(i32);
impl_merge_tuples!(i16);
impl_merge_tuples!(i8);

#[test]
fn test_coalesce_empty() {
    let mut v = vec![];
    v.coalesce(0, (0, 1));
    assert_eq!(v, [(0, 1)]);
}

#[test]
fn test_coalesce_first() {
    let mut v = vec![(1, 1)];
    v.coalesce(0, (0, 1));
    assert_eq!(v, [(0, 1)])
}

#[test]
fn test_coalesce_last() {
    let mut v = vec![(1, 1)];
    v.coalesce(1, (1, 2));
    assert_eq!(v, [(1, 2)])
}

#[test]
fn test_coalesce_both() {
    let mut v = vec![(1, 1), (2, 2)];
    v.coalesce(1, (1, 2));
    assert_eq!(v, [(1, 2)])
}

#[test]
fn test_coalesce_none() {
    let mut v = vec![(1, 1), (3, 3)];
    v.coalesce(1, (2, 2));
    assert_eq!(v, [(1, 1), (2, 2), (3, 3)])
}

#[test]
fn test_coalesce_twice() {
    let mut v = vec![];
    v.coalesce(0, (0, 1));
    v.coalesce(0, (-2, -1));
    v.coalesce(1, (-1, 0));
    assert_eq!(v, [(-2, 1)]);
}

#[test]
fn test_search_and_coalesce() {
    let mut v = vec![];
    for el in vec![(0, 1), (-2, -1), (-1, 0)] {
        let index = v.binary_search(&el).err().unwrap();
        v.coalesce(index, el);
    }
    assert_eq!(v, [(-2, 1)]);
}

#[test]
fn test_coalesce_subrange() {
    let mut v = vec![(0, 3)];
    v.coalesce(1, (1, 2));
    assert_eq!(v, [(0, 3)]);
}

#[test]
fn test_search_coalesce() {
    let mut v = vec![(0, 1), (2, 3), (4, 5), (6, 7)];
    assert_eq!(2, v.search_coalesce(1, (4, 5)));
}

#[test]
fn test_search_coalesce_2() {
    let mut v = vec![(0, 1), (2, 3), (4, 5), (6, 7)];
    assert_eq!(3, v.search_coalesce(1, (5, 6)));
    assert_eq!(v, [(0, 1), (2, 3), (4, 7)]);
}
<|endoftext|>


<commit_before>use std::fmt;
use std::from_str::from_str;

use message::IrcMessage;
use watchers::base::{Bundler, BundlerTrigger, EventWatcher};
use event::{
    IrcEvent,
    IrcEventJoinBundle
};

pub type JoinResult = Result<JoinSuccess, JoinError>;

trait ChannelTargeted {
    fn get_channel(&self) -> &str;
}

impl ChannelTargeted for JoinResult {
    fn get_channel(&self) -> &str {
        match self {
            &Ok(ref join_succ) => join_succ.channel.as_slice(),
            &Err(ref join_err) => join_err.channel.as_slice()
        }
    }
}

#[deriving(Clone, Show)]
pub struct JoinSuccess {
    pub channel: String,
    pub nicks: Vec<String>,
    pub topic: Option<TopicMeta>,
}

#[deriving(Clone, Show)]
pub struct TopicMeta {
    pub text: String,
    pub set_at: u64,
    pub set_by: String,
}

impl TopicMeta {
    fn new(topic: &String, other: &BundlerTopicMeta) -> TopicMeta {
        TopicMeta {
            text: topic.clone(),
            set_at: other.set_at,
            set_by: other.set_by.clone(),
        }
    }
}

#[deriving(Clone, Show)]
pub struct JoinError {
    pub channel: String,
    pub errcode: i16,
    pub message: String
}

pub struct JoinBundlerTrigger;

impl JoinBundlerTrigger {
    pub fn new() -> JoinBundlerTrigger {
        JoinBundlerTrigger
    }
}

impl BundlerTrigger for JoinBundlerTrigger {
    fn on_message(&mut self, message: &IrcMessage) -> Vec<Box<Bundler+Send>> {
        let mut out = Vec::new();
        if message.command() == "JOIN" {
            let channel = message.get_args()[0];
            let bundler: Box<Bundler+Send> = box JoinBundler::new(channel);
            out.push(bundler);
        }
        out
    }
}

struct BundlerTopicMeta {
    set_by: String,
    set_at: u64,
}

impl BundlerTopicMeta {
    fn from_msg(msg: &IrcMessage) -> Option<BundlerTopicMeta> {
        let args = msg.get_args();
        match from_str(args[3]) {
            Some(set_at) => {
                Some(BundlerTopicMeta {
                    set_by: args[2].to_string(),
                    set_at: set_at,
                })
            },
            None => None
        }
    }
}

pub struct JoinBundler {
    channel: String,
    topic: Option<String>,
    topic_meta: Option<BundlerTopicMeta>,
    nicks: Option<Vec<String>>,
    state: i16,
    result: Option<JoinResult>,
}

impl JoinBundler {
    pub fn new(channel: &str) -> JoinBundler {
        JoinBundler {
            channel: String::from_str(channel),
            topic: None,
            topic_meta: None,
            nicks: Some(Vec::new()),
            state: 0,
            result: None
        }
    }

    fn accept_state0(&mut self, message: &IrcMessage) -> Option<i16> {
        let success = message.command() == "JOIN" &&
            *message.get_args()[0] == self.channel.as_slice();

        let failure = message.command() == "475" &&
            *message.get_args()[1] == self.channel.as_slice();

        if failure {
            self.result = Some(Err(JoinError {
                channel: String::from_str(self.channel.as_slice()),
                errcode: 0,
                message: String::from_str("")
            }));
        }

        match (success, failure) {
            (false, false) => None,
            (false, true) => Some(-1),
            (true, false) => Some(1),
            _ => panic!("invariant invalid")
        }
    }

    fn on_topic(&mut self, message: &IrcMessage) -> Option<i16> {
        self.topic = Some(message.get_args()[2].to_string());
        None
    }

    fn on_topic_meta(&mut self, message: &IrcMessage) -> Option<i16> {
        self.topic_meta = BundlerTopicMeta::from_msg(message);
        None
    }

    fn on_names(&mut self, message: &IrcMessage) -> Option<i16> {
        if let Some(nicks) = self.nicks.as_mut() {
            for nick in message.get_args()[3].split(' ') {
                nicks.push(nick.to_string());
            }
        }
        None
    }

    fn on_names_end(&mut self, _: &IrcMessage) -> Option<i16> {
        let topic = match (self.topic.as_ref(), self.topic_meta.as_ref()) {
            (Some(topic), Some(topic_meta)) => {
                Some(TopicMeta::new(topic, topic_meta))
            },
            _ => None
        };
        self.result = Some(Ok(JoinSuccess {
            channel: self.channel.clone(),
            nicks: self.nicks.take().unwrap(),
            topic: topic
        }));
        Some(2)
    }

    fn accept_state1(&mut self, message: &IrcMessage) -> Option<i16> {
        if message.command() == "332" {
            if message.get_args()[1] == self.channel.as_slice() {
                return self.on_topic(message);
            }
            return None;
        }
        if message.command() == "333" {
            if message.get_args()[1] == self.channel.as_slice() {
                return self.on_topic_meta(message);
            }
            return None;
        }
        if message.command() == "353" {
            assert!(match message.get_args()[1] {
                "=" => true,
                "*" => true,
                "@" => true,
                _ => false
            });
            if message.get_args()[2] == self.channel.as_slice() {
                return self.on_names(message);
            }
            return None;
        }
        if message.command() == "366" {
            if message.get_args()[1] == self.channel.as_slice() {
                return self.on_names_end(message);
            }
            return None;
        }
        None
    }
}

impl Bundler for JoinBundler {
    fn on_message(&mut self, message: &IrcMessage) -> Vec<IrcEvent> {
        let new_state = match self.state {
            0 => self.accept_state0(message),
            1 => self.accept_state1(message),
            _ => None
        };
        match new_state {
            Some(new_state) => {
                self.state = new_state;
            },
            None => ()
        }
        match self.result.take() {
            Some(result) => {
                vec![IrcEventJoinBundle(result)]
            },
            None => vec![]
        }
    }

    fn is_finished(&mut self) -> bool {
        self.state == -1 || self.state == 2
    }

}

impl fmt::Show for JoinBundler {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JoinBundler({})", self.channel.as_slice())
    }
}

/// Waits for target JoinBundleEvent and clones it down the monitor
pub struct JoinEventWatcher {
    channel: String,
    result: Option<JoinResult>,
    monitors: Vec<SyncSender<JoinResult>>,
    finished: bool
}

impl JoinEventWatcher {
    pub fn new(channel: &str) -> JoinEventWatcher {
        JoinEventWatcher {
            channel: String::from_str(channel),
            monitors: Vec::new(),
            result: None,
            finished: false
        }
    }

    fn dispatch_monitors(&mut self) {
        let result = self.result.clone().unwrap();
        for monitor in self.monitors.iter() {
            match monitor.try_send(result.clone()) {
                Ok(_) => (),
                Err(_) => panic!("sending failed")
            }
        }
        self.monitors = Vec::new();
    }

    fn add_monitor(&mut self, monitor: SyncSender<JoinResult>) {
        let result = self.result.clone();

        match result {
            Some(result) => monitor.send(result.clone()),
            None => self.monitors.push(monitor)
        }
    }

    pub fn get_monitor(&mut self) -> Receiver<JoinResult> {
        let (tx, rx) = sync_channel(1);
        self.add_monitor(tx);
        rx
    }
}

impl EventWatcher for JoinEventWatcher {
    fn on_event(&mut self, message: &IrcEvent) {
        match *message {
            IrcEventJoinBundle(ref result) => {
                if result.get_channel() == self.channel.as_slice() {
                    self.result = Some(result.clone());
                    self.dispatch_monitors();
                }
            },
            _ => ()
        }
        self.finished = true;
    }

    fn is_finished(&self) -> bool {
        false
    }

    fn get_name(&self) -> &'static str {
        "JoinEventWatcher"
    }
}

<commit_msg>Use enums instead of ints for join status<commit_after>use std::fmt;
use std::from_str::from_str;

use message::IrcMessage;
use watchers::base::{Bundler, BundlerTrigger, EventWatcher};
use event::{
    IrcEvent,
    IrcEventJoinBundle
};

pub type JoinResult = Result<JoinSuccess, JoinError>;

trait ChannelTargeted {
    fn get_channel(&self) -> &str;
}

impl ChannelTargeted for JoinResult {
    fn get_channel(&self) -> &str {
        match self {
            &Ok(ref join_succ) => join_succ.channel.as_slice(),
            &Err(ref join_err) => join_err.channel.as_slice()
        }
    }
}

#[deriving(Clone, Show)]
pub struct JoinSuccess {
    pub channel: String,
    pub nicks: Vec<String>,
    pub topic: Option<TopicMeta>,
}

#[deriving(Clone, Show)]
pub struct TopicMeta {
    pub text: String,
    pub set_at: u64,
    pub set_by: String,
}

impl TopicMeta {
    fn new(topic: &String, other: &BundlerTopicMeta) -> TopicMeta {
        TopicMeta {
            text: topic.clone(),
            set_at: other.set_at,
            set_by: other.set_by.clone(),
        }
    }
}

#[deriving(Clone, Show)]
pub struct JoinError {
    pub channel: String,
    pub errcode: i16,
    pub message: String
}

pub struct JoinBundlerTrigger;

impl JoinBundlerTrigger {
    pub fn new() -> JoinBundlerTrigger {
        JoinBundlerTrigger
    }
}

impl BundlerTrigger for JoinBundlerTrigger {
    fn on_message(&mut self, message: &IrcMessage) -> Vec<Box<Bundler+Send>> {
        let mut out = Vec::new();
        if message.command() == "JOIN" {
            let channel = message.get_args()[0];
            let bundler: Box<Bundler+Send> = box JoinBundler::new(channel);
            out.push(bundler);
        }
        out
    }
}

struct BundlerTopicMeta {
    set_by: String,
    set_at: u64,
}

impl BundlerTopicMeta {
    fn from_msg(msg: &IrcMessage) -> Option<BundlerTopicMeta> {
        let args = msg.get_args();
        match from_str(args[3]) {
            Some(set_at) => {
                Some(BundlerTopicMeta {
                    set_by: args[2].to_string(),
                    set_at: set_at,
                })
            },
            None => None
        }
    }
}

pub struct JoinBundler {
    channel: String,
    topic: Option<String>,
    topic_meta: Option<BundlerTopicMeta>,
    nicks: Option<Vec<String>>,
    state: JoinBundlerState,
    result: Option<JoinResult>,
}

enum JoinBundlerState {
    PreJoin,
    Joining,
    Joined,
    JoinFail
}

impl JoinBundler {
    pub fn new(channel: &str) -> JoinBundler {
        JoinBundler {
            channel: String::from_str(channel),
            topic: None,
            topic_meta: None,
            nicks: Some(Vec::new()),
            state: PreJoin,
            result: None
        }
    }

    fn accept_state_prejoin(&mut self, message: &IrcMessage) -> Option<JoinBundlerState> {
        let success = match message.command() {
            "JOIN" => {
                if *message.get_args()[0] != self.channel.as_slice() {
                    return None;
                }
                true
            },
            "475" => {
                if *message.get_args()[1] == self.channel.as_slice() {
                    return None;
                }
                false
            },
            _ => return None
        };

        if !success {
            self.result = Some(Err(JoinError {
                channel: String::from_str(self.channel.as_slice()),
                errcode: 0,
                message: String::from_str("")
            }));
        }
        Some(if success { Joining } else { JoinFail })
    }

    fn on_topic(&mut self, message: &IrcMessage) -> Option<JoinBundlerState> {
        self.topic = Some(message.get_args()[2].to_string());
        None
    }

    fn on_topic_meta(&mut self, message: &IrcMessage) -> Option<JoinBundlerState> {
        self.topic_meta = BundlerTopicMeta::from_msg(message);
        None
    }

    fn on_names(&mut self, message: &IrcMessage) -> Option<JoinBundlerState> {
        if let Some(nicks) = self.nicks.as_mut() {
            for nick in message.get_args()[3].split(' ') {
                nicks.push(nick.to_string());
            }
        }
        None
    }

    fn on_names_end(&mut self, _: &IrcMessage) -> Option<JoinBundlerState> {
        let topic = match (self.topic.as_ref(), self.topic_meta.as_ref()) {
            (Some(topic), Some(topic_meta)) => {
                Some(TopicMeta::new(topic, topic_meta))
            },
            _ => None
        };
        self.result = Some(Ok(JoinSuccess {
            channel: self.channel.clone(),
            nicks: self.nicks.take().unwrap(),
            topic: topic
        }));
        Some(Joined)
    }

    fn accept_state_joining(&mut self, message: &IrcMessage) -> Option<JoinBundlerState> {
        if message.command() == "332" {
            if message.get_args()[1] == self.channel.as_slice() {
                return self.on_topic(message);
            }
            return None;
        }
        if message.command() == "333" {
            if message.get_args()[1] == self.channel.as_slice() {
                return self.on_topic_meta(message);
            }
            return None;
        }
        if message.command() == "353" {
            assert!(match message.get_args()[1] {
                "=" => true,
                "*" => true,
                "@" => true,
                _ => false
            });
            if message.get_args()[2] == self.channel.as_slice() {
                return self.on_names(message);
            }
            return None;
        }
        if message.command() == "366" {
            if message.get_args()[1] == self.channel.as_slice() {
                return self.on_names_end(message);
            }
            return None;
        }
        None
    }
}

impl Bundler for JoinBundler {
    fn on_message(&mut self, message: &IrcMessage) -> Vec<IrcEvent> {
        let new_state = match self.state {
            PreJoin => self.accept_state_prejoin(message),
            Joining => self.accept_state_joining(message),
            _ => None
        };
        match new_state {
            Some(new_state) => {
                self.state = new_state;
            },
            None => ()
        }
        match self.result.take() {
            Some(result) => {
                vec![IrcEventJoinBundle(result)]
            },
            None => vec![]
        }
    }

    fn is_finished(&mut self) -> bool {
        match self.state {
            JoinFail | Joined => true,
            _ => false
        }
    }

}

impl fmt::Show for JoinBundler {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JoinBundler({})", self.channel.as_slice())
    }
}

/// Waits for target JoinBundleEvent and clones it down the monitor
pub struct JoinEventWatcher {
    channel: String,
    result: Option<JoinResult>,
    monitors: Vec<SyncSender<JoinResult>>,
    finished: bool
}

impl JoinEventWatcher {
    pub fn new(channel: &str) -> JoinEventWatcher {
        JoinEventWatcher {
            channel: String::from_str(channel),
            monitors: Vec::new(),
            result: None,
            finished: false
        }
    }

    fn dispatch_monitors(&mut self) {
        let result = self.result.clone().unwrap();
        for monitor in self.monitors.iter() {
            match monitor.try_send(result.clone()) {
                Ok(_) => (),
                Err(_) => panic!("sending failed")
            }
        }
        self.monitors = Vec::new();
    }

    fn add_monitor(&mut self, monitor: SyncSender<JoinResult>) {
        let result = self.result.clone();

        match result {
            Some(result) => monitor.send(result.clone()),
            None => self.monitors.push(monitor)
        }
    }

    pub fn get_monitor(&mut self) -> Receiver<JoinResult> {
        let (tx, rx) = sync_channel(1);
        self.add_monitor(tx);
        rx
    }
}

impl EventWatcher for JoinEventWatcher {
    fn on_event(&mut self, message: &IrcEvent) {
        match *message {
            IrcEventJoinBundle(ref result) => {
                if result.get_channel() == self.channel.as_slice() {
                    self.result = Some(result.clone());
                    self.dispatch_monitors();
                }
            },
            _ => ()
        }
        self.finished = true;
    }

    fn is_finished(&self) -> bool {
        false
    }

    fn get_name(&self) -> &'static str {
        "JoinEventWatcher"
    }
}

<|endoftext|>


<commit_before>use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::net::udp::UdpSocket;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

#[allow(dead_code)]
struct UtpPacketHeader {
    ver_type: u8, // ver: u4, type: u4
    extension: u8,
    connection_id: u16,
    timestamp_microseconds: u32,
    timestamp_difference_microseconds: u32,
    wnd_size: u32,
    seq_nr: u16,
    ack_nr: u16,
}

impl UtpPacketHeader {
    fn bytes(&self) -> &[u8] {
        unsafe {
            let buf: &[u8, ..20] = std::mem::transmute(self);
            return buf.as_slice();
        }
    }
}

fn connection_handler(stream: TcpStream) {
    let mut sock = stream;
    println!("New client {}", sock.peer_name().unwrap());

    // Read request
    let mut buf = [0, ..512];
    let mut count: uint = 0;

    match sock.read(buf) {
        Err(e) => { println!("Error detected! {}", e) }
        Ok(c) => {
            count = c;
            println!("Received {} bytes:", c);
            println!("{}", std::str::from_utf8(buf).unwrap());
        }
    }

    // Answer request
    match sock.write(buf.slice(0, count)) {
        _ => {}
    }

    println!("Gone!");
    drop(sock);

}

fn main() {
    let header = UtpPacketHeader {
        ver_type: 0 | 0 << 4,
        extension: 0,
        connection_id: 0,
        timestamp_microseconds: 0,
        timestamp_difference_microseconds: 0,
        wnd_size: 0,
        seq_nr: 0,
        ack_nr: 0,
    };

    let mut buf = [0, ..512];
    let mut sock = UdpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 }).unwrap();
    match sock.recvfrom(buf) {
        Ok((_, src)) => {
            let _ = sock.sendto(header.bytes(), src);
        }
        Err(_) => {}
    }
    drop(sock);
    return;
    // Create socket
    let socket = TcpListener::bind("127.0.0.1", 8080);

    // Listen for new connections
    let mut acceptor = socket.listen();

    // Spawn a new process for handling each incoming connection
    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("{}", e) }
            Ok(stream) => spawn(proc() { connection_handler(stream) })
        }
    }

    drop(acceptor);
}
<commit_msg>Implement and use UtpPacket.<commit_after>use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::net::udp::UdpSocket;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

#[allow(dead_code)]
struct UtpPacketHeader {
    ver_type: u8, // ver: u4, type: u4
    extension: u8,
    connection_id: u16,
    timestamp_microseconds: u32,
    timestamp_difference_microseconds: u32,
    wnd_size: u32,
    seq_nr: u16,
    ack_nr: u16,
}

impl UtpPacketHeader {
    fn bytes(&self) -> &[u8] {
        unsafe {
            let buf: &[u8, ..20] = std::mem::transmute(self);
            return buf.as_slice();
        }
    }

    fn len(&self) -> uint {
        return 24;
    }
}

#[allow(dead_code)]
struct UtpPacket {
    header: UtpPacketHeader,
    payload: Vec<u8>,
}

impl UtpPacket {
    fn bytes(&self) -> Vec<u8> {
        let mut buf: Vec<u8> = Vec::with_capacity(self.len());
        buf.push_all(self.header.bytes());
        buf.push_all(self.payload.as_slice());
        return buf;
    }

    fn len(&self) -> uint {
        self.header.len() + self.payload.len()
    }
}

fn connection_handler(stream: TcpStream) {
    let mut sock = stream;
    println!("New client {}", sock.peer_name().unwrap());

    // Read request
    let mut buf = [0, ..512];
    let mut count: uint = 0;

    match sock.read(buf) {
        Err(e) => { println!("Error detected! {}", e) }
        Ok(c) => {
            count = c;
            println!("Received {} bytes:", c);
            println!("{}", std::str::from_utf8(buf).unwrap());
        }
    }

    // Answer request
    match sock.write(buf.slice(0, count)) {
        _ => {}
    }

    println!("Gone!");
    drop(sock);

}

fn main() {
    let packet = UtpPacket {
        header: UtpPacketHeader {
            ver_type: 0 | 0 << 4,
            extension: 0,
            connection_id: 0,
            timestamp_microseconds: 0,
            timestamp_difference_microseconds: 0,
            wnd_size: 0,
            seq_nr: 0,
            ack_nr: 0,
        },
        payload: String::from_str("Hello\n").into_bytes(),
    };

    let mut buf = [0, ..512];
    let mut sock = UdpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 }).unwrap();
    match sock.recvfrom(buf) {
        Ok((_, src)) => {
            let _ = sock.sendto(packet.bytes().as_slice(), src);
        }
        Err(_) => {}
    }
    drop(sock);
    return;
    // Create socket
    let socket = TcpListener::bind("127.0.0.1", 8080);

    // Listen for new connections
    let mut acceptor = socket.listen();

    // Spawn a new process for handling each incoming connection
    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("{}", e) }
            Ok(stream) => spawn(proc() { connection_handler(stream) })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>use std::fs::{self, File};
use std::io::{BufRead, BufReader};

use bson::Bson;
use mongodb::{Client, CommandResult, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use rand;

fn timed_query(_client: Client, command_result: &CommandResult) {
    let duration = match command_result {
        &CommandResult::Success { duration, .. } => duration,
        _ => panic!("Command failed!")
    };

    // Sanity check
    assert!(duration >= 1500000000);

    // Technically not guaranteed, but since the query is running locally, it shouldn't even be close
    assert!(duration < 2000000000);
}

#[test]
fn command_duration() {
    let mut client = Client::connect("localhost", 27017).ok().expect("damn it!");
    let db = client.db("test");
    let coll = db.collection("event_hooks");
    coll.drop().unwrap();

    let docs = (1..4).map(|i| doc! { "_id" => i, "x" => (rand::random::<u8>() as u32) }).collect();
    coll.insert_many(docs, false, None).unwrap();
    client.add_completion_hook(timed_query).unwrap();

    let doc = doc! {
        "$where" => (Bson::JavaScriptCode("function() { sleep(500); }".to_owned()))
    };

    coll.find(Some(doc), None).unwrap();
}

#[test]
fn logging() {
    for file in fs::read_dir(".").unwrap() {
        if file.unwrap().file_name().eq("test_log.txt") {
            fs::remove_file("test_log.txt").unwrap();
        }
    }

    let client = Client::connect_with_log_file("localhost", 27017, "test_log.txt").unwrap();
    let db = client.db("test");
    let coll = db.collection("logging");
    coll.drop().unwrap();

    let doc1 = doc! { "_id" => 1 };
    let doc2 = doc! { "_id" => 2 };
    let doc3 = doc! { "_id" => 3 };

    coll.insert_one(doc1, None).unwrap();
    coll.insert_one(doc2, None).unwrap();
    coll.insert_one(doc3, None).unwrap();

    let filter = doc! {
        "_id" => { "$gt" => 1 }
    };

    coll.find(Some(filter), None).unwrap();

    let f = File::open("test_log.txt").unwrap();
    let mut file = BufReader::new(&f);
    let mut line = String::new();

    // Drop collection started
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.drop_collection 127.0.0.1:27017 STARTED: { drop: \"logging\" }\n", &line);

    // Drop collection completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.drop_collection 127.0.0.1:27017 COMPLETED: { ns: \"test.logging\", nIndexesWas: 1, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // First insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 1 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // First insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Second insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 2 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Second insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Third insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 3 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Third insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Find command started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.find 127.0.0.1:27017 STARTED: { find: \"logging\", filter: {  }, projection: {  }, skip: 0, limit: 0, batchSize: 20, sort: {  } }\n", &line);

    // Find command completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.find 127.0.0.1:27017 COMPLETED: { cursor: { id: 0, ns: \"test.logging\", firstBatch: [{ _id: 2 }, { _id: 3 }] }, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));
}
<commit_msg>removed extra newline<commit_after>use std::fs::{self, File};
use std::io::{BufRead, BufReader};

use bson::Bson;
use mongodb::{Client, CommandResult, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use rand;

fn timed_query(_client: Client, command_result: &CommandResult) {
    let duration = match command_result {
        &CommandResult::Success { duration, .. } => duration,
        _ => panic!("Command failed!")
    };

    // Sanity check
    assert!(duration >= 1500000000);

    // Technically not guaranteed, but since the query is running locally, it shouldn't even be close
    assert!(duration < 2000000000);
}

#[test]
fn command_duration() {
    let mut client = Client::connect("localhost", 27017).ok().expect("damn it!");
    let db = client.db("test");
    let coll = db.collection("event_hooks");
    coll.drop().unwrap();

    let docs = (1..4).map(|i| doc! { "_id" => i, "x" => (rand::random::<u8>() as u32) }).collect();
    coll.insert_many(docs, false, None).unwrap();
    client.add_completion_hook(timed_query).unwrap();

    let doc = doc! {
        "$where" => (Bson::JavaScriptCode("function() { sleep(500); }".to_owned()))
    };

    coll.find(Some(doc), None).unwrap();
}

#[test]
fn logging() {
    for file in fs::read_dir(".").unwrap() {
        if file.unwrap().file_name().eq("test_log.txt") {
            fs::remove_file("test_log.txt").unwrap();
        }
    }

    let client = Client::connect_with_log_file("localhost", 27017, "test_log.txt").unwrap();
    let db = client.db("test");
    let coll = db.collection("logging");
    coll.drop().unwrap();

    let doc1 = doc! { "_id" => 1 };
    let doc2 = doc! { "_id" => 2 };
    let doc3 = doc! { "_id" => 3 };

    coll.insert_one(doc1, None).unwrap();
    coll.insert_one(doc2, None).unwrap();
    coll.insert_one(doc3, None).unwrap();

    let filter = doc! {
        "_id" => { "$gt" => 1 }
    };

    coll.find(Some(filter), None).unwrap();

    let f = File::open("test_log.txt").unwrap();
    let mut file = BufReader::new(&f);
    let mut line = String::new();

    // Drop collection started
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.drop_collection 127.0.0.1:27017 STARTED: { drop: \"logging\" }\n", &line);

    // Drop collection completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.drop_collection 127.0.0.1:27017 COMPLETED: { ns: \"test.logging\", nIndexesWas: 1, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // First insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 1 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // First insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Second insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 2 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Second insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Third insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 3 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Third insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Find command started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.find 127.0.0.1:27017 STARTED: { find: \"logging\", filter: {  }, projection: {  }, skip: 0, limit: 0, batchSize: 20, sort: {  } }\n", &line);

    // Find command completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.find 127.0.0.1:27017 COMPLETED: { cursor: { id: 0, ns: \"test.logging\", firstBatch: [{ _id: 2 }, { _id: 3 }] }, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));
}
<|endoftext|>


<commit_before>use graph_algorithms::Graph;
use graph_algorithms::node_vec::NodeVec;
use graph::{BasicBlockIndex, FuncGraph};
use env::{Environment, Point};
use std::collections::BTreeMap;
use std::cmp;
use std::fmt;

/// A region is characterized by an entry point and a set of leaves.
/// The region contains all blocks B where:
/// - `entry dom B`
/// - and `exists leaf in leaves. B dom leaf`
#[derive(Clone, PartialEq, Eq)]
pub struct Region {
    entry: BasicBlockIndex,
    leaves: BTreeMap<BasicBlockIndex, usize>,
}

impl Region {
    pub fn with_point(point: Point) -> Self {
        // The minimal region containing point just has `point` as a tail.
        Self::new(point.block, Some(point))
    }

    pub fn new<I>(entry: BasicBlockIndex, leaves: I) -> Self
        where I: IntoIterator<Item = Point>
    {
        Region {
            entry: entry,
            leaves: leaves.into_iter()
                          .map(|p| (p.block, p.action))
                          .collect(),
        }
    }

    pub fn leaves(&self) -> Leaves {
        Leaves {
            iter: Box::new(self.leaves
                               .iter()
                               .map(|(&block, &action)| {
                                   Point {
                                       block: block,
                                       action: action,
                                   }
                               })),
        }
    }

    pub fn contains(&self, env: &Environment, point: Point) -> bool {
        log!("contains(self={:?}, point={:?})", self, point);

        // no leaves is the empty region, which contains no points
        if self.leaves.is_empty() {
            return false;
        }

        // point must be dominated by the entry
        if !env.dominators.is_dominated_by(point.block, self.entry) {
            log!("contains: {:?} not dominated by entry {:?}",
                 point.block,
                 self.entry);
            return false;
        }

        // point dominate one of the leaves; if it is in a tail block,
        // compare the actions, otherwise consult the dominator graph
        if let Some(&action) = self.leaves.get(&point.block) {
            log!("contains: {:?} is a tail upto {:?}", point.block, action);
            return point.action <= action;
        }
        log!("contains: comparing leaves");
        self.leaves
            .keys()
            .any(|&tail| env.dominators.is_dominated_by(tail, point.block))
    }

    pub fn add_point(&mut self, env: &Environment, point: Point) -> bool {
        log!("add_point(self={:?}, point={:?})", self, point);
        assert!(point.action < env.end_action(point.block));

        if self.contains(env, point) {
            return false;
        }

        // Update entry point to be the mutual dominator
        self.entry = env.dominators.mutual_dominator_node(self.entry, point.block);

        // Compute the minimal consistent region beginning at
        // `new_entry` that contains all the leaves and the new point.
        let mut rev_dfs = RevDfs::new(env, self.entry);
        for tail in self.leaves() {
            rev_dfs.walk(tail);
        }
        rev_dfs.walk(point);

        // Distill that into just the leaves and update our internal map.
        self.leaves.clear();
        let mut stack = vec![self.entry];
        while let Some(node) = stack.pop() {
            let upto_action = rev_dfs.contained[node];
            let end_action = env.end_action(node);

            log!("node {:?} contained up to action {:?} out of {:?}",
                 node,
                 upto_action,
                 end_action);

            assert!(upto_action <= end_action);
            if upto_action == end_action {
                // Block is fully contained; visit its children,
                // unless this is a leaf of the tree, in which case we
                // have to record is as one of our leaves.
                let children = env.dominator_tree.children(node);
                if children.is_empty() {
                    self.leaves.insert(node, upto_action - 1);
                } else {
                    stack.extend(children);
                }
                continue;
            }

            if upto_action == 0 {
                // Block is not contained at all. Stop walking.
                continue;
            }

            // Block is partially contained. Record as a tail but stop
            // walking.
            self.leaves.insert(node, upto_action - 1);
        }

        log!("add_point: leaves={:?}", self.leaves);
        assert!(self.contains(env, point));
        true
    }
}

struct RevDfs<'env, 'func: 'env, 'arena: 'func> {
    env: &'env Environment<'func, 'arena>,

    // for each block, stores the number of actions that are contained
    // in the set; hence a value of `0` means that a block is not
    // contained at all; a value of `1` means the first action is
    // contained but not any others; and a value of `N` where `N` is
    // the number of actions means the block is fully contained.
    contained: NodeVec<FuncGraph<'arena>, usize>,
    stack: Vec<BasicBlockIndex>,
    entry: BasicBlockIndex,
}

impl<'env, 'func, 'arena> RevDfs<'env, 'func, 'arena> {
    fn new(env: &'env Environment<'func, 'arena>, entry: BasicBlockIndex) -> Self {
        RevDfs {
            env: env,
            contained: NodeVec::from_default(env.graph),
            stack: vec![],
            entry: entry,
        }
    }

    fn walk(&mut self, mut start: Point) {
        log!("walk({:?})", start);
        assert!(self.env.dominators.is_dominated_by(start.block, self.entry));
        assert!(self.stack.is_empty());

        // convert `start` to be exclusive (one past the included point)
        start.action += 1;

        self.push(start);

        // Visit reachable predecessors, unless this is the region entry
        while let Some(p) = self.pop() {
            log!("walk: walking preds of {:?}", p);
            if p == self.entry {
                continue;
            }
            for pred_block in self.env.graph.predecessors(p) {
                self.push(self.env.end_point(pred_block));
            }
        }
    }

    fn push(&mut self, p: Point) {
        log!("push({:?})", p);
        if self.contained[p.block] > 0 {
            log!("push: already visited {:?} up to action {:?} out of {:?}, \
                  adjusting to {:?}",
                 p.block,
                 self.contained[p.block],
                 self.env.end_action(p.block),
                 cmp::max(p.action, self.contained[p.block]));
            self.contained[p.block] = cmp::max(p.action, self.contained[p.block]);
        } else {
            log!("push: enstacking {:?} up to action {:?}", p.block, p.action);
            self.contained[p.block] = p.action;
            self.stack.push(p.block); // still have to visit preds too
        }
    }

    fn pop(&mut self) -> Option<BasicBlockIndex> {
        self.stack.pop()
    }
}

pub struct Leaves<'iter> {
    iter: Box<Iterator<Item = Point> + 'iter>,
}

impl<'iter> Iterator for Leaves<'iter> {
    type Item = Point;

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

impl fmt::Debug for Region {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(fmt, "{{{:?} -> ", self.entry));
        for leaf in self.leaves() {
            try!(write!(fmt, "{:?}", leaf));
        }
        write!(fmt, "}}")
    }
}
<commit_msg>update comment more<commit_after>use graph_algorithms::Graph;
use graph_algorithms::node_vec::NodeVec;
use graph::{BasicBlockIndex, FuncGraph};
use env::{Environment, Point};
use std::collections::BTreeMap;
use std::cmp;
use std::fmt;

/// A region is characterized by an entry point and a set of leaves.
///
/// The region contains all blocks B where:
/// - `entry dom B`
/// - and `exists leaf in leaves. B dom leaf`.
///
/// To be valid, two conditions must be met:
/// - entry must dominate all leaves
/// - there must not exist an edge U->V in the graph where:
///   - V is in the region and not the entry
///   - but U is not
#[derive(Clone, PartialEq, Eq)]
pub struct Region {
    entry: BasicBlockIndex,
    leaves: BTreeMap<BasicBlockIndex, usize>,
}

impl Region {
    pub fn with_point(point: Point) -> Self {
        // The minimal region containing point just has `point` as a tail.
        Self::new(point.block, Some(point))
    }

    pub fn new<I>(entry: BasicBlockIndex, leaves: I) -> Self
        where I: IntoIterator<Item = Point>
    {
        Region {
            entry: entry,
            leaves: leaves.into_iter()
                          .map(|p| (p.block, p.action))
                          .collect(),
        }
    }

    pub fn leaves(&self) -> Leaves {
        Leaves {
            iter: Box::new(self.leaves
                               .iter()
                               .map(|(&block, &action)| {
                                   Point {
                                       block: block,
                                       action: action,
                                   }
                               })),
        }
    }

    pub fn contains(&self, env: &Environment, point: Point) -> bool {
        log!("contains(self={:?}, point={:?})", self, point);

        // no leaves is the empty region, which contains no points
        if self.leaves.is_empty() {
            return false;
        }

        // point must be dominated by the entry
        if !env.dominators.is_dominated_by(point.block, self.entry) {
            log!("contains: {:?} not dominated by entry {:?}",
                 point.block,
                 self.entry);
            return false;
        }

        // point dominate one of the leaves; if it is in a tail block,
        // compare the actions, otherwise consult the dominator graph
        if let Some(&action) = self.leaves.get(&point.block) {
            log!("contains: {:?} is a tail upto {:?}", point.block, action);
            return point.action <= action;
        }
        log!("contains: comparing leaves");
        self.leaves
            .keys()
            .any(|&tail| env.dominators.is_dominated_by(tail, point.block))
    }

    pub fn add_point(&mut self, env: &Environment, point: Point) -> bool {
        log!("add_point(self={:?}, point={:?})", self, point);
        assert!(point.action < env.end_action(point.block));

        if self.contains(env, point) {
            return false;
        }

        // Update entry point to be the mutual dominator
        self.entry = env.dominators.mutual_dominator_node(self.entry, point.block);

        // Compute the minimal consistent region beginning at
        // `new_entry` that contains all the leaves and the new point.
        let mut rev_dfs = RevDfs::new(env, self.entry);
        for tail in self.leaves() {
            rev_dfs.walk(tail);
        }
        rev_dfs.walk(point);

        // Distill that into just the leaves and update our internal map.
        self.leaves.clear();
        let mut stack = vec![self.entry];
        while let Some(node) = stack.pop() {
            let upto_action = rev_dfs.contained[node];
            let end_action = env.end_action(node);

            log!("node {:?} contained up to action {:?} out of {:?}",
                 node,
                 upto_action,
                 end_action);

            assert!(upto_action <= end_action);
            if upto_action == end_action {
                // Block is fully contained; visit its children,
                // unless this is a leaf of the tree, in which case we
                // have to record is as one of our leaves.
                let children = env.dominator_tree.children(node);
                if children.is_empty() {
                    self.leaves.insert(node, upto_action - 1);
                } else {
                    stack.extend(children);
                }
                continue;
            }

            if upto_action == 0 {
                // Block is not contained at all. Stop walking.
                continue;
            }

            // Block is partially contained. Record as a tail but stop
            // walking.
            self.leaves.insert(node, upto_action - 1);
        }

        log!("add_point: leaves={:?}", self.leaves);
        assert!(self.contains(env, point));
        true
    }
}

struct RevDfs<'env, 'func: 'env, 'arena: 'func> {
    env: &'env Environment<'func, 'arena>,

    // for each block, stores the number of actions that are contained
    // in the set; hence a value of `0` means that a block is not
    // contained at all; a value of `1` means the first action is
    // contained but not any others; and a value of `N` where `N` is
    // the number of actions means the block is fully contained.
    contained: NodeVec<FuncGraph<'arena>, usize>,
    stack: Vec<BasicBlockIndex>,
    entry: BasicBlockIndex,
}

impl<'env, 'func, 'arena> RevDfs<'env, 'func, 'arena> {
    fn new(env: &'env Environment<'func, 'arena>, entry: BasicBlockIndex) -> Self {
        RevDfs {
            env: env,
            contained: NodeVec::from_default(env.graph),
            stack: vec![],
            entry: entry,
        }
    }

    fn walk(&mut self, mut start: Point) {
        log!("walk({:?})", start);
        assert!(self.env.dominators.is_dominated_by(start.block, self.entry));
        assert!(self.stack.is_empty());

        // convert `start` to be exclusive (one past the included point)
        start.action += 1;

        self.push(start);

        // Visit reachable predecessors, unless this is the region entry
        while let Some(p) = self.pop() {
            log!("walk: walking preds of {:?}", p);
            if p == self.entry {
                continue;
            }
            for pred_block in self.env.graph.predecessors(p) {
                self.push(self.env.end_point(pred_block));
            }
        }
    }

    fn push(&mut self, p: Point) {
        log!("push({:?})", p);
        if self.contained[p.block] > 0 {
            log!("push: already visited {:?} up to action {:?} out of {:?}, \
                  adjusting to {:?}",
                 p.block,
                 self.contained[p.block],
                 self.env.end_action(p.block),
                 cmp::max(p.action, self.contained[p.block]));
            self.contained[p.block] = cmp::max(p.action, self.contained[p.block]);
        } else {
            log!("push: enstacking {:?} up to action {:?}", p.block, p.action);
            self.contained[p.block] = p.action;
            self.stack.push(p.block); // still have to visit preds too
        }
    }

    fn pop(&mut self) -> Option<BasicBlockIndex> {
        self.stack.pop()
    }
}

pub struct Leaves<'iter> {
    iter: Box<Iterator<Item = Point> + 'iter>,
}

impl<'iter> Iterator for Leaves<'iter> {
    type Item = Point;

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

impl fmt::Debug for Region {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(fmt, "{{{:?} -> ", self.entry));
        for leaf in self.leaves() {
            try!(write!(fmt, "{:?}", leaf));
        }
        write!(fmt, "}}")
    }
}
<|endoftext|>