<commit_before>mod samplers;
mod utils;
mod filters;
mod config;

use std::{fmt, mem};
use std::sync::Mutex;
use simple_parallel;

use color::Color;
use utils::datastructures::Matrix;
use geom::{UnitVector, Dot, Ray};
use scene::{Intersection, Scene, Texture};
use utils::time_it;
use self::filters::Filter;
use self::samplers::{Sample, Sampler, StratifiedSampler};

pub use self::config::TracerConfig;

pub type Pixel = [u32; 2];

pub type Image = Matrix<Color>;

pub struct TracingStats {
    pub rendering_time: f64,
    pub filtering_time: f64
}

impl fmt::Display for TracingStats {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "Rendering:   {:.2}s\nFiltering:   {:.2}s",
               self.rendering_time, self.filtering_time)
    }

}

pub struct Tracer {
    scene: Scene,
    sampler: Box<Sampler>,
    filter: Box<Filter>,
    n_reflections: u32,
    n_threads: u16,
}

impl Tracer {
    pub fn new(scene: Scene, config: TracerConfig) -> Tracer {
        Tracer {
            scene: scene,
            sampler: Box::new(StratifiedSampler::new(config.resolution, config.sampler)),
            filter: Box::new(Filter::new(config.resolution, config.filter)),
            n_reflections: config.n_reflections,
            n_threads: config.n_threads.unwrap_or(8),
        }
    }

    pub fn render(&self) -> (Image, TracingStats) {
        let samplers = self.sampler.split(self.n_threads * 10);
        let (results, rendering_time) = time_it(|| {
            let results = Mutex::new(Vec::new());
            let mut pool = simple_parallel::Pool::new(self.n_threads as usize);
            pool.for_(samplers, |sampler| {
                let r = self.render_samples(&sampler.sample());
                results.lock().unwrap().extend(r.into_iter());
            });
            let mut guard = results.lock().unwrap();
            mem::replace(&mut *guard, Vec::new())
        });

        let (image, filtering_time) = time_it(|| self.filter.apply(&results));
        (image, TracingStats {rendering_time: rendering_time,
                              filtering_time: filtering_time})
    }

    fn render_samples(&self, samples: &[Sample]) -> Vec<(Sample, Color)> {
        samples.into_iter()
            .map(|&s| {
                let ray = self.scene.camera.cast_ray(s.pixel);
                (s, self.radiace(&ray, 0))
            }).collect()
    }

    pub fn radiace(&self, ray: &Ray, level: u32) -> Color {
        match self.scene.find_obstacle(ray) {
            Some(ref intersection) => {
                let arrived_light = self.colorize(ray.direction, intersection);
                let reflectance = intersection.material.reflectance;
                let has_reflection = level < self.n_reflections
                    && reflectance > 0.0;
                let reflected_light = if has_reflection  {
                    let refl_dir = ray.direction.reflect(intersection.geom.normal);
                    let reflected_ray = self.scene.ray_from(intersection, refl_dir);
                    self.radiace(&reflected_ray, level + 1) * reflectance
                } else {
                    Color::new(0.0, 0.0, 0.0)
                };

                arrived_light + reflected_light
            },
            None => self.scene.background_color
        }
    }

    fn colorize(&self, view_direction: UnitVector, intersection: &Intersection) -> Color {
        let mut result = intersection.colorize_ambient(self.scene.ambient_light);
        let visible_lights = self.scene.lights.iter()
            .filter(|&light| self.scene.is_visible(light.position(), &intersection));

        for light in visible_lights {
            let light_direction = light.position().direction_to(intersection.geom.point);
            let illumination = light.illuminate(intersection.geom.point);
            result = result
                + intersection.colorize_diffuse(illumination, light_direction)
                + intersection.colorize_specular(illumination, light_direction, view_direction);
        }
        result
    }
}

trait IntersectionExt {
    fn colorize_ambient(&self, illumination: Color) -> Color;

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color;

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color;
}

impl<'a> IntersectionExt for Intersection<'a> {
    fn colorize_ambient(&self, illumination: Color) -> Color {
        self.material.color.at(&self.geom) * illumination
    }

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color {

        let k = (-light_direction.dot(self.geom.normal)).max(0.0) * self.material.diffuse;
        self.material.color.at(&self.geom) * illumination * k
    }

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color {

        let r = light_direction.reflect(self.geom.normal);
        let k = (-r.dot(view_direction)).max(0.0).powf(self.material.specular);
        illumination * k
    }
}
<commit_msg>name constants<commit_after>mod samplers;
mod utils;
mod filters;
mod config;

use std::{fmt, mem};
use std::sync::Mutex;
use simple_parallel;

use color::Color;
use utils::datastructures::Matrix;
use geom::{UnitVector, Dot, Ray};
use scene::{Intersection, Scene, Texture};
use utils::time_it;
use self::filters::Filter;
use self::samplers::{Sample, Sampler, StratifiedSampler};

pub use self::config::TracerConfig;

pub type Pixel = [u32; 2];

pub type Image = Matrix<Color>;

pub struct TracingStats {
    pub rendering_time: f64,
    pub filtering_time: f64
}

impl fmt::Display for TracingStats {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "Rendering:   {:.2}s\nFiltering:   {:.2}s",
               self.rendering_time, self.filtering_time)
    }

}

pub struct Tracer {
    scene: Scene,
    sampler: Box<Sampler>,
    filter: Box<Filter>,
    n_reflections: u32,
    n_threads: u16,
}

const THREAD_NUMBER: u16 = 8;
const BLOCKS_PER_THREAD: u16 = 20;

impl Tracer {
    pub fn new(scene: Scene, config: TracerConfig) -> Tracer {
        Tracer {
            scene: scene,
            sampler: Box::new(StratifiedSampler::new(config.resolution, config.sampler)),
            filter: Box::new(Filter::new(config.resolution, config.filter)),
            n_reflections: config.n_reflections,
            n_threads: config.n_threads.unwrap_or(THREAD_NUMBER),
        }
    }

    pub fn render(&self) -> (Image, TracingStats) {
        let samplers = self.sampler.split(self.n_threads * BLOCKS_PER_THREAD);
        let (results, rendering_time) = time_it(|| {
            let results = Mutex::new(Vec::new());
            let mut pool = simple_parallel::Pool::new(self.n_threads as usize);
            pool.for_(samplers, |sampler| {
                let r = self.render_samples(&sampler.sample());
                results.lock().unwrap().extend(r.into_iter());
            });
            let mut guard = results.lock().unwrap();
            mem::replace(&mut *guard, Vec::new())
        });

        let (image, filtering_time) = time_it(|| self.filter.apply(&results));
        (image, TracingStats {rendering_time: rendering_time,
                              filtering_time: filtering_time})
    }

    fn render_samples(&self, samples: &[Sample]) -> Vec<(Sample, Color)> {
        samples.into_iter()
            .map(|&s| {
                let ray = self.scene.camera.cast_ray(s.pixel);
                (s, self.radiace(&ray, 0))
            }).collect()
    }

    pub fn radiace(&self, ray: &Ray, level: u32) -> Color {
        match self.scene.find_obstacle(ray) {
            Some(ref intersection) => {
                let arrived_light = self.colorize(ray.direction, intersection);
                let reflectance = intersection.material.reflectance;
                let has_reflection = level < self.n_reflections
                    && reflectance > 0.0;
                let reflected_light = if has_reflection  {
                    let refl_dir = ray.direction.reflect(intersection.geom.normal);
                    let reflected_ray = self.scene.ray_from(intersection, refl_dir);
                    self.radiace(&reflected_ray, level + 1) * reflectance
                } else {
                    Color::new(0.0, 0.0, 0.0)
                };

                arrived_light + reflected_light
            },
            None => self.scene.background_color
        }
    }

    fn colorize(&self, view_direction: UnitVector, intersection: &Intersection) -> Color {
        let mut result = intersection.colorize_ambient(self.scene.ambient_light);
        let visible_lights = self.scene.lights.iter()
            .filter(|&light| self.scene.is_visible(light.position(), &intersection));

        for light in visible_lights {
            let light_direction = light.position().direction_to(intersection.geom.point);
            let illumination = light.illuminate(intersection.geom.point);
            result = result
                + intersection.colorize_diffuse(illumination, light_direction)
                + intersection.colorize_specular(illumination, light_direction, view_direction);
        }
        result
    }
}

trait IntersectionExt {
    fn colorize_ambient(&self, illumination: Color) -> Color;

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color;

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color;
}

impl<'a> IntersectionExt for Intersection<'a> {
    fn colorize_ambient(&self, illumination: Color) -> Color {
        self.material.color.at(&self.geom) * illumination
    }

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color {

        let k = (-light_direction.dot(self.geom.normal)).max(0.0) * self.material.diffuse;
        self.material.color.at(&self.geom) * illumination * k
    }

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color {

        let r = light_direction.reflect(self.geom.normal);
        let k = (-r.dot(view_direction)).max(0.0).powf(self.material.specular);
        illumination * k
    }
}
<|endoftext|>


<commit_before>#![cfg(windows)]

extern crate libc;
extern crate winapi;
extern crate "kernel32-sys" as kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;
use std::io::IoError;

extern "system" {
    fn CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE) -> HANDLE;
    fn ReadFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
    fn WriteFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
}

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    conin: HANDLE,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            // Unlike in Linux, we *could* use the default stdin/stdout file handles to talk
            // directly to the console. However, we need the default stdin handle for the list of
            // choices, and we need to write just the final selection to stdout. Therefore we have
            // to explicitly create new handles to talk to the console. The gory details are
            // available at:
            //
            // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075%28v=vs.85%29.aspx
            // http://stackoverflow.com/questions/377152/what-does-createfileconin-do
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            conin: conin,
            conout: conout,
        }
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in range(0, self.height) {
            self.write(blank_line.as_slice());
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteFile(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
        let mut chars_read: DWORD = 0;
        win32!(ReadFile(self.conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));

        let mut ret = Vec::new();
        for i in range(0, chars_read) {
            ret.push(Screen::translate_byte(buf[i as usize]));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conin: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conin, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    let conout = unsafe { kernel32::GetStdHandle(-11) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<commit_msg>Remove unused import<commit_after>#![cfg(windows)]

extern crate libc;
extern crate winapi;
extern crate "kernel32-sys" as kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

extern "system" {
    fn CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE) -> HANDLE;
    fn ReadFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
    fn WriteFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
}

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    conin: HANDLE,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            // Unlike in Linux, we *could* use the default stdin/stdout file handles to talk
            // directly to the console. However, we need the default stdin handle for the list of
            // choices, and we need to write just the final selection to stdout. Therefore we have
            // to explicitly create new handles to talk to the console. The gory details are
            // available at:
            //
            // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075%28v=vs.85%29.aspx
            // http://stackoverflow.com/questions/377152/what-does-createfileconin-do
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            conin: conin,
            conout: conout,
        }
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in range(0, self.height) {
            self.write(blank_line.as_slice());
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteFile(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
        let mut chars_read: DWORD = 0;
        win32!(ReadFile(self.conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));

        let mut ret = Vec::new();
        for i in range(0, chars_read) {
            ret.push(Screen::translate_byte(buf[i as usize]));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conin: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conin, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    let conout = unsafe { kernel32::GetStdHandle(-11) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<|endoftext|>


<commit_before>use ast::*;
use ast::Stmt::*;
use ast::visit::*;
use ctxt::{Context, FctId, FctSrc};
use error::msg::Msg;
use semck;
use ty::BuiltinType;

pub fn check<'a, 'ast>(ctxt: &Context<'ast>) {
    let last = ctxt.fcts.len();

    for id in 0..last {
        let id = FctId(id);

        let ast = {
            let fct = ctxt.fcts[id].borrow();
            if !fct.is_src() && !fct.kind.is_definition() {
                continue;
            }

            fct.ast
        };

        {
            for p in &ast.params {
                let ty = semck::read_type(ctxt, &p.data_type).unwrap_or(BuiltinType::Unit);

                let mut fct = ctxt.fcts[id].borrow_mut();
                fct.param_types.push(ty);

                if fct.is_src() {
                    let src = fct.src();
                    let mut src = src.lock().unwrap();

                    let var = *src.map_vars.get(p.id).unwrap();
                    src.vars[var].ty = ty;
                }
            }

            if let Some(ret) = ast.return_type.as_ref() {
                let ty = semck::read_type(ctxt, ret).unwrap_or(BuiltinType::Unit);
                let mut fct = ctxt.fcts[id].borrow_mut();
                fct.return_type = ty;
            }
        }

        let src = {
            let fct = ctxt.fcts[id].borrow();
            if !fct.is_src() {
                continue;
            }

            fct.src()
        };

        let mut src = src.lock().unwrap();

        let mut defck = FctDefCheck {
            ctxt: ctxt,
            fct_id: id,
            src: &mut src,
            ast: ast,
            current_type: BuiltinType::Unit,
        };

        defck.check();
    }
}

struct FctDefCheck<'a, 'ast: 'a> {
    ctxt: &'a Context<'ast>,
    fct_id: FctId,
    src: &'a mut FctSrc<'ast>,
    ast: &'ast Function,
    current_type: BuiltinType,
}

impl<'a, 'ast> FctDefCheck<'a, 'ast> {
    fn check(&mut self) {
        self.visit_fct(self.ast);

        if self.ctxt.diag.borrow().has_errors() {
            return;
        }

        let mut fct = self.ctxt.fcts[self.fct_id].borrow_mut();
        fct.initialized = true;

        if let Some(clsid) = fct.owner_class {
            let cls = self.ctxt.classes[clsid].borrow();

            for &method in &cls.methods {
                if method == fct.id {
                    continue;
                }
                let method = self.ctxt.fcts[method].borrow();

                if method.initialized && method.name == fct.name &&
                   method.params_without_self() == fct.params_without_self() {
                    let cls_name = BuiltinType::Class(clsid).name(self.ctxt);
                    let param_names = method.params_without_self()
                        .iter()
                        .map(|a| a.name(self.ctxt))
                        .collect::<Vec<String>>();
                    let method_name = self.ctxt.interner.str(method.name).to_string();

                    let msg = Msg::MethodExists(cls_name, method_name, param_names, method.pos);
                    self.ctxt.diag.borrow_mut().report(self.ast.pos, msg);
                    return;
                }
            }
        }
    }
}

impl<'a, 'ast> Visitor<'ast> for FctDefCheck<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        self.visit_stmt(f.block());
    }

    fn visit_stmt(&mut self, s: &'ast Stmt) {
        match *s {
            StmtVar(ref var) => {
                if let Some(ref data_type) = var.data_type {
                    self.visit_type(data_type);

                    let varid = *self.src.map_vars.get(var.id).unwrap();
                    self.src.vars[varid].ty = self.current_type;
                }

                if let Some(ref expr) = var.expr {
                    visit::walk_expr(self, expr);
                }

            }

            StmtDo(ref try) => {
                for catch in &try.catch_blocks {
                    self.visit_type(&catch.data_type);
                    self.src.set_ty(catch.id, self.current_type);

                    let var = *self.src.map_vars.get(catch.id).unwrap();
                    self.src.vars[var].ty = self.current_type;

                    if !self.current_type.reference_type() {
                        let ty = self.current_type.name(self.ctxt);
                        self.ctxt
                            .diag
                            .borrow_mut()
                            .report(catch.data_type.pos(), Msg::ReferenceTypeExpected(ty));
                    }
                }

                if try.catch_blocks.is_empty() && try.finally_block.is_none() {
                    self.ctxt.diag.borrow_mut().report(try.pos, Msg::CatchOrFinallyExpected);
                }

                visit::walk_stmt(self, s);
            }

            _ => visit::walk_stmt(self, s),
        }
    }

    fn visit_type(&mut self, t: &'ast Type) {
        self.current_type = semck::read_type(self.ctxt, t).unwrap_or(BuiltinType::Unit);
    }
}
<commit_msg>fctdefck: make use of Fct-RefCell<commit_after>use ast::*;
use ast::Stmt::*;
use ast::visit::*;
use ctxt::{Context, Fct, FctSrc};
use error::msg::Msg;
use semck;
use ty::BuiltinType;

pub fn check<'a, 'ast>(ctxt: &Context<'ast>) {
    for fct in &ctxt.fcts {
        let mut fct = fct.borrow_mut();
        let ast = fct.ast;

        if !fct.is_src() && !fct.kind.is_definition() {
            continue;
        }

        for p in &ast.params {
            let ty = semck::read_type(ctxt, &p.data_type).unwrap_or(BuiltinType::Unit);
            fct.param_types.push(ty);

            if fct.is_src() {
                let src = fct.src();
                let mut src = src.lock().unwrap();

                let var = *src.map_vars.get(p.id).unwrap();
                src.vars[var].ty = ty;
            }
        }

        if let Some(ret) = ast.return_type.as_ref() {
            let ty = semck::read_type(ctxt, ret).unwrap_or(BuiltinType::Unit);
            fct.return_type = ty;
        }

        if !fct.is_src() {
            continue;
        }

        let src = fct.src();
        let mut src = src.lock().unwrap();

        let mut defck = FctDefCheck {
            ctxt: ctxt,
            fct: &mut *fct,
            src: &mut src,
            ast: ast,
            current_type: BuiltinType::Unit,
        };

        defck.check();
    }
}

struct FctDefCheck<'a, 'ast: 'a> {
    ctxt: &'a Context<'ast>,
    fct: &'a mut Fct<'ast>,
    src: &'a mut FctSrc<'ast>,
    ast: &'ast Function,
    current_type: BuiltinType,
}

impl<'a, 'ast> FctDefCheck<'a, 'ast> {
    fn check(&mut self) {
        self.visit_fct(self.ast);

        if self.ctxt.diag.borrow().has_errors() {
            return;
        }

        self.fct.initialized = true;

        if let Some(clsid) = self.fct.owner_class {
            let cls = self.ctxt.classes[clsid].borrow();

            for &method in &cls.methods {
                if method == self.fct.id {
                    continue;
                }
                let method = self.ctxt.fcts[method].borrow();

                if method.initialized && method.name == self.fct.name &&
                   method.params_without_self() == self.fct.params_without_self() {
                    let cls_name = BuiltinType::Class(clsid).name(self.ctxt);
                    let param_names = method.params_without_self()
                        .iter()
                        .map(|a| a.name(self.ctxt))
                        .collect::<Vec<String>>();
                    let method_name = self.ctxt.interner.str(method.name).to_string();

                    let msg = Msg::MethodExists(cls_name, method_name, param_names, method.pos);
                    self.ctxt.diag.borrow_mut().report(self.ast.pos, msg);
                    return;
                }
            }
        }
    }
}

impl<'a, 'ast> Visitor<'ast> for FctDefCheck<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        self.visit_stmt(f.block());
    }

    fn visit_stmt(&mut self, s: &'ast Stmt) {
        match *s {
            StmtVar(ref var) => {
                if let Some(ref data_type) = var.data_type {
                    self.visit_type(data_type);

                    let varid = *self.src.map_vars.get(var.id).unwrap();
                    self.src.vars[varid].ty = self.current_type;
                }

                if let Some(ref expr) = var.expr {
                    visit::walk_expr(self, expr);
                }

            }

            StmtDo(ref try) => {
                for catch in &try.catch_blocks {
                    self.visit_type(&catch.data_type);
                    self.src.set_ty(catch.id, self.current_type);

                    let var = *self.src.map_vars.get(catch.id).unwrap();
                    self.src.vars[var].ty = self.current_type;

                    if !self.current_type.reference_type() {
                        let ty = self.current_type.name(self.ctxt);
                        self.ctxt
                            .diag
                            .borrow_mut()
                            .report(catch.data_type.pos(), Msg::ReferenceTypeExpected(ty));
                    }
                }

                if try.catch_blocks.is_empty() && try.finally_block.is_none() {
                    self.ctxt.diag.borrow_mut().report(try.pos, Msg::CatchOrFinallyExpected);
                }

                visit::walk_stmt(self, s);
            }

            _ => visit::walk_stmt(self, s),
        }
    }

    fn visit_type(&mut self, t: &'ast Type) {
        self.current_type = semck::read_type(self.ctxt, t).unwrap_or(BuiltinType::Unit);
    }
}
<|endoftext|>


<commit_before>//! Types for the Global Descriptor Table and segment selectors.

use bit_field::BitField;
use core::fmt;
use PrivilegeLevel;

/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
/// with some additional flags).
///
/// See Intel 3a, Section 3.4.2 "Segment Selectors"
pub struct SegmentSelector(pub u16);

impl SegmentSelector {
    /// Creates a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index`: index in GDT or LDT array (not the offset)
    ///  * `rpl`: the requested privilege level
    pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
        SegmentSelector(index << 3 | (rpl as u16))
    }

    /// Returns the GDT index.
    pub fn index(&self) -> u16 {
        self.0 >> 3
    }

    /// Returns the requested privilege level.
    pub fn rpl(&self) -> PrivilegeLevel {
        PrivilegeLevel::from_u16(self.0.get_bits(0..2))
    }
}

impl fmt::Debug for SegmentSelector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("SegmentSelector");
        s.field("index", &self.index());
        s.field("rpl", &self.rpl());
        s.finish()
    }
}
<commit_msg>Add basic types for GDT and GDT descriptors<commit_after>//! Types for the Global Descriptor Table and segment selectors.

use bit_field::BitField;
use core::fmt;
use structures::tss::TaskStateSegment;
use PrivilegeLevel;

/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
/// with some additional flags).
///
/// See Intel 3a, Section 3.4.2 "Segment Selectors"
pub struct SegmentSelector(pub u16);

impl SegmentSelector {
    /// Creates a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index`: index in GDT or LDT array (not the offset)
    ///  * `rpl`: the requested privilege level
    pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
        SegmentSelector(index << 3 | (rpl as u16))
    }

    /// Returns the GDT index.
    pub fn index(&self) -> u16 {
        self.0 >> 3
    }

    /// Returns the requested privilege level.
    pub fn rpl(&self) -> PrivilegeLevel {
        PrivilegeLevel::from_u16(self.0.get_bits(0..2))
    }
}

impl fmt::Debug for SegmentSelector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("SegmentSelector");
        s.field("index", &self.index());
        s.field("rpl", &self.rpl());
        s.finish()
    }
}

pub struct GlobalDescriptorTable {
    table: [u64; 8],
    next_free: usize,
}

impl GlobalDescriptorTable {
    pub fn new() -> GlobalDescriptorTable {
        GlobalDescriptorTable {
            table: [0; 8],
            next_free: 1,
        }
    }

    pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
        let index = match entry {
            Descriptor::UserSegment(value) => self.push(value),
            Descriptor::SystemSegment(value_low, value_high) => {
                let index = self.push(value_low);
                self.push(value_high);
                index
            }
        };
        SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
    }

    pub fn load(&'static self) {
        use core::mem::size_of;
        use instructions::tables::{lgdt, DescriptorTablePointer};

        let ptr = DescriptorTablePointer {
            base: self.table.as_ptr() as u64,
            limit: (self.table.len() * size_of::<u64>() - 1) as u16,
        };

        unsafe { lgdt(&ptr) };
    }

    fn push(&mut self, value: u64) -> usize {
        if self.next_free < self.table.len() {
            let index = self.next_free;
            self.table[index] = value;
            self.next_free += 1;
            index
        } else {
            panic!("GDT full");
        }
    }
}

pub enum Descriptor {
    UserSegment(u64),
    SystemSegment(u64, u64),
}

bitflags! {
    pub struct DescriptorFlags: u64 {
        const CONFORMING        = 1 << 42;
        const EXECUTABLE        = 1 << 43;
        const USER_SEGMENT      = 1 << 44;
        const PRESENT           = 1 << 47;
        const LONG_MODE         = 1 << 53;
    }
}

impl Descriptor {
    pub fn kernel_code_segment() -> Descriptor {
        use self::DescriptorFlags as Flags;

        let flags = Flags::USER_SEGMENT | Flags::PRESENT | Flags::EXECUTABLE | Flags::LONG_MODE;
        Descriptor::UserSegment(flags.bits())
    }

    pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor {
        use self::DescriptorFlags as Flags;
        use bit_field::BitField;
        use core::mem::size_of;

        let ptr = tss as *const _ as u64;

        let mut low = Flags::PRESENT.bits();
        // base
        low.set_bits(16..40, ptr.get_bits(0..24));
        low.set_bits(56..64, ptr.get_bits(24..32));
        // limit (the `-1` in needed since the bound is inclusive)
        low.set_bits(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
        // type (0b1001 = available 64-bit tss)
        low.set_bits(40..44, 0b1001);

        let mut high = 0;
        high.set_bits(0..32, ptr.get_bits(32..64));

        Descriptor::SystemSegment(low, high)
    }
}
<|endoftext|>


<commit_before>//! This is the Buffer module for Xtensis.

// This file is part of Xtensis.

// This is the Xtensis text editor; it edits text.
// Copyright (C) 2016-2017  The Xtensis Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

extern crate slog;
extern crate slog_scope;

use std::path::PathBuf;

use server::gapbuffer::GapBuffer;
use utils::uuid;
use slog::Logger;

/// Struct for a Buffer in Xtensis
/// This stores metadata about a buffer.
#[derive(Debug)]
pub struct Buffer {
    /// UUID of a buffer.
    pub buf_uuid: String,
    /// File path of a buffer.
    pub file_path: Option<PathBuf>,
    /// Active status of a buffer.
    pub active: bool,
    /// Temporary status of a buffer.
    pub temporary: bool,
    /// If a buffer is r/o.
    /// If this is `true`, then r/w is `false.`
    /// Likewise, if this is `false`, then r/w is `true.
    pub read_only: bool,
    /// Major mode of a buffer
    pub major_mode: &'static str,
    /// Vector of Minor modes in a buffer
    pub minor_modes: Vec<&'static str>,
    /// Dirty status of a buffer
    pub dirty: bool,
    /// Contents of a buffer.
    pub text: GapBuffer<u8>,
    /// Logger of a buffer.
    pub logger: Logger,
}

impl Buffer {
    /// Return a new instance of `Buffer`.
    pub fn new() -> Buffer {
        let buf_logger = slog_scope::logger().new(o!("module" =>
                                                     "buffer"));

        slog_scope::scope(buf_logger.clone(), || {
            warn!("The buffer is being created!!");
        });

        trace!("Initialising logger..");
        Buffer {
            buf_uuid: uuid::get_uuid_buffer(),
            file_path: None,
            active: false,
            temporary: false,
            read_only: false,
            major_mode: "fundamental-mode",
            minor_modes: Vec::new(),
            dirty: false,
            text: GapBuffer::new(),
            logger: buf_logger,
        }
    }

    /// Return true if a buffer is active.
    /// That is to say, a 'focused' buffer, or otherwise in-use, and
    /// *not* inactive.
    /// If it's not a active buffer, then return false.
    pub fn is_active(&self) -> bool {
        self.active
    }

    /// Return true if a buffer is temporary.
    /// If it's not a temporary buffer, then return false.
    /// A temporary buffer is defined by the characteristic of having
    /// no 'target' to save to.
    pub fn is_temporary(&self) -> bool {
        self.temporary
    }

    /// Return true if a buffer is read only.

    /// If it's not read-only, then it returns false, and the buffer
    /// will be presumed to be read-write.

    /// A read-only buffer is defined by the characteristic of the FS
    /// denying write access, or being set manually.
    pub fn is_ro(&self) -> bool {
        self.read_only
    }

    /// Return true if a buffer is dirty.
    /// If it's not dirty, then return false.
    /// A dirty buffer is defined by the characteristic of the buffer
    /// having changed since the last save.
    /// Temporary buffers are *exempt* from this field.
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Return the current major mode of a buffer.
    pub fn get_major_mode(&self) -> &str {
        self.major_mode
    }

    /// Return a `Vec<&'static str>` of minor modes.
    pub fn get_minor_modes(&self) -> Vec<&'static str> {
        self.minor_modes.clone()
    }

    /// Return the length of a buffer.
    pub fn get_buffer_length(&self) -> usize {
        self.text.len()
    }
}

impl Default for Buffer {
    fn default() -> Buffer {
        Buffer::new()
    }
}

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

    #[test]
    fn test_buffer_default_values() {
        let buf = Buffer::new();

        assert_eq!(None, buf.file_path);
        assert_eq!(false, buf.active);
        assert_eq!(false, buf.is_active());

        assert_eq!(false, buf.temporary);
        assert_eq!(false, buf.is_temporary());

        assert_eq!(false, buf.read_only);
        assert_eq!(false, buf.is_ro());

        assert_eq!("fundamental-mode", buf.major_mode);
        assert_eq!(false, buf.dirty);
    }

    #[test]
    fn test_buffer_major_minor_modes() {
        let mut buf = Buffer::new();
        buf.major_mode = "rust-mode";
        buf.minor_modes.push("auto-wrap-mode");
        buf.minor_modes.push("spell-check-mode");
        buf.minor_modes.push("complete-me-mode");
        buf.minor_modes.push("language-server-mode");

        assert_eq!(2, buf.minor_modes.len());
        assert_eq!("latex-mode", buf.major_mode);
    }
}
<commit_msg>buffer: Fix tests on buffer.rs<commit_after>//! This is the Buffer module for Xtensis.

// This file is part of Xtensis.

// This is the Xtensis text editor; it edits text.
// Copyright (C) 2016-2017  The Xtensis Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

extern crate slog;
extern crate slog_scope;

use std::path::PathBuf;

use server::gapbuffer::GapBuffer;
use utils::uuid;
use slog::Logger;

/// Struct for a Buffer in Xtensis
/// This stores metadata about a buffer.
#[derive(Debug)]
pub struct Buffer {
    /// UUID of a buffer.
    pub buf_uuid: String,
    /// File path of a buffer.
    pub file_path: Option<PathBuf>,
    /// Active status of a buffer.
    pub active: bool,
    /// Temporary status of a buffer.
    pub temporary: bool,
    /// If a buffer is r/o.
    /// If this is `true`, then r/w is `false.`
    /// Likewise, if this is `false`, then r/w is `true.
    pub read_only: bool,
    /// Major mode of a buffer
    pub major_mode: &'static str,
    /// Vector of Minor modes in a buffer
    pub minor_modes: Vec<&'static str>,
    /// Dirty status of a buffer
    pub dirty: bool,
    /// Contents of a buffer.
    pub text: GapBuffer<u8>,
    /// Logger of a buffer.
    pub logger: Logger,
}

impl Buffer {
    /// Return a new instance of `Buffer`.
    pub fn new() -> Buffer {
        let buf_logger = slog_scope::logger().new(o!("module" =>
                                                     "buffer"));

        slog_scope::scope(buf_logger.clone(), || {
            warn!("The buffer is being created!!");
        });

        trace!("Initialising logger..");
        Buffer {
            buf_uuid: uuid::get_uuid_buffer(),
            file_path: None,
            active: false,
            temporary: false,
            read_only: false,
            major_mode: "fundamental-mode",
            minor_modes: Vec::new(),
            dirty: false,
            text: GapBuffer::new(),
            logger: buf_logger,
        }
    }

    /// Return true if a buffer is active.
    /// That is to say, a 'focused' buffer, or otherwise in-use, and
    /// *not* inactive.
    /// If it's not a active buffer, then return false.
    pub fn is_active(&self) -> bool {
        self.active
    }

    /// Return true if a buffer is temporary.
    /// If it's not a temporary buffer, then return false.
    /// A temporary buffer is defined by the characteristic of having
    /// no 'target' to save to.
    pub fn is_temporary(&self) -> bool {
        self.temporary
    }

    /// Return true if a buffer is read only.

    /// If it's not read-only, then it returns false, and the buffer
    /// will be presumed to be read-write.

    /// A read-only buffer is defined by the characteristic of the FS
    /// denying write access, or being set manually.
    pub fn is_ro(&self) -> bool {
        self.read_only
    }

    /// Return true if a buffer is dirty.
    /// If it's not dirty, then return false.
    /// A dirty buffer is defined by the characteristic of the buffer
    /// having changed since the last save.
    /// Temporary buffers are *exempt* from this field.
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Return the current major mode of a buffer.
    pub fn get_major_mode(&self) -> &str {
        self.major_mode
    }

    /// Return a `Vec<&'static str>` of minor modes.
    pub fn get_minor_modes(&self) -> Vec<&'static str> {
        self.minor_modes.clone()
    }

    /// Return the length of a buffer.
    pub fn get_buffer_length(&self) -> usize {
        self.text.len()
    }
}

impl Default for Buffer {
    fn default() -> Buffer {
        Buffer::new()
    }
}

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

    #[test]
    fn test_buffer_default_values() {
        let buf = Buffer::new();

        assert_eq!(None, buf.file_path);
        assert_eq!(false, buf.active);
        assert_eq!(false, buf.is_active());

        assert_eq!(false, buf.temporary);
        assert_eq!(false, buf.is_temporary());

        assert_eq!(false, buf.read_only);
        assert_eq!(false, buf.is_ro());

        assert_eq!("fundamental-mode", buf.major_mode);
        assert_eq!(false, buf.dirty);
    }

    #[test]
    fn test_buffer_major_minor_modes() {
        let mut buf = Buffer::new();
        buf.major_mode = "rust-mode";
        buf.minor_modes.push("auto-wrap-mode");
        buf.minor_modes.push("spell-check-mode");
        buf.minor_modes.push("complete-me-mode");
        buf.minor_modes.push("language-server-mode");

        assert_eq!(4, buf.minor_modes.len());
        assert_eq!("rust-mode", buf.major_mode);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// This example shows a basic packet logger using libpnet
extern crate pnet;

use pnet::datalink::{self, NetworkInterface};

use pnet::packet::arp::ArpPacket;
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
use pnet::packet::icmp::{echo_reply, echo_request, IcmpPacket, IcmpTypes};
use pnet::packet::icmpv6::Icmpv6Packet;
use pnet::packet::ip::{IpNextHeaderProtocol, IpNextHeaderProtocols};
use pnet::packet::ipv4::Ipv4Packet;
use pnet::packet::ipv6::Ipv6Packet;
use pnet::packet::tcp::TcpPacket;
use pnet::packet::udp::UdpPacket;
use pnet::packet::Packet;
use pnet::util::MacAddr;

use std::env;
use std::io::{self, Write};
use std::net::IpAddr;
use std::process;

fn handle_udp_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let udp = UdpPacket::new(packet);

    if let Some(udp) = udp {
        println!(
            "[{}]: UDP Packet: {}:{} > {}:{}; length: {}",
            interface_name,
            source,
            udp.get_source(),
            destination,
            udp.get_destination(),
            udp.get_length()
        );
    } else {
        println!("[{}]: Malformed UDP Packet", interface_name);
    }
}

fn handle_icmp_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let icmp_packet = IcmpPacket::new(packet);
    if let Some(icmp_packet) = icmp_packet {
        match icmp_packet.get_icmp_type() {
            IcmpTypes::EchoReply => {
                let echo_reply_packet = echo_reply::EchoReplyPacket::new(packet).unwrap();
                println!(
                    "[{}]: ICMP echo reply {} -> {} (seq={:?}, id={:?})",
                    interface_name,
                    source,
                    destination,
                    echo_reply_packet.get_sequence_number(),
                    echo_reply_packet.get_identifier()
                );
            }
            IcmpTypes::EchoRequest => {
                let echo_request_packet = echo_request::EchoRequestPacket::new(packet).unwrap();
                println!(
                    "[{}]: ICMP echo request {} -> {} (seq={:?}, id={:?})",
                    interface_name,
                    source,
                    destination,
                    echo_request_packet.get_sequence_number(),
                    echo_request_packet.get_identifier()
                );
            }
            _ => println!(
                "[{}]: ICMP packet {} -> {} (type={:?})",
                interface_name,
                source,
                destination,
                icmp_packet.get_icmp_type()
            ),
        }
    } else {
        println!("[{}]: Malformed ICMP Packet", interface_name);
    }
}

fn handle_icmpv6_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let icmpv6_packet = Icmpv6Packet::new(packet);
    if let Some(icmpv6_packet) = icmpv6_packet {
        println!(
            "[{}]: ICMPv6 packet {} -> {} (type={:?})",
            interface_name,
            source,
            destination,
            icmpv6_packet.get_icmpv6_type()
        )
    } else {
        println!("[{}]: Malformed ICMPv6 Packet", interface_name);
    }
}

fn handle_tcp_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let tcp = TcpPacket::new(packet);
    if let Some(tcp) = tcp {
        println!(
            "[{}]: TCP Packet: {}:{} > {}:{}; length: {}",
            interface_name,
            source,
            tcp.get_source(),
            destination,
            tcp.get_destination(),
            packet.len()
        );
    } else {
        println!("[{}]: Malformed TCP Packet", interface_name);
    }
}

fn handle_transport_protocol(
    interface_name: &str,
    source: IpAddr,
    destination: IpAddr,
    protocol: IpNextHeaderProtocol,
    packet: &[u8],
) {
    match protocol {
        IpNextHeaderProtocols::Udp => {
            handle_udp_packet(interface_name, source, destination, packet)
        }
        IpNextHeaderProtocols::Tcp => {
            handle_tcp_packet(interface_name, source, destination, packet)
        }
        IpNextHeaderProtocols::Icmp => {
            handle_icmp_packet(interface_name, source, destination, packet)
        }
        IpNextHeaderProtocols::Icmpv6 => {
            handle_icmpv6_packet(interface_name, source, destination, packet)
        }
        _ => println!(
            "[{}]: Unknown {} packet: {} > {}; protocol: {:?} length: {}",
            interface_name,
            match source {
                IpAddr::V4(..) => "IPv4",
                _ => "IPv6",
            },
            source,
            destination,
            protocol,
            packet.len()
        ),
    }
}

fn handle_ipv4_packet(interface_name: &str, ethernet: &EthernetPacket) {
    let header = Ipv4Packet::new(ethernet.payload());
    if let Some(header) = header {
        handle_transport_protocol(
            interface_name,
            IpAddr::V4(header.get_source()),
            IpAddr::V4(header.get_destination()),
            header.get_next_level_protocol(),
            header.payload(),
        );
    } else {
        println!("[{}]: Malformed IPv4 Packet", interface_name);
    }
}

fn handle_ipv6_packet(interface_name: &str, ethernet: &EthernetPacket) {
    let header = Ipv6Packet::new(ethernet.payload());
    if let Some(header) = header {
        handle_transport_protocol(
            interface_name,
            IpAddr::V6(header.get_source()),
            IpAddr::V6(header.get_destination()),
            header.get_next_header(),
            header.payload(),
        );
    } else {
        println!("[{}]: Malformed IPv6 Packet", interface_name);
    }
}

fn handle_arp_packet(interface_name: &str, ethernet: &EthernetPacket) {
    let header = ArpPacket::new(ethernet.payload());
    if let Some(header) = header {
        println!(
            "[{}]: ARP packet: {}({}) > {}({}); operation: {:?}",
            interface_name,
            ethernet.get_source(),
            header.get_sender_proto_addr(),
            ethernet.get_destination(),
            header.get_target_proto_addr(),
            header.get_operation()
        );
    } else {
        println!("[{}]: Malformed ARP Packet", interface_name);
    }
}

fn handle_ethernet_frame(interface: &NetworkInterface, ethernet: &EthernetPacket) {
    let interface_name = &interface.name[..];
    match ethernet.get_ethertype() {
        EtherTypes::Ipv4 => handle_ipv4_packet(interface_name, ethernet),
        EtherTypes::Ipv6 => handle_ipv6_packet(interface_name, ethernet),
        EtherTypes::Arp => handle_arp_packet(interface_name, ethernet),
        _ => println!(
            "[{}]: Unknown packet: {} > {}; ethertype: {:?} length: {}",
            interface_name,
            ethernet.get_source(),
            ethernet.get_destination(),
            ethernet.get_ethertype(),
            ethernet.packet().len()
        ),
    }
}

fn main() {
    use pnet::datalink::Channel::Ethernet;

    let iface_name = match env::args().nth(1) {
        Some(n) => n,
        None => {
            writeln!(io::stderr(), "USAGE: packetdump <NETWORK INTERFACE>").unwrap();
            process::exit(1);
        }
    };
    let interface_names_match = |iface: &NetworkInterface| iface.name == iface_name;

    // Find the network interface with the provided name
    let interfaces = datalink::interfaces();
    let interface = interfaces
        .into_iter()
        .filter(interface_names_match)
        .next()
        .unwrap();

    // Create a channel to receive on
    let (_, mut rx) = match datalink::channel(&interface, Default::default()) {
        Ok(Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("packetdump: unhandled channel type: {}"),
        Err(e) => panic!("packetdump: unable to create channel: {}", e),
    };

    loop {
        let mut buf: [u8; 1600] = [0u8; 1600];
        let mut fake_ethernet_frame = MutableEthernetPacket::new(&mut buf[..]).unwrap();
        match rx.next() {
            Ok(packet) => {
                let payload_offset;
                if cfg!(target_os = "macos") && interface.is_up() && !interface.is_broadcast()
                    && ((!interface.is_loopback() && interface.is_point_to_point())
                         || interface.is_loopback())
                {
                    if interface.is_loopback()
                    {
                        // The pnet code for BPF loopback adds a zero'd out Ethernet header
                        payload_offset = 14;
                    }
                    else
                    {
                        // Maybe is TUN interface
                        payload_offset = 0;
                    }
                    if packet.len() > payload_offset
                    {
                        let version = Ipv4Packet::new(&packet[payload_offset..]).unwrap().get_version();
                        if version == 4 {
                            fake_ethernet_frame.set_destination(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_source(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_ethertype(EtherTypes::Ipv4);
                            fake_ethernet_frame.set_payload(&packet[payload_offset..]);
                            handle_ethernet_frame(&interface, &fake_ethernet_frame.to_immutable());
                            continue;
                        } else if version == 6 {
                            fake_ethernet_frame.set_destination(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_source(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_ethertype(EtherTypes::Ipv6);
                            fake_ethernet_frame.set_payload(&packet[payload_offset..]);
                            handle_ethernet_frame(&interface, &fake_ethernet_frame.to_immutable());
                            continue;
                        }
                    }
                }
                handle_ethernet_frame(&interface, &EthernetPacket::new(packet).unwrap());
            }
            Err(e) => panic!("packetdump: unable to receive packet: {}", e),
        }
    }
}
<commit_msg>Add error message when invalid interface is provided<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// This example shows a basic packet logger using libpnet
extern crate pnet;

use pnet::datalink::{self, NetworkInterface};

use pnet::packet::arp::ArpPacket;
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
use pnet::packet::icmp::{echo_reply, echo_request, IcmpPacket, IcmpTypes};
use pnet::packet::icmpv6::Icmpv6Packet;
use pnet::packet::ip::{IpNextHeaderProtocol, IpNextHeaderProtocols};
use pnet::packet::ipv4::Ipv4Packet;
use pnet::packet::ipv6::Ipv6Packet;
use pnet::packet::tcp::TcpPacket;
use pnet::packet::udp::UdpPacket;
use pnet::packet::Packet;
use pnet::util::MacAddr;

use std::env;
use std::io::{self, Write};
use std::net::IpAddr;
use std::process;

fn handle_udp_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let udp = UdpPacket::new(packet);

    if let Some(udp) = udp {
        println!(
            "[{}]: UDP Packet: {}:{} > {}:{}; length: {}",
            interface_name,
            source,
            udp.get_source(),
            destination,
            udp.get_destination(),
            udp.get_length()
        );
    } else {
        println!("[{}]: Malformed UDP Packet", interface_name);
    }
}

fn handle_icmp_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let icmp_packet = IcmpPacket::new(packet);
    if let Some(icmp_packet) = icmp_packet {
        match icmp_packet.get_icmp_type() {
            IcmpTypes::EchoReply => {
                let echo_reply_packet = echo_reply::EchoReplyPacket::new(packet).unwrap();
                println!(
                    "[{}]: ICMP echo reply {} -> {} (seq={:?}, id={:?})",
                    interface_name,
                    source,
                    destination,
                    echo_reply_packet.get_sequence_number(),
                    echo_reply_packet.get_identifier()
                );
            }
            IcmpTypes::EchoRequest => {
                let echo_request_packet = echo_request::EchoRequestPacket::new(packet).unwrap();
                println!(
                    "[{}]: ICMP echo request {} -> {} (seq={:?}, id={:?})",
                    interface_name,
                    source,
                    destination,
                    echo_request_packet.get_sequence_number(),
                    echo_request_packet.get_identifier()
                );
            }
            _ => println!(
                "[{}]: ICMP packet {} -> {} (type={:?})",
                interface_name,
                source,
                destination,
                icmp_packet.get_icmp_type()
            ),
        }
    } else {
        println!("[{}]: Malformed ICMP Packet", interface_name);
    }
}

fn handle_icmpv6_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let icmpv6_packet = Icmpv6Packet::new(packet);
    if let Some(icmpv6_packet) = icmpv6_packet {
        println!(
            "[{}]: ICMPv6 packet {} -> {} (type={:?})",
            interface_name,
            source,
            destination,
            icmpv6_packet.get_icmpv6_type()
        )
    } else {
        println!("[{}]: Malformed ICMPv6 Packet", interface_name);
    }
}

fn handle_tcp_packet(interface_name: &str, source: IpAddr, destination: IpAddr, packet: &[u8]) {
    let tcp = TcpPacket::new(packet);
    if let Some(tcp) = tcp {
        println!(
            "[{}]: TCP Packet: {}:{} > {}:{}; length: {}",
            interface_name,
            source,
            tcp.get_source(),
            destination,
            tcp.get_destination(),
            packet.len()
        );
    } else {
        println!("[{}]: Malformed TCP Packet", interface_name);
    }
}

fn handle_transport_protocol(
    interface_name: &str,
    source: IpAddr,
    destination: IpAddr,
    protocol: IpNextHeaderProtocol,
    packet: &[u8],
) {
    match protocol {
        IpNextHeaderProtocols::Udp => {
            handle_udp_packet(interface_name, source, destination, packet)
        }
        IpNextHeaderProtocols::Tcp => {
            handle_tcp_packet(interface_name, source, destination, packet)
        }
        IpNextHeaderProtocols::Icmp => {
            handle_icmp_packet(interface_name, source, destination, packet)
        }
        IpNextHeaderProtocols::Icmpv6 => {
            handle_icmpv6_packet(interface_name, source, destination, packet)
        }
        _ => println!(
            "[{}]: Unknown {} packet: {} > {}; protocol: {:?} length: {}",
            interface_name,
            match source {
                IpAddr::V4(..) => "IPv4",
                _ => "IPv6",
            },
            source,
            destination,
            protocol,
            packet.len()
        ),
    }
}

fn handle_ipv4_packet(interface_name: &str, ethernet: &EthernetPacket) {
    let header = Ipv4Packet::new(ethernet.payload());
    if let Some(header) = header {
        handle_transport_protocol(
            interface_name,
            IpAddr::V4(header.get_source()),
            IpAddr::V4(header.get_destination()),
            header.get_next_level_protocol(),
            header.payload(),
        );
    } else {
        println!("[{}]: Malformed IPv4 Packet", interface_name);
    }
}

fn handle_ipv6_packet(interface_name: &str, ethernet: &EthernetPacket) {
    let header = Ipv6Packet::new(ethernet.payload());
    if let Some(header) = header {
        handle_transport_protocol(
            interface_name,
            IpAddr::V6(header.get_source()),
            IpAddr::V6(header.get_destination()),
            header.get_next_header(),
            header.payload(),
        );
    } else {
        println!("[{}]: Malformed IPv6 Packet", interface_name);
    }
}

fn handle_arp_packet(interface_name: &str, ethernet: &EthernetPacket) {
    let header = ArpPacket::new(ethernet.payload());
    if let Some(header) = header {
        println!(
            "[{}]: ARP packet: {}({}) > {}({}); operation: {:?}",
            interface_name,
            ethernet.get_source(),
            header.get_sender_proto_addr(),
            ethernet.get_destination(),
            header.get_target_proto_addr(),
            header.get_operation()
        );
    } else {
        println!("[{}]: Malformed ARP Packet", interface_name);
    }
}

fn handle_ethernet_frame(interface: &NetworkInterface, ethernet: &EthernetPacket) {
    let interface_name = &interface.name[..];
    match ethernet.get_ethertype() {
        EtherTypes::Ipv4 => handle_ipv4_packet(interface_name, ethernet),
        EtherTypes::Ipv6 => handle_ipv6_packet(interface_name, ethernet),
        EtherTypes::Arp => handle_arp_packet(interface_name, ethernet),
        _ => println!(
            "[{}]: Unknown packet: {} > {}; ethertype: {:?} length: {}",
            interface_name,
            ethernet.get_source(),
            ethernet.get_destination(),
            ethernet.get_ethertype(),
            ethernet.packet().len()
        ),
    }
}

fn main() {
    use pnet::datalink::Channel::Ethernet;

    let iface_name = match env::args().nth(1) {
        Some(n) => n,
        None => {
            writeln!(io::stderr(), "USAGE: packetdump <NETWORK INTERFACE>").unwrap();
            process::exit(1);
        }
    };
    let interface_names_match = |iface: &NetworkInterface| iface.name == iface_name;

    // Find the network interface with the provided name
    let interfaces = datalink::interfaces();
    let interface = interfaces
        .into_iter()
        .filter(interface_names_match)
        .next()
        .unwrap_or_else(|| panic!("No such network interface: {}", iface_name));

    // Create a channel to receive on
    let (_, mut rx) = match datalink::channel(&interface, Default::default()) {
        Ok(Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("packetdump: unhandled channel type: {}"),
        Err(e) => panic!("packetdump: unable to create channel: {}", e),
    };

    loop {
        let mut buf: [u8; 1600] = [0u8; 1600];
        let mut fake_ethernet_frame = MutableEthernetPacket::new(&mut buf[..]).unwrap();
        match rx.next() {
            Ok(packet) => {
                let payload_offset;
                if cfg!(target_os = "macos") && interface.is_up() && !interface.is_broadcast()
                    && ((!interface.is_loopback() && interface.is_point_to_point())
                         || interface.is_loopback())
                {
                    if interface.is_loopback()
                    {
                        // The pnet code for BPF loopback adds a zero'd out Ethernet header
                        payload_offset = 14;
                    }
                    else
                    {
                        // Maybe is TUN interface
                        payload_offset = 0;
                    }
                    if packet.len() > payload_offset
                    {
                        let version = Ipv4Packet::new(&packet[payload_offset..]).unwrap().get_version();
                        if version == 4 {
                            fake_ethernet_frame.set_destination(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_source(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_ethertype(EtherTypes::Ipv4);
                            fake_ethernet_frame.set_payload(&packet[payload_offset..]);
                            handle_ethernet_frame(&interface, &fake_ethernet_frame.to_immutable());
                            continue;
                        } else if version == 6 {
                            fake_ethernet_frame.set_destination(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_source(MacAddr(0, 0, 0, 0, 0, 0));
                            fake_ethernet_frame.set_ethertype(EtherTypes::Ipv6);
                            fake_ethernet_frame.set_payload(&packet[payload_offset..]);
                            handle_ethernet_frame(&interface, &fake_ethernet_frame.to_immutable());
                            continue;
                        }
                    }
                }
                handle_ethernet_frame(&interface, &EthernetPacket::new(packet).unwrap());
            }
            Err(e) => panic!("packetdump: unable to receive packet: {}", e),
        }
    }
}
<|endoftext|>


<commit_before>/// A simple example demonstrating how to handle user input. This is
/// a bit out of the scope of the library as it does not provide any
/// input handling out of the box. However, it may helps some to get
/// started.
///
/// This is a very simple example:
///   * A input box always focused. Every character you type is registered
///   here
///   * Pressing Backspace erases a character
///   * Pressing Enter pushes the current input in the history of previous
///   messages

#[allow(dead_code)]
mod util;

use std::io::{self, Write};

use termion::cursor::Goto;
use termion::event::Key;
use termion::input::MouseTerminal;
use termion::raw::IntoRawMode;
use termion::screen::AlternateScreen;
use tui::backend::TermionBackend;
use tui::layout::{Constraint, Direction, Layout};
use tui::style::{Color, Style};
use tui::widgets::{Block, Borders, List, Paragraph, Text, Widget};
use tui::Terminal;
use unicode_width::UnicodeWidthStr;

use crate::util::event::{Event, Events};

/// App holds the state of the application
struct App {
    /// Current value of the input box
    input: String,
    /// History of recorded messages
    messages: Vec<String>,
}

impl Default for App {
    fn default() -> App {
        App {
            input: String::new(),
            messages: Vec::new(),
        }
    }
}

fn main() -> Result<(), failure::Error> {
    // Terminal initialization
    let stdout = io::stdout().into_raw_mode()?;
    let stdout = MouseTerminal::from(stdout);
    let stdout = AlternateScreen::from(stdout);
    let backend = TermionBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // Setup event handlers
    let events = Events::new();

    // Create default app state
    let mut app = App::default();

    loop {
        // Draw UI
        terminal.draw(|mut f| {
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .margin(2)
                .constraints([Constraint::Length(3), Constraint::Min(1)].as_ref())
                .split(f.size());
            Paragraph::new([Text::raw(&app.input)].iter())
                .style(Style::default().fg(Color::Yellow))
                .block(Block::default().borders(Borders::ALL).title("Input"))
                .render(&mut f, chunks[0]);
            let messages = app
                .messages
                .iter()
                .enumerate()
                .map(|(i, m)| Text::raw(format!("{}: {}", i, m)));
            List::new(messages)
                .block(Block::default().borders(Borders::ALL).title("Messages"))
                .render(&mut f, chunks[1]);
        })?;

        // Put the cursor back inside the input box
        write!(
            terminal.backend_mut(),
            "{}",
            Goto(4 + app.input.width() as u16, 4)
        )?;

        // Handle input
        match events.next()? {
            Event::Input(input) => match input {
                Key::Char('q') => {
                    break;
                }
                Key::Char('\n') => {
                    app.messages.push(app.input.drain(..).collect());
                }
                Key::Char(c) => {
                    app.input.push(c);
                }
                Key::Backspace => {
                    app.input.pop();
                }
                _ => {}
            },
            _ => {}
        }
    }
    Ok(())
}
<commit_msg>[example: user_input] Assure the cursor responds immediatel when hitting backspace<commit_after>/// A simple example demonstrating how to handle user input. This is
/// a bit out of the scope of the library as it does not provide any
/// input handling out of the box. However, it may helps some to get
/// started.
///
/// This is a very simple example:
///   * A input box always focused. Every character you type is registered
///   here
///   * Pressing Backspace erases a character
///   * Pressing Enter pushes the current input in the history of previous
///   messages

#[allow(dead_code)]
mod util;

use std::io::{self, Write};

use termion::cursor::Goto;
use termion::event::Key;
use termion::input::MouseTerminal;
use termion::raw::IntoRawMode;
use termion::screen::AlternateScreen;
use tui::backend::TermionBackend;
use tui::layout::{Constraint, Direction, Layout};
use tui::style::{Color, Style};
use tui::widgets::{Block, Borders, List, Paragraph, Text, Widget};
use tui::Terminal;
use unicode_width::UnicodeWidthStr;

use crate::util::event::{Event, Events};

/// App holds the state of the application
struct App {
    /// Current value of the input box
    input: String,
    /// History of recorded messages
    messages: Vec<String>,
}

impl Default for App {
    fn default() -> App {
        App {
            input: String::new(),
            messages: Vec::new(),
        }
    }
}

fn main() -> Result<(), failure::Error> {
    // Terminal initialization
    let stdout = io::stdout().into_raw_mode()?;
    let stdout = MouseTerminal::from(stdout);
    let stdout = AlternateScreen::from(stdout);
    let backend = TermionBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // Setup event handlers
    let events = Events::new();

    // Create default app state
    let mut app = App::default();

    loop {
        // Draw UI
        terminal.draw(|mut f| {
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .margin(2)
                .constraints([Constraint::Length(3), Constraint::Min(1)].as_ref())
                .split(f.size());
            Paragraph::new([Text::raw(&app.input)].iter())
                .style(Style::default().fg(Color::Yellow))
                .block(Block::default().borders(Borders::ALL).title("Input"))
                .render(&mut f, chunks[0]);
            let messages = app
                .messages
                .iter()
                .enumerate()
                .map(|(i, m)| Text::raw(format!("{}: {}", i, m)));
            List::new(messages)
                .block(Block::default().borders(Borders::ALL).title("Messages"))
                .render(&mut f, chunks[1]);
        })?;

        // Put the cursor back inside the input box
        write!(
            terminal.backend_mut(),
            "{}",
            Goto(4 + app.input.width() as u16, 4)
        )?;
        // stdout is buffered, flush it to see the effect immediately when hitting backspace
        io::stdout().flush().ok();

        // Handle input
        match events.next()? {
            Event::Input(input) => match input {
                Key::Char('q') => {
                    break;
                }
                Key::Char('\n') => {
                    app.messages.push(app.input.drain(..).collect());
                }
                Key::Char(c) => {
                    app.input.push(c);
                }
                Key::Backspace => {
                    app.input.pop();
                }
                _ => {}
            },
            _ => {}
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;

use orbclient::event;

use std::env;
use std::error::Error;
use std::io::{Read, Write, self};
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::thread;

use console::Console;

mod console;

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

    let width = 640;
    let height = 480;

    env::set_var("COLUMNS", format!("{}", width/8));
    env::set_var("LINES", format!("{}", height/16));
    match Command::new(&shell).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
        Ok(process) => {
            let output_mutex = Arc::new(Mutex::new(Vec::new()));

            {
                let mut stdout = process.stdout.unwrap();
                let stdout_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    let term_stderr = io::stderr();
                    let mut term_stderr = term_stderr.lock();
                    'stdout: loop {
                        let mut buf = [0; 4096];
                        match stdout.read(&mut buf) {
                            Ok(0) => break 'stdout,
                            Ok(count) => {
                                if let Ok(mut stdout_output) = stdout_output_mutex.lock() {
                                    stdout_output.extend_from_slice(&buf[..count]);
                                } else {
                                    let _ = term_stderr.write(b"failed to lock stdout output mutex.\n");
                                    break 'stdout;
                                }
                            },
                            Err(err) => {
                                let _ = term_stderr.write(b"failed to read stdout: ");
                                let _ = term_stderr.write(err.description().as_bytes());
                                let _ = term_stderr.write(b"\n");
                                break 'stdout;
                            }
                        }
                    }
                });
            }

            {
                let mut stderr = process.stderr.unwrap();
                let stderr_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    let mut term_stderr = io::stderr();
                    'stderr: loop {
                        let mut buf = [0; 4096];
                        match stderr.read(&mut buf) {
                            Ok(0) => break 'stderr,
                            Ok(count) => {
                                match stderr_output_mutex.lock() {
                                    Ok(mut stderr_output) => stderr_output.extend_from_slice(&buf[..count]),
                                    Err(_) => {
                                        let _ = term_stderr.write(b"failed to lock stderr output mutex.\n");
                                        break 'stderr;
                                    }
                                }
                            },
                            Err(err) => {
                                let _ = term_stderr.write(b"failed to read stderr: ");
                                let _ = term_stderr.write(err.description().as_bytes());
                                let _ = term_stderr.write(b"\n");
                                break 'stderr;
                            }
                        }
                    }
                });
            }

            let mut stdin = process.stdin.unwrap();
            let mut console = Console::new(width, height);
            'events: loop {
                match output_mutex.lock() {
                    Ok(mut output) => {
                        if !output.is_empty() {
                            console.write(&output);
                            output.clear();
                        }
                    },
                    Err(_) => {
                        let term_stderr = io::stderr();
                        let mut term_stderr = term_stderr.lock();
                        let _ = term_stderr.write(b"failed to lock stdout mutex.\n");
                        break 'events;
                    }
                }

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

                    if let Some(line) = console.event(event) {
                        if let Err(err) = stdin.write(&line.as_bytes()) {
                            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;
                        }
                    }
                }

                thread::sleep(Duration::new(0, 1000000));
            }
        },
        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>Allow exit of terminal to close window<commit_after>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;

use orbclient::event;

use std::env;
use std::error::Error;
use std::io::{Read, Write, self};
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::thread;

use console::Console;

mod console;

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

    let width = 640;
    let height = 480;

    env::set_var("COLUMNS", format!("{}", width/8));
    env::set_var("LINES", format!("{}", height/16));
    match Command::new(&shell).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
        Ok(process) => {
            let output_mutex = Arc::new(Mutex::new(Some(Vec::new())));

            {
                let mut stdout = process.stdout.unwrap();
                let stdout_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    let term_stderr = io::stderr();
                    let mut term_stderr = term_stderr.lock();
                    'stdout: loop {
                        let mut buf = [0; 4096];
                        match stdout.read(&mut buf) {
                            Ok(0) => break 'stdout,
                            Ok(count) => match stdout_output_mutex.lock() {
                                Ok(mut stdout_output_option) => match *stdout_output_option {
                                    Some(ref mut stdout_output) => stdout_output.extend_from_slice(&buf[..count]),
                                    None => break 'stdout
                                },
                                Err(_) => {
                                    let _ = term_stderr.write(b"failed to lock stdout output mutex\n");
                                    break 'stdout;
                                }
                            },
                            Err(err) => {
                                let _ = term_stderr.write(b"failed to read stdout: ");
                                let _ = term_stderr.write(err.description().as_bytes());
                                let _ = term_stderr.write(b"\n");
                                break 'stdout;
                            }
                        }
                    }
                    stdout_output_mutex.lock().unwrap().take();
                });
            }

            {
                let mut stderr = process.stderr.unwrap();
                let stderr_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    let mut term_stderr = io::stderr();
                    'stderr: loop {
                        let mut buf = [0; 4096];
                        match stderr.read(&mut buf) {
                            Ok(0) => break 'stderr,
                            Ok(count) => match stderr_output_mutex.lock() {
                                Ok(mut stderr_output_option) => match *stderr_output_option {
                                    Some(ref mut stderr_output) => stderr_output.extend_from_slice(&buf[..count]),
                                    None => break 'stderr
                                },
                                Err(_) => {
                                    let _ = term_stderr.write(b"failed to lock stdout output mutex\n");
                                    break 'stderr;
                                }
                            },
                            Err(err) => {
                                let _ = term_stderr.write(b"failed to read stderr: ");
                                let _ = term_stderr.write(err.description().as_bytes());
                                let _ = term_stderr.write(b"\n");
                                break 'stderr;
                            }
                        }
                    }
                    stderr_output_mutex.lock().unwrap().take();
                });
            }

            let mut stdin = process.stdin.unwrap();
            let mut console = Console::new(width, height);
            'events: loop {
                match output_mutex.lock() {
                    Ok(mut output_option) => match *output_option {
                        Some(ref mut output) => if !output.is_empty() {
                            console.write(&output);
                            output.clear();
                        },
                        None => break 'events
                    },
                    Err(_) => {
                        let term_stderr = io::stderr();
                        let mut term_stderr = term_stderr.lock();
                        let _ = term_stderr.write(b"failed to lock stdout mutex\n");
                        break 'events;
                    }
                }

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

                    if let Some(line) = console.event(event) {
                        if let Err(err) = stdin.write(&line.as_bytes()) {
                            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;
                        }
                    }
                }

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

            output_mutex.lock().unwrap().take();
        },
        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>pub trait TextureUnit {
    fn idx() -> u32;
}

// 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);
<commit_msg>Add unsafe `TextureUnits::current()` constructor<commit_after>pub trait TextureUnit {
    fn idx() -> u32;
}

// 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)
    }
}
<|endoftext|>


<commit_before>use parking_lot::Mutex;
use std::sync::atomic::{AtomicUsize, Ordering};

/// Storage cell for shared signal values.
pub struct Storage<T> {
    val: Mutex<Option<T>>,
    serial: AtomicUsize,
}

const ERR_EMPTY: &str = "storage empty";

impl<T> Storage<T> {
    /// Creates a storage with an initial value.
    pub fn new(val: T) -> Self {
        Storage {
            val: Mutex::new(Some(val)),
            serial: AtomicUsize::new(1),
        }
    }

    /// Gets the value by cloning.
    pub fn get(&self) -> T
    where
        T: Clone,
    {
        self.val.lock().clone().expect(ERR_EMPTY)
    }

    /// Sets value and increments the serial.
    pub fn set(&self, val: T) {
        *self.val.lock() = Some(val);
        self.inc_serial();
    }

    /// Replaces the stored value and returns the previous one.
    pub fn replace(&self, val: T) -> T {
        let old = self.val.lock().replace(val);
        self.inc_serial();
        old.expect(ERR_EMPTY)
    }

    /// Passes the stored value through a function.
    pub fn replace_with<F>(&self, f: F)
    where
        F: FnOnce(T) -> T,
    {
        let mut st = self.val.lock();
        let old = st.take().expect(ERR_EMPTY);
        *st = Some(f(old));
        drop(st);
        self.inc_serial();
    }

    /// Increments the serial of this storage.
    fn inc_serial(&self) {
        self.serial.fetch_add(1, Ordering::Release);
    }
}

impl<T> Default for Storage<T> {
    /// Creates an empty storage.
    fn default() -> Self {
        Storage {
            val: Default::default(),
            serial: Default::default(),
        }
    }
}
<commit_msg>not using serials anymore<commit_after>use parking_lot::Mutex;

/// Storage cell for shared signal values.
pub struct Storage<T> {
    val: Mutex<Option<T>>,
}

const ERR_EMPTY: &str = "storage empty";

impl<T> Storage<T> {
    /// Creates a storage with an initial value.
    pub fn new(val: T) -> Self {
        Storage {
            val: Mutex::new(Some(val)),
        }
    }

    /// Gets the value by cloning.
    pub fn get(&self) -> T
    where
        T: Clone,
    {
        self.val.lock().clone().expect(ERR_EMPTY)
    }

    /// Sets the value.
    pub fn set(&self, val: T) {
        *self.val.lock() = Some(val);
    }

    /// Replaces the stored value and returns the previous one.
    pub fn replace(&self, val: T) -> T {
        self.val.lock().replace(val).expect(ERR_EMPTY)
    }

    /// Passes the stored value through a function.
    pub fn replace_with<F>(&self, f: F)
    where
        F: FnOnce(T) -> T,
    {
        let mut st = self.val.lock();
        let old = st.take().expect(ERR_EMPTY);
        *st = Some(f(old));
    }
}

impl<T> Default for Storage<T> {
    /// Creates an empty storage.
    fn default() -> Self {
        Storage {
            val: Default::default(),
        }
    }
}
<|endoftext|>