<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use command_line::command_line_init;
use interfaces::cef_app_t;
use types::{cef_main_args_t, cef_settings_t};
use window::init_window;

use browser;
use libc::{c_char, c_int, c_void};
use servo_config::opts;
use std::ffi;
use std::str;

const MAX_RENDERING_THREADS: usize = 128;

//static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";

static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
#[cfg(target_os="windows")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"5c7f3e50ff5265985d11dc1a466513e25748bedd\0";
#[cfg(target_os="macos")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"6813214accbf2ebfb6bdcf8d00654650b251bf3d\0";
#[cfg(target_os="linux")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e17fa17a6d\0";

pub static mut CEF_APP: *mut cef_app_t = 0 as *mut cef_app_t;

#[no_mangle]
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
                                 settings: *mut cef_settings_t,
                                 application: *mut cef_app_t,
                                 _windows_sandbox_info: *const c_void)
                                 -> c_int {
    if args.is_null() {
        return 0;
    }
    unsafe {
        if !CEF_APP.is_null() {
            panic!("Attempting to call cef_initialize() multiple times!");
        }
    }

    unsafe {
        command_line_init((*args).argc, (*args).argv);

        if !application.is_null() {
            (*application).get_browser_process_handler.map(|cb| {
                    let handler = cb(application);
                    if !handler.is_null() {
                        (*handler).on_context_initialized.map(|hcb| hcb(handler));
                    }
            });
            CEF_APP = application;
        }
    }

    let rendering_threads = unsafe {
        if ((*settings).rendering_threads as usize) < 1 {
            1
        } else if (*settings).rendering_threads as usize > MAX_RENDERING_THREADS {
            MAX_RENDERING_THREADS
        } else {
            (*settings).rendering_threads as usize
        }
    };

    let mut temp_opts = opts::default_opts();
    temp_opts.headless = false;
    temp_opts.hard_fail = false;
    temp_opts.enable_text_antialiasing = true;
    temp_opts.enable_canvas_antialiasing = true;
    temp_opts.url = None;
    opts::set_defaults(temp_opts);

    if unsafe { (*settings).windowless_rendering_enabled != 0 } {
        init_window();
    }

    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    // GWTODO: Support blocking message loop
    // again. Although, will it ever actually
    // be used or will everything use the
    // cef_do_message_loop_work function below
    // as our current miniservo apps do?
    unimplemented!()
}

#[no_mangle]
pub extern "C" fn cef_do_message_loop_work() {
    browser::update();
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
                                      _app: *mut cef_app_t,
                                      _windows_sandbox_info: *mut c_void)
                                      -> c_int {
    -1
}

#[no_mangle]
pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
    if entry == 0 {
        &CEF_API_HASH_PLATFORM[0] as *const u8 as *const c_char
    } else {
        &CEF_API_HASH_UNIVERSAL[0] as *const u8 as *const c_char
    }
}

#[no_mangle]
pub extern "C" fn cef_log(_file: *const c_char,
                          _line: c_int,
                          _severity: c_int,
                          message: *const c_char) {
    unsafe {
        let slice = ffi::CStr::from_ptr(message);
        println!("{}", str::from_utf8(slice.to_bytes()).unwrap())
    }
}

#[no_mangle]
pub extern "C" fn cef_get_min_log_level() -> c_int {
    0
}
<commit_msg>Remove unused CEF variable.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use command_line::command_line_init;
use interfaces::cef_app_t;
use types::{cef_main_args_t, cef_settings_t};
use window::init_window;

use browser;
use libc::{c_char, c_int, c_void};
use servo_config::opts;
use std::ffi;
use std::str;

//static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";

static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
#[cfg(target_os="windows")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"5c7f3e50ff5265985d11dc1a466513e25748bedd\0";
#[cfg(target_os="macos")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"6813214accbf2ebfb6bdcf8d00654650b251bf3d\0";
#[cfg(target_os="linux")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e17fa17a6d\0";

pub static mut CEF_APP: *mut cef_app_t = 0 as *mut cef_app_t;

#[no_mangle]
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
                                 settings: *mut cef_settings_t,
                                 application: *mut cef_app_t,
                                 _windows_sandbox_info: *const c_void)
                                 -> c_int {
    if args.is_null() {
        return 0;
    }
    unsafe {
        if !CEF_APP.is_null() {
            panic!("Attempting to call cef_initialize() multiple times!");
        }
    }

    unsafe {
        command_line_init((*args).argc, (*args).argv);

        if !application.is_null() {
            (*application).get_browser_process_handler.map(|cb| {
                    let handler = cb(application);
                    if !handler.is_null() {
                        (*handler).on_context_initialized.map(|hcb| hcb(handler));
                    }
            });
            CEF_APP = application;
        }
    }

    let mut temp_opts = opts::default_opts();
    temp_opts.headless = false;
    temp_opts.hard_fail = false;
    temp_opts.enable_text_antialiasing = true;
    temp_opts.enable_canvas_antialiasing = true;
    temp_opts.url = None;
    opts::set_defaults(temp_opts);

    if unsafe { (*settings).windowless_rendering_enabled != 0 } {
        init_window();
    }

    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    // GWTODO: Support blocking message loop
    // again. Although, will it ever actually
    // be used or will everything use the
    // cef_do_message_loop_work function below
    // as our current miniservo apps do?
    unimplemented!()
}

#[no_mangle]
pub extern "C" fn cef_do_message_loop_work() {
    browser::update();
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
                                      _app: *mut cef_app_t,
                                      _windows_sandbox_info: *mut c_void)
                                      -> c_int {
    -1
}

#[no_mangle]
pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
    if entry == 0 {
        &CEF_API_HASH_PLATFORM[0] as *const u8 as *const c_char
    } else {
        &CEF_API_HASH_UNIVERSAL[0] as *const u8 as *const c_char
    }
}

#[no_mangle]
pub extern "C" fn cef_log(_file: *const c_char,
                          _line: c_int,
                          _severity: c_int,
                          message: *const c_char) {
    unsafe {
        let slice = ffi::CStr::from_ptr(message);
        println!("{}", str::from_utf8(slice.to_bytes()).unwrap())
    }
}

#[no_mangle]
pub extern "C" fn cef_get_min_log_level() -> c_int {
    0
}
<|endoftext|>


<commit_before>use options::Options;
use std::any::Any;
use std::fs::File;
use std::path::Path;
use std::rc::Rc;
use toml::{self, Value};

use Result;

pub struct Config {
    node: Rc<Node>,
    path: String,
}

struct Node(Options);

impl Config {
    pub fn new<T: AsRef<Path>>(path: T) -> Result<Config> {
        use std::io::Read;

        let path = path.as_ref();
        let mut content = String::new();
        ok!(ok!(File::open(path)).read_to_string(&mut content));

        let mut node = try!(Node::parse(&content));
        if let Some(root) = path.parent() {
            node.set("root", root.to_path_buf());
        }

        Ok(Config {
            node: Rc::new(node),
            path: String::new(),
        })
    }

    pub fn get<'l, T: Any>(&'l self, path: &str) -> Option<&'l T> {
        let mut prefix = &*self.path;
        loop {
            if prefix.is_empty() {
                return self.node.lookup(path);
            }
            if let Some(value) = self.node.lookup(&format!("{}.{}", prefix, path)) {
                return Some(value);
            }
            prefix = match prefix.rfind('.') {
                Some(i) => &prefix[..i],
                _ => "",
            };
        }
    }

    pub fn branch(&self, path: &str) -> Option<Config> {
        if let None = self.get::<Node>(path) {
            return None;
        }
        Some(Config {
            node: self.node.clone(),
            path: if self.path.is_empty() {
                path.to_string()
            } else {
                format!("{}.{}", &self.path, path)
            },
        })
    }
}

impl Node {
    fn parse(content: &str) -> Result<Node> {
        use toml::Parser;

        let mut parser = Parser::new(content);
        let node = match parser.parse() {
            Some(node) => node,
            _ => {
                let mut errors = String::new();
                for error in parser.errors {
                    if !errors.is_empty() {
                        errors.push_str(", ");
                    }
                    errors.push_str(&format!("{}", error));
                }
                raise!("failed to parse the configuration file ({})", errors);
            },
        };

        Node::from(node)
    }

    fn from(mut table: toml::Table) -> Result<Node> {
        let mut options = Options::new();

        for (name, _) in &table {
            options.set(name, 0);
        }
        for (name, value) in &mut options {
            match table.remove(name).unwrap() {
                Value::Array(inner) => {
                    let mut array = vec![];
                    for inner in inner {
                        if let Value::Table(inner) = inner {
                            array.push(try!(Node::from(inner)));
                        } else {
                            raise!("extected a table");
                        }
                    }
                    value.set(array);
                },
                Value::Boolean(inner) => value.set(inner),
                Value::Datetime(inner) => value.set(inner),
                Value::Float(inner) => value.set(inner),
                Value::Integer(inner) => value.set(inner),
                Value::String(inner) => value.set(inner),
                Value::Table(inner) => value.set(try!(Node::from(inner))),
            }
        }

        Ok(Node(options))
    }

    fn lookup<'l, T: Any>(&'l self, path: &str) -> Option<&'l T> {
        let chunks = path.split('.').collect::<Vec<_>>();
        let count = chunks.len();
        let mut current = self;
        let mut i = 0;
        while i < count {
            if i + 1 == count {
                return current.0.get_ref(chunks[i]);
            }
            if let Some(node) = current.0.get_ref::<Node>(chunks[i]) {
                i += 1;
                current = node;
            } else if let Some(array) = current.0.get_ref::<Vec<Node>>(chunks[i]) {
                i += 1;
                match chunks[i].parse::<usize>() {
                    Ok(j) => if i + 1 == count {
                        return Any::downcast_ref(&array[j]);
                    } else {
                        i += 1;
                        current = &array[j];
                    },
                    _ => return None,
                }
            } else {
                return None;
            }
        }
        unreachable!()
    }

    #[inline]
    fn set<T: Any>(&mut self, name: &str, value: T) {
        self.0.set(name, value);
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use super::{Config, Node};

    #[test]
    fn branch_get() {
        let content = r#"
            qux = 69

            [foo]
            bar = 42

            [[bar.baz]]
            qux = 42
        "#;
        let config = Config {
            node: Rc::new(Node::parse(content).unwrap()),
            path: String::new(),
        };

        {
            let config = config.branch("foo").unwrap();
            assert_eq!(config.get::<i64>("bar").unwrap(), &42);
            assert_eq!(config.get::<i64>("qux").unwrap(), &69);
        }
        {
            let config = config.branch("bar").unwrap();
            assert_eq!(config.get::<i64>("qux").unwrap(), &69);
        }
        {
            let config = config.branch("bar.baz.0").unwrap();
            assert_eq!(config.get::<i64>("qux").unwrap(), &42);
        }
    }
}
<commit_msg>Implement Deref and DerefMut for Config<commit_after>use options::Options;
use std::any::Any;
use std::fs::File;
use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::rc::Rc;
use toml::{self, Value};

use Result;

pub struct Config {
    node: Rc<Node>,
    path: String,
}

struct Node(Options);

impl Config {
    pub fn new<T: AsRef<Path>>(path: T) -> Result<Config> {
        use std::io::Read;

        let path = path.as_ref();
        let mut content = String::new();
        ok!(ok!(File::open(path)).read_to_string(&mut content));

        let mut node = try!(Node::parse(&content));
        if let Some(root) = path.parent() {
            node.set("root", root.to_path_buf());
        }

        Ok(Config {
            node: Rc::new(node),
            path: String::new(),
        })
    }

    pub fn get<'l, T: Any>(&'l self, path: &str) -> Option<&'l T> {
        let mut prefix = &*self.path;
        loop {
            if prefix.is_empty() {
                return self.node.lookup(path);
            }
            if let Some(value) = self.node.lookup(&format!("{}.{}", prefix, path)) {
                return Some(value);
            }
            prefix = match prefix.rfind('.') {
                Some(i) => &prefix[..i],
                _ => "",
            };
        }
    }

    pub fn branch(&self, path: &str) -> Option<Config> {
        if let None = self.get::<Node>(path) {
            return None;
        }
        Some(Config {
            node: self.node.clone(),
            path: if self.path.is_empty() {
                path.to_string()
            } else {
                format!("{}.{}", &self.path, path)
            },
        })
    }
}

impl Node {
    fn parse(content: &str) -> Result<Node> {
        use toml::Parser;

        let mut parser = Parser::new(content);
        let node = match parser.parse() {
            Some(node) => node,
            _ => {
                let mut errors = String::new();
                for error in parser.errors {
                    if !errors.is_empty() {
                        errors.push_str(", ");
                    }
                    errors.push_str(&format!("{}", error));
                }
                raise!("failed to parse the configuration file ({})", errors);
            },
        };

        Node::from(node)
    }

    fn from(mut table: toml::Table) -> Result<Node> {
        let mut options = Options::new();

        for (name, _) in &table {
            options.set(name, 0);
        }
        for (name, value) in &mut options {
            match table.remove(name).unwrap() {
                Value::Array(inner) => {
                    let mut array = vec![];
                    for inner in inner {
                        if let Value::Table(inner) = inner {
                            array.push(try!(Node::from(inner)));
                        } else {
                            raise!("extected a table");
                        }
                    }
                    value.set(array);
                },
                Value::Boolean(inner) => value.set(inner),
                Value::Datetime(inner) => value.set(inner),
                Value::Float(inner) => value.set(inner),
                Value::Integer(inner) => value.set(inner),
                Value::String(inner) => value.set(inner),
                Value::Table(inner) => value.set(try!(Node::from(inner))),
            }
        }

        Ok(Node(options))
    }

    fn lookup<'l, T: Any>(&'l self, path: &str) -> Option<&'l T> {
        let chunks = path.split('.').collect::<Vec<_>>();
        let count = chunks.len();
        let mut current = self;
        let mut i = 0;
        while i < count {
            if i + 1 == count {
                return current.0.get_ref(chunks[i]);
            }
            if let Some(node) = current.0.get_ref::<Node>(chunks[i]) {
                i += 1;
                current = node;
            } else if let Some(array) = current.0.get_ref::<Vec<Node>>(chunks[i]) {
                i += 1;
                match chunks[i].parse::<usize>() {
                    Ok(j) => if i + 1 == count {
                        return Any::downcast_ref(&array[j]);
                    } else {
                        i += 1;
                        current = &array[j];
                    },
                    _ => return None,
                }
            } else {
                return None;
            }
        }
        unreachable!()
    }
}

impl Deref for Node {
    type Target = Options;

    #[inline]
    fn deref(&self) -> &Options {
        &self.0
    }
}

impl DerefMut for Node {
    #[inline]
    fn deref_mut(&mut self) -> &mut Options {
        &mut self.0
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use super::{Config, Node};

    #[test]
    fn branch_get() {
        let content = r#"
            qux = 69

            [foo]
            bar = 42

            [[bar.baz]]
            qux = 42
        "#;
        let config = Config {
            node: Rc::new(Node::parse(content).unwrap()),
            path: String::new(),
        };

        {
            let config = config.branch("foo").unwrap();
            assert_eq!(config.get::<i64>("bar").unwrap(), &42);
            assert_eq!(config.get::<i64>("qux").unwrap(), &69);
        }
        {
            let config = config.branch("bar").unwrap();
            assert_eq!(config.get::<i64>("qux").unwrap(), &69);
        }
        {
            let config = config.branch("bar.baz.0").unwrap();
            assert_eq!(config.get::<i64>("qux").unwrap(), &42);
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "An atomically reference counted wrapper that can be used to
share immutable data between tasks."]

import comm::{port, chan, methods};

export arc, get, clone, shared_arc, get_arc;

#[abi = "cdecl"]
native mod rustrt {
    #[rust_stack]
    fn rust_atomic_increment(p: &mut libc::intptr_t)
        -> libc::intptr_t;

    #[rust_stack]
    fn rust_atomic_decrement(p: &mut libc::intptr_t)
        -> libc::intptr_t;
}

type arc_data<T: const> = {
    mut count: libc::intptr_t,
    data: T
};

resource arc_destruct<T: const>(data: *libc::c_void) {
    unsafe {
        let data: ~arc_data<T> = unsafe::reinterpret_cast(data);
        let ref_ptr = &mut data.count;

        let new_count = rustrt::rust_atomic_decrement(ref_ptr);
        assert new_count >= 0;
        if new_count == 0 {
            // drop glue takes over.
        } else {
            unsafe::forget(data);
        }
    }
}

type arc<T: const> = arc_destruct<T>;

#[doc="Create an atomically reference counted wrapper."]
fn arc<T: const>(-data: T) -> arc<T> {
    let data = ~{mut count: 1, data: data};
    unsafe {
        let ptr = unsafe::reinterpret_cast(data);
        unsafe::forget(data);
        arc_destruct(ptr)
    }
}

#[doc="Access the underlying data in an atomically reference counted
 wrapper."]
fn get<T: const>(rc: &a.arc<T>) -> &a.T {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        // Cast us back into the correct region
        let r = unsafe::reinterpret_cast(&ptr.data);
        unsafe::forget(ptr);
        ret r;
    }
}

#[doc="Duplicate an atomically reference counted wrapper.

The resulting two `arc` objects will point to the same underlying data
object. However, one of the `arc` objects can be sent to another task,
allowing them to share the underlying data."]
fn clone<T: const>(rc: &arc<T>) -> arc<T> {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        rustrt::rust_atomic_increment(&mut ptr.count);
        unsafe::forget(ptr);
    }
    arc_destruct(**rc)
}

// Convenience code for sharing arcs between tasks

enum proto<T: send const> {
    terminate,
    shared_get(comm::chan<arc::arc<T>>)
}

resource shared_arc_res<T: send const>(c: comm::chan<proto<T>>) {
    c.send(terminate);
}

fn shared_arc<T: send const>(-data: T) -> shared_arc_res<T> {
    let a = arc::arc(data);
    let c = task::spawn_listener::<proto<T>>() {|p, move a|
        let mut live = true;
        while live {
            alt p.recv() {
              terminate { live = false; }
              shared_get(cc) {
                cc.send(arc::clone(&a));
              }
            }
        }
    };
    shared_arc_res(c)
}

fn get_arc<T: send const>(c: comm::chan<proto<T>>) -> arc::arc<T> {
    let p = port();
    c.send(shared_get(chan(p)));
    p.recv()
}

#[cfg(test)]
mod tests {
    import comm::*;

    #[test]
    fn manually_share_arc() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let arc_v = arc::arc(v);

        let p = port();
        let c = chan(p);

        task::spawn() {||
            let p = port();
            c.send(chan(p));

            let arc_v = p.recv();

            let v = *arc::get::<[int]>(&arc_v);
            assert v[3] == 4;
        };

        let c = p.recv();
        c.send(arc::clone(&arc_v));

        assert (*arc::get(&arc_v))[2] == 3;

        log(info, arc_v);
    }
}
<commit_msg>Rewriting shared_arc to work around Issue #2444.<commit_after>#[doc = "An atomically reference counted wrapper that can be used to
share immutable data between tasks."]

import comm::{port, chan, methods};

export arc, get, clone, shared_arc, get_arc;

#[abi = "cdecl"]
native mod rustrt {
    #[rust_stack]
    fn rust_atomic_increment(p: &mut libc::intptr_t)
        -> libc::intptr_t;

    #[rust_stack]
    fn rust_atomic_decrement(p: &mut libc::intptr_t)
        -> libc::intptr_t;
}

type arc_data<T: const> = {
    mut count: libc::intptr_t,
    data: T
};

resource arc_destruct<T: const>(data: *libc::c_void) {
    unsafe {
        let data: ~arc_data<T> = unsafe::reinterpret_cast(data);
        let ref_ptr = &mut data.count;

        let new_count = rustrt::rust_atomic_decrement(ref_ptr);
        assert new_count >= 0;
        if new_count == 0 {
            // drop glue takes over.
        } else {
            unsafe::forget(data);
        }
    }
}

type arc<T: const> = arc_destruct<T>;

#[doc="Create an atomically reference counted wrapper."]
fn arc<T: const>(-data: T) -> arc<T> {
    let data = ~{mut count: 1, data: data};
    unsafe {
        let ptr = unsafe::reinterpret_cast(data);
        unsafe::forget(data);
        arc_destruct(ptr)
    }
}

#[doc="Access the underlying data in an atomically reference counted
 wrapper."]
fn get<T: const>(rc: &a.arc<T>) -> &a.T {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        // Cast us back into the correct region
        let r = unsafe::reinterpret_cast(&ptr.data);
        unsafe::forget(ptr);
        ret r;
    }
}

#[doc="Duplicate an atomically reference counted wrapper.

The resulting two `arc` objects will point to the same underlying data
object. However, one of the `arc` objects can be sent to another task,
allowing them to share the underlying data."]
fn clone<T: const>(rc: &arc<T>) -> arc<T> {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        rustrt::rust_atomic_increment(&mut ptr.count);
        unsafe::forget(ptr);
    }
    arc_destruct(**rc)
}

// Convenience code for sharing arcs between tasks

type get_chan<T: const send> = chan<chan<arc<T>>>;

// (terminate, get)
type shared_arc<T: const send> = (shared_arc_res, get_chan<T>);

resource shared_arc_res(c: comm::chan<()>) {
    c.send(());
}

fn shared_arc<T: send const>(-data: T) -> shared_arc<T> {
    let a = arc::arc(data);
    let p = port();
    let c = chan(p);
    task::spawn() {|move a|
        let mut live = true;
        let terminate = port();
        let get = port();

        c.send((chan(terminate), chan(get)));

        while live {
            alt comm::select2(terminate, get) {
              either::left(()) { live = false; }
              either::right(cc) {
                comm::send(cc, arc::clone(&a));
              }
            }
        }
    };
    let (terminate, get) = p.recv();
    (shared_arc_res(terminate), get)
}

fn get_arc<T: send const>(c: get_chan<T>) -> arc::arc<T> {
    let p = port();
    c.send(chan(p));
    p.recv()
}

#[cfg(test)]
mod tests {
    import comm::*;

    #[test]
    fn manually_share_arc() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let arc_v = arc::arc(v);

        let p = port();
        let c = chan(p);

        task::spawn() {||
            let p = port();
            c.send(chan(p));

            let arc_v = p.recv();

            let v = *arc::get::<[int]>(&arc_v);
            assert v[3] == 4;
        };

        let c = p.recv();
        c.send(arc::clone(&arc_v));

        assert (*arc::get(&arc_v))[2] == 3;

        log(info, arc_v);
    }

    #[test]
    fn auto_share_arc() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let (res, arc_c) = shared_arc(v);

        let p = port();
        let c = chan(p);

        task::spawn() {||
            let arc_v = get_arc(arc_c);
            let v = *get(&arc_v);
            assert v[2] == 3;

            c.send(());
        };

        assert p.recv() == ();
    }
}
<|endoftext|>


<commit_before>//! The linalg module provides some basic linear algebra functionality for
//! transforming 3D geometry

use std::f32;
use std::ops::{Index, Mul, Add};

// Re-export the linalg types from the internal modules
pub use self::vector::Vector;
pub use self::normal::Normal;
pub use self::point::Point;
pub use self::ray::Ray;
pub use self::matrix4::Matrix4;
pub use self::transform::Transform;

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;

/// Enum representing on of the 3 spatial axes
#[derive(Copy, Clone)]
pub enum Axis { X, Y, Z }

/// Convert value in degrees to radians
/// TODO: See where `f32::to_radians` ends up, if it gets stabilized into Rust switch back to it
pub fn to_radians(d: f32) -> f32 {
    f32::consts::PI / 180.0 * d
}
/// Compute the cross product of two vectors
pub fn cross<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> vector::Vector {
    Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/// Lerp between `a` and `b` at some distance `t` where t is in [0, 1]
/// and t = 0 returns `a` and t = 1 returns `b`
pub fn lerp<T: Mul<f32, Output = T> + Add<Output = T> + Copy>(t: f32, a: &T, b: &T) -> T {
    *a * (1.0 - t) + *b * t
}
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> vector::Vector {
    Vector::new(sin_theta * f32::cos(phi), sin_theta * f32::sin(phi),
                cos_theta)
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    f32::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match f32::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI_2,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim = f32::sqrt(b * b - 4f32 * a * c);
    if f32::is_nan(discrim) {
        None
    } else {
        let q = if b < 0f32 { -0.5f32 * (b - discrim) } else { -0.5f32 * (b + discrim) };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}

#[test]
fn test_cross() {
    let a = Vector::new(1f32, 0f32, 0f32);
    let b = Vector::new(0f32, 1f32, 0f32);
    let c = cross(&a, &b);
    assert!(c == Vector::new(0f32, 0f32, 1f32));
}

#[test]
fn test_dot() {
    let a = Vector::new(1f32, 2f32, 3f32);
    let b = Vector::new(4f32, 5f32, 6f32);
    assert!(dot(&a, &b) == 1f32 * 4f32 + 2f32 * 5f32 + 3f32 * 6f32);
}

<commit_msg>Implement debug for Axis<commit_after>//! The linalg module provides some basic linear algebra functionality for
//! transforming 3D geometry

use std::f32;
use std::ops::{Index, Mul, Add};

// Re-export the linalg types from the internal modules
pub use self::vector::Vector;
pub use self::normal::Normal;
pub use self::point::Point;
pub use self::ray::Ray;
pub use self::matrix4::Matrix4;
pub use self::transform::Transform;

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;

/// Enum representing on of the 3 spatial axes
#[derive(Copy, Clone, Debug)]
pub enum Axis { X, Y, Z }

/// Convert value in degrees to radians
/// TODO: See where `f32::to_radians` ends up, if it gets stabilized into Rust switch back to it
pub fn to_radians(d: f32) -> f32 {
    f32::consts::PI / 180.0 * d
}
/// Compute the cross product of two vectors
pub fn cross<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> vector::Vector {
    Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/// Lerp between `a` and `b` at some distance `t` where t is in [0, 1]
/// and t = 0 returns `a` and t = 1 returns `b`
pub fn lerp<T: Mul<f32, Output = T> + Add<Output = T> + Copy>(t: f32, a: &T, b: &T) -> T {
    *a * (1.0 - t) + *b * t
}
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> vector::Vector {
    Vector::new(sin_theta * f32::cos(phi), sin_theta * f32::sin(phi),
                cos_theta)
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    f32::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match f32::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI_2,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim = f32::sqrt(b * b - 4f32 * a * c);
    if f32::is_nan(discrim) {
        None
    } else {
        let q = if b < 0f32 { -0.5f32 * (b - discrim) } else { -0.5f32 * (b + discrim) };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}

#[test]
fn test_cross() {
    let a = Vector::new(1f32, 0f32, 0f32);
    let b = Vector::new(0f32, 1f32, 0f32);
    let c = cross(&a, &b);
    assert!(c == Vector::new(0f32, 0f32, 1f32));
}

#[test]
fn test_dot() {
    let a = Vector::new(1f32, 2f32, 3f32);
    let b = Vector::new(4f32, 5f32, 6f32);
    assert!(dot(&a, &b) == 1f32 * 4f32 + 2f32 * 5f32 + 3f32 * 6f32);
}

<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use super::system::get_all_data;
use utils;
use DiskExt;
use DiskType;

use libc::statvfs;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

macro_rules! cast {
    ($x:expr) => {
        u64::from($x)
    };
}

/// Struct containing a disk information.
#[derive(PartialEq)]
pub struct Disk {
    type_: DiskType,
    name: OsString,
    file_system: Vec<u8>,
    mount_point: PathBuf,
    total_space: u64,
    available_space: u64,
}

impl DiskExt for Disk {
    fn get_type(&self) -> DiskType {
        self.type_
    }

    fn get_name(&self) -> &OsStr {
        &self.name
    }

    fn get_file_system(&self) -> &[u8] {
        &self.file_system
    }

    fn get_mount_point(&self) -> &Path {
        &self.mount_point
    }

    fn get_total_space(&self) -> u64 {
        self.total_space
    }

    fn get_available_space(&self) -> u64 {
        self.available_space
    }

    fn refresh(&mut self) -> bool {
        unsafe {
            let mut stat: statvfs = mem::zeroed();
            let mount_point_cpath = utils::to_cpath(&self.mount_point);
            if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
                let tmp = cast!(stat.f_bsize) * cast!(stat.f_bavail);
                self.available_space = cast!(tmp);
                true
            } else {
                false
            }
        }
    }
}

fn new_disk(name: &OsStr, mount_point: &Path, file_system: &[u8]) -> Option<Disk> {
    let mount_point_cpath = utils::to_cpath(mount_point);
    let type_ = find_type_for_name(name);
    let mut total = 0;
    let mut available = 0;
    unsafe {
        let mut stat: statvfs = mem::zeroed();
        if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
            total = cast!(stat.f_bsize) * cast!(stat.f_blocks);
            available = cast!(stat.f_bsize) * cast!(stat.f_bavail);
        }
    }
    if total == 0 {
        return None;
    }
    Some(Disk {
        type_,
        name: name.to_owned(),
        file_system: file_system.to_owned(),
        mount_point: mount_point.to_owned(),
        total_space: cast!(total),
        available_space: cast!(available),
    })
}

fn find_type_for_name(name: &OsStr) -> DiskType {
    // The format of devices are as follows:
    //  - name_path is symbolic link in the case of /dev/mapper/
    //     and /dev/root, and the target is corresponding device under
    //     /sys/block/
    //  - In the case of /dev/sd, the format is /dev/sd[a-z][1-9],
    //     corresponding to /sys/block/sd[a-z]
    //  - In the case of /dev/nvme, the format is /dev/nvme[0-9]n[0-9]p[0-9],
    //     corresponding to /sys/block/nvme[0-9]n[0-9]
    //  - In the case of /dev/mmcblk, the format is /dev/mmcblk[0-9]p[0-9],
    //     corresponding to /sys/block/mmcblk[0-9]
    let name_path = name.to_str().unwrap_or_default();
    let real_path = fs::canonicalize(name_path).unwrap_or_else(|_| PathBuf::from(name_path));
    let mut real_path = real_path.to_str().unwrap_or_default();
    if name_path.starts_with("/dev/mapper/") {
        // Recursively solve, for example /dev/dm-0
        return find_type_for_name(OsStr::new(&real_path));
    } else if name_path.starts_with("/dev/sd") {
        // Turn "sda1" into "sda"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
    } else if name_path.starts_with("/dev/nvme") {
        // Turn "nvme0n1p1" into "nvme0n1"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
        real_path = real_path.trim_end_matches(|c| c == 'p');
    } else if name_path.starts_with("/dev/root") {
        // Recursively solve, for example /dev/mmcblk0p1
        return find_type_for_name(OsStr::new(&real_path));
    } else if name_path.starts_with("/dev/mmcblk") {
        // Turn "mmcblk0p1" into "mmcblk0"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
        real_path = real_path.trim_end_matches(|c| c == 'p');
    } else {
        // Default case: remove /dev/ and expects the name presents under /sys/block/
        // For example, /dev/dm-0 to dm-0
        real_path = real_path.trim_start_matches("/dev/");
    }

    let trimmed: &OsStr = OsStrExt::from_bytes(real_path.as_bytes());

    let path = Path::new("/sys/block/")
        .to_owned()
        .join(trimmed)
        .join("queue/rotational");
    // Normally, this file only contains '0' or '1' but just in case, we get 8 bytes...
    let rotational_int = get_all_data(path, 8).unwrap_or_default().trim().parse();
    DiskType::from(rotational_int.unwrap_or(-1))
}

fn get_all_disks_inner(content: &str) -> Vec<Disk> {
    content
        .lines()
        .map(|line| {
            let line = line.trim_start();
            // mounts format
            // http://man7.org/linux/man-pages/man5/fstab.5.html
            // fs_spec<tab>fs_file<tab>fs_vfstype<tab>other fields
            let mut fields = line.split_whitespace();
            let fs_spec = fields.next().unwrap_or("");
            let fs_file = fields.next().unwrap_or("");
            let fs_vfstype = fields.next().unwrap_or("");
            (fs_spec, fs_file, fs_vfstype)
        })
        .filter(|(fs_spec, fs_file, fs_vfstype)| {
            // Check if fs_vfstype is one of our 'ignored' file systems.
            let filtered = match *fs_vfstype {
                "sysfs" | // pseudo file system for kernel objects
                "proc" |  // another pseudo file system
                "tmpfs" |
                "cgroup" |
                "cgroup2" |
                "pstore" | // https://www.kernel.org/doc/Documentation/ABI/testing/pstore
                "squashfs" | // squashfs is a compressed read-only file system (for snaps)
                "rpc_pipefs" | // The pipefs pseudo file system service
                "iso9660" => true, // optical media
                _ => false,
            };

            !(filtered ||
               fs_file.starts_with("/sys") || // check if fs_file is an 'ignored' mount point
               fs_file.starts_with("/proc") ||
               fs_file.starts_with("/run") ||
               fs_spec.starts_with("sunrpc"))
        })
        .filter_map(|(fs_spec, fs_file, fs_vfstype)| {
            new_disk(fs_spec.as_ref(), Path::new(fs_file), fs_vfstype.as_bytes())
        })
        .collect()
}

pub fn get_all_disks() -> Vec<Disk> {
    get_all_disks_inner(&get_all_data("/proc/mounts", 16_385).unwrap_or_default())
}

// #[test]
// fn check_all_disks() {
//     let disks = get_all_disks_inner(
//         r#"tmpfs /proc tmpfs rw,seclabel,relatime 0 0
// proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
// systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=17771 0 0
// tmpfs /sys tmpfs rw,seclabel,relatime 0 0
// sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
// cgroup2 /sys/fs/cgroup cgroup2 rw,seclabel,nosuid,nodev,noexec,relatime,nsdelegate 0 0
// pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// none /sys/fs/bpf bpf rw,nosuid,nodev,noexec,relatime,mode=700 0 0
// configfs /sys/kernel/config configfs rw,nosuid,nodev,noexec,relatime 0 0
// selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
// debugfs /sys/kernel/debug debugfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// tmpfs /dev/shm tmpfs rw,seclabel,relatime 0 0
// devpts /dev/pts devpts rw,seclabel,relatime,gid=5,mode=620,ptmxmode=666 0 0
// tmpfs /sys/fs/selinux tmpfs rw,seclabel,relatime 0 0
// /dev/vda2 /proc/filesystems xfs rw,seclabel,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
// "#,
//     );
//     assert_eq!(disks.len(), 1);
//     assert_eq!(
//         disks[0],
//         Disk {
//             type_: DiskType::Unknown(-1),
//             name: OsString::from("devpts"),
//             file_system: vec![100, 101, 118, 112, 116, 115],
//             mount_point: PathBuf::from("/dev/pts"),
//             total_space: 0,
//             available_space: 0,
//         }
//     );
// }
<commit_msg>Prevent infinite recursion when getting disk<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use super::system::get_all_data;
use utils;
use DiskExt;
use DiskType;

use libc::statvfs;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

macro_rules! cast {
    ($x:expr) => {
        u64::from($x)
    };
}

/// Struct containing a disk information.
#[derive(PartialEq)]
pub struct Disk {
    type_: DiskType,
    name: OsString,
    file_system: Vec<u8>,
    mount_point: PathBuf,
    total_space: u64,
    available_space: u64,
}

impl DiskExt for Disk {
    fn get_type(&self) -> DiskType {
        self.type_
    }

    fn get_name(&self) -> &OsStr {
        &self.name
    }

    fn get_file_system(&self) -> &[u8] {
        &self.file_system
    }

    fn get_mount_point(&self) -> &Path {
        &self.mount_point
    }

    fn get_total_space(&self) -> u64 {
        self.total_space
    }

    fn get_available_space(&self) -> u64 {
        self.available_space
    }

    fn refresh(&mut self) -> bool {
        unsafe {
            let mut stat: statvfs = mem::zeroed();
            let mount_point_cpath = utils::to_cpath(&self.mount_point);
            if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
                let tmp = cast!(stat.f_bsize) * cast!(stat.f_bavail);
                self.available_space = cast!(tmp);
                true
            } else {
                false
            }
        }
    }
}

fn new_disk(name: &OsStr, mount_point: &Path, file_system: &[u8]) -> Option<Disk> {
    let mount_point_cpath = utils::to_cpath(mount_point);
    let type_ = find_type_for_name(name);
    let mut total = 0;
    let mut available = 0;
    unsafe {
        let mut stat: statvfs = mem::zeroed();
        if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
            total = cast!(stat.f_bsize) * cast!(stat.f_blocks);
            available = cast!(stat.f_bsize) * cast!(stat.f_bavail);
        }
    }
    if total == 0 {
        return None;
    }
    Some(Disk {
        type_,
        name: name.to_owned(),
        file_system: file_system.to_owned(),
        mount_point: mount_point.to_owned(),
        total_space: cast!(total),
        available_space: cast!(available),
    })
}

fn find_type_for_name(name: &OsStr) -> DiskType {
    // The format of devices are as follows:
    //  - name_path is symbolic link in the case of /dev/mapper/
    //     and /dev/root, and the target is corresponding device under
    //     /sys/block/
    //  - In the case of /dev/sd, the format is /dev/sd[a-z][1-9],
    //     corresponding to /sys/block/sd[a-z]
    //  - In the case of /dev/nvme, the format is /dev/nvme[0-9]n[0-9]p[0-9],
    //     corresponding to /sys/block/nvme[0-9]n[0-9]
    //  - In the case of /dev/mmcblk, the format is /dev/mmcblk[0-9]p[0-9],
    //     corresponding to /sys/block/mmcblk[0-9]
    let name_path = name.to_str().unwrap_or_default();
    let real_path = fs::canonicalize(name_path).unwrap_or_else(|_| PathBuf::from(name_path));
    let mut real_path = real_path.to_str().unwrap_or_default();
    if name_path.starts_with("/dev/mapper/") {
        // Recursively solve, for example /dev/dm-0
        return find_type_for_name(OsStr::new(&real_path));
    } else if name_path.starts_with("/dev/sd") {
        // Turn "sda1" into "sda"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
    } else if name_path.starts_with("/dev/nvme") {
        // Turn "nvme0n1p1" into "nvme0n1"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
        real_path = real_path.trim_end_matches(|c| c == 'p');
    } else if name_path.starts_with("/dev/root") {
        // Recursively solve, for example /dev/mmcblk0p1
        if real_path != name_path {
            return find_type_for_name(OsStr::new(&real_path));
        }
    } else if name_path.starts_with("/dev/mmcblk") {
        // Turn "mmcblk0p1" into "mmcblk0"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
        real_path = real_path.trim_end_matches(|c| c == 'p');
    } else {
        // Default case: remove /dev/ and expects the name presents under /sys/block/
        // For example, /dev/dm-0 to dm-0
        real_path = real_path.trim_start_matches("/dev/");
    }

    let trimmed: &OsStr = OsStrExt::from_bytes(real_path.as_bytes());

    let path = Path::new("/sys/block/")
        .to_owned()
        .join(trimmed)
        .join("queue/rotational");
    // Normally, this file only contains '0' or '1' but just in case, we get 8 bytes...
    let rotational_int = get_all_data(path, 8).unwrap_or_default().trim().parse();
    DiskType::from(rotational_int.unwrap_or(-1))
}

fn get_all_disks_inner(content: &str) -> Vec<Disk> {
    content
        .lines()
        .map(|line| {
            let line = line.trim_start();
            // mounts format
            // http://man7.org/linux/man-pages/man5/fstab.5.html
            // fs_spec<tab>fs_file<tab>fs_vfstype<tab>other fields
            let mut fields = line.split_whitespace();
            let fs_spec = fields.next().unwrap_or("");
            let fs_file = fields.next().unwrap_or("");
            let fs_vfstype = fields.next().unwrap_or("");
            (fs_spec, fs_file, fs_vfstype)
        })
        .filter(|(fs_spec, fs_file, fs_vfstype)| {
            // Check if fs_vfstype is one of our 'ignored' file systems.
            let filtered = match *fs_vfstype {
                "sysfs" | // pseudo file system for kernel objects
                "proc" |  // another pseudo file system
                "tmpfs" |
                "cgroup" |
                "cgroup2" |
                "pstore" | // https://www.kernel.org/doc/Documentation/ABI/testing/pstore
                "squashfs" | // squashfs is a compressed read-only file system (for snaps)
                "rpc_pipefs" | // The pipefs pseudo file system service
                "iso9660" => true, // optical media
                _ => false,
            };

            !(filtered ||
               fs_file.starts_with("/sys") || // check if fs_file is an 'ignored' mount point
               fs_file.starts_with("/proc") ||
               fs_file.starts_with("/run") ||
               fs_spec.starts_with("sunrpc"))
        })
        .filter_map(|(fs_spec, fs_file, fs_vfstype)| {
            new_disk(fs_spec.as_ref(), Path::new(fs_file), fs_vfstype.as_bytes())
        })
        .collect()
}

pub fn get_all_disks() -> Vec<Disk> {
    get_all_disks_inner(&get_all_data("/proc/mounts", 16_385).unwrap_or_default())
}

// #[test]
// fn check_all_disks() {
//     let disks = get_all_disks_inner(
//         r#"tmpfs /proc tmpfs rw,seclabel,relatime 0 0
// proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
// systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=17771 0 0
// tmpfs /sys tmpfs rw,seclabel,relatime 0 0
// sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
// cgroup2 /sys/fs/cgroup cgroup2 rw,seclabel,nosuid,nodev,noexec,relatime,nsdelegate 0 0
// pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// none /sys/fs/bpf bpf rw,nosuid,nodev,noexec,relatime,mode=700 0 0
// configfs /sys/kernel/config configfs rw,nosuid,nodev,noexec,relatime 0 0
// selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
// debugfs /sys/kernel/debug debugfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// tmpfs /dev/shm tmpfs rw,seclabel,relatime 0 0
// devpts /dev/pts devpts rw,seclabel,relatime,gid=5,mode=620,ptmxmode=666 0 0
// tmpfs /sys/fs/selinux tmpfs rw,seclabel,relatime 0 0
// /dev/vda2 /proc/filesystems xfs rw,seclabel,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
// "#,
//     );
//     assert_eq!(disks.len(), 1);
//     assert_eq!(
//         disks[0],
//         Disk {
//             type_: DiskType::Unknown(-1),
//             name: OsString::from("devpts"),
//             file_system: vec![100, 101, 118, 112, 116, 115],
//             mount_point: PathBuf::from("/dev/pts"),
//             total_space: 0,
//             available_space: 0,
//         }
//     );
// }
<|endoftext|>


<commit_before>use std::io;
use std::io::BufRead;
use std::io::Write;
use chrono::*;
use http_status::HttpStatus;

// http://stackoverflow.com/a/27590832/376138
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub url: String
}

impl Request {
    fn new_from_log_line(log_line: &String) -> Result<Request, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = match parts.get(2) {
            Some(id) =>  id,
            None => return Err("Uncomprehensible request logline")
        };

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible request logline");
        }

        let id_parsed: i32 = match id[1..id.len()-1].parse() {
            Ok(id) =>  id,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        let url = match parts.get(5) {
            Some(url) =>  url,
            None => return Err("Uncomprehensible request logline")
        };

        let date = &format!("{} {}", parts[0], parts[1]);

        let date_parsed = match DateTime::parse_from_str(date, "%d/%b/%Y:%H:%M:%S %z") {
            Ok(date_time) => date_time,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        Ok(Request {
            id: id_parsed,
            time: date_parsed,
            url: url.to_string()
        })
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub mime_type: String,
    pub response_time: Duration,
    pub http_status: HttpStatus,
}

impl Response {
    fn new_from_log_line(log_line: &String) -> Result<Response, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let id_numeric: i32 = match id[1..id.len()-1].parse() {
            Ok(number) => number,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let time = match DateTime::parse_from_str(&format!("{} {}", parts[0], parts[1]), "%d/%b/%Y:%H:%M:%S %z") {
            Ok(time) => time,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let response_time = parts[parts.len()-1];
        if response_time.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let response_time_duration = match response_time[0..response_time.len()-2].parse() {
            Ok(number) => Duration::milliseconds(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        // Handle special case where the mime type sometimes contains
        // a space, so we need to re-assemble it
        let mime_type = match parts.len() {
            8 => format!("{} {}", parts[5], parts[6]),
            _ => parts[5].to_string()
        };

        let status_code = match parts[4].parse() {
            Ok(number) => HttpStatus::from_code(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        Ok(Response {
            id: id_numeric,
            time: time,
            response_time: response_time_duration,
            mime_type: mime_type,
            http_status: status_code,
        })
    }
}

pub fn parse(reader: &mut io::Read) -> Result<(Vec<Request>,Vec<Response>), &'static str> {
    let input = io::BufReader::new(reader);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in input.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            match Request::new_from_log_line(&line_value) {
                Ok(r) => {
                    // if time_filter.is_none() ||
                    //   (time_filter.is_some() && r.is_between_times(UTC::now().with_timezone(&r.time.timezone()) - time_filter.unwrap(), UTC::now().with_timezone(&r.time.timezone()))) {
                        requests.push(r);
                    // }
                },
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

        if line_value.contains("<-") {
            match Response::new_from_log_line(&line_value) {
                Ok(r) => responses.push(r),
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

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

    fn base_parsing_test(file_path: &str, expected_request_count: usize, expected_response_count: usize) -> (Vec<Request>,Vec<Response>) {
        let mut input_reader = File::open(file_path).unwrap();

        let (requests, responses) = parse(&mut input_reader).unwrap();

        assert_eq!(requests.len(), expected_request_count);
        assert_eq!(responses.len(), expected_response_count);

        (requests, responses)
    }

    #[test]
    fn test_parse_simple() {
        base_parsing_test("src/test/simple-1.log", 2, 2);
    }
}
<commit_msg>Revert "Extract test for common scenario, DRY"<commit_after>use std::io;
use std::io::BufRead;
use std::io::Write;
use chrono::*;
use http_status::HttpStatus;

// http://stackoverflow.com/a/27590832/376138
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub url: String
}

impl Request {
    fn new_from_log_line(log_line: &String) -> Result<Request, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = match parts.get(2) {
            Some(id) =>  id,
            None => return Err("Uncomprehensible request logline")
        };

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible request logline");
        }

        let id_parsed: i32 = match id[1..id.len()-1].parse() {
            Ok(id) =>  id,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        let url = match parts.get(5) {
            Some(url) =>  url,
            None => return Err("Uncomprehensible request logline")
        };

        let date = &format!("{} {}", parts[0], parts[1]);

        let date_parsed = match DateTime::parse_from_str(date, "%d/%b/%Y:%H:%M:%S %z") {
            Ok(date_time) => date_time,
            Err(_) => return Err("Uncomprehensible request logline")
        };

        Ok(Request {
            id: id_parsed,
            time: date_parsed,
            url: url.to_string()
        })
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    pub id: i32,
    pub time: DateTime<FixedOffset>,
    pub mime_type: String,
    pub response_time: Duration,
    pub http_status: HttpStatus,
}

impl Response {
    fn new_from_log_line(log_line: &String) -> Result<Response, &'static str> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];

        // Shortest valid id format is "[1]"
        if id.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let id_numeric: i32 = match id[1..id.len()-1].parse() {
            Ok(number) => number,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let time = match DateTime::parse_from_str(&format!("{} {}", parts[0], parts[1]), "%d/%b/%Y:%H:%M:%S %z") {
            Ok(time) => time,
            Err(_) => return Err("Uncomprehensible response logline")
        };

        let response_time = parts[parts.len()-1];
        if response_time.len() < 3 {
            return Err("Uncomprehensible response logline");
        }

        let response_time_duration = match response_time[0..response_time.len()-2].parse() {
            Ok(number) => Duration::milliseconds(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        // Handle special case where the mime type sometimes contains
        // a space, so we need to re-assemble it
        let mime_type = match parts.len() {
            8 => format!("{} {}", parts[5], parts[6]),
            _ => parts[5].to_string()
        };

        let status_code = match parts[4].parse() {
            Ok(number) => HttpStatus::from_code(number),
            Err(_) => return Err("Uncomprehensible response logline")
        };

        Ok(Response {
            id: id_numeric,
            time: time,
            response_time: response_time_duration,
            mime_type: mime_type,
            http_status: status_code,
        })
    }
}

pub fn parse(reader: &mut io::Read) -> Result<(Vec<Request>,Vec<Response>), &'static str> {
    let input = io::BufReader::new(reader);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in input.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            match Request::new_from_log_line(&line_value) {
                Ok(r) => {
                    // if time_filter.is_none() ||
                    //   (time_filter.is_some() && r.is_between_times(UTC::now().with_timezone(&r.time.timezone()) - time_filter.unwrap(), UTC::now().with_timezone(&r.time.timezone()))) {
                        requests.push(r);
                    // }
                },
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

        if line_value.contains("<-") {
            match Response::new_from_log_line(&line_value) {
                Ok(r) => responses.push(r),
                Err(err) => println_stderr!("Skipped a line: {}", err)
            }
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

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

    #[test]
    fn test_parse_simple() {
        let mut input_reader = File::open("src/test/simple-1.log").unwrap();

        let (requests, responses) = parse(&mut input_reader).unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }
}
<|endoftext|>


<commit_before>extern crate glium;
#[macro_use]
extern crate korome;

use korome::*;

fn main() {
    let draw = Draw::new("korome works!", 800, 600);

    let planet = include_texture!(draw, "planet.png", 64, 64).unwrap();

    let mut objs = Vec::new();

    objs.push(Object::new(&planet, -400., 300., 0.));

    let game = Game::with_shared(draw, objs, logic, render);

    game.run_until_closed();
}

struct Object<'a>{
    pos: Vector2<f32>,
    theta: f32,
    tex: &'a Texture
}

impl<'a> Object<'a>{
    fn new(tex: &'a Texture, x: f32, y: f32, theta: f32) -> Self{
        Object{
            tex: tex,
            pos: Vector2(x, y),
            theta: theta,
        }
    }
}

impl<'a> Sprite for Object<'a>{
    fn get_pos(&self) -> (f32, f32){
        self.pos.into()
    }

    fn get_rotation(&self) -> f32{
        self.theta
    }

    fn get_texture(&self) -> &Texture{
        self.tex
    }
}

fn logic(objs: &mut Vec<Object>, l_args: LogicArgs){
    let ref mut planet = objs[0];

    let delta = l_args.delta as f32;

    let vel = 200.0 * delta;
    let pos = &mut planet.pos;

    is_down!{
        l_args;

        Left, A => {
            pos.0 -= vel
        },
        Right, D => {
            pos.0 += vel
        },
        Down , S => {
            pos.1 -= vel
        },
        Up   , W => {
            pos.1 += vel
        },
        E => {
            planet.theta += delta
        },
        Q => {
            planet.theta -= delta
        }
    }
}

fn render(objs: &Vec<Object>, mut r_args: RenderArgs){
    //.rotate() doesn't actually work properly right now
    r_args.draw_sprites(objs)
        .unwrap_or_else(|e| panic!("{}", e))
}
<commit_msg>Comment basic<commit_after>extern crate glium;
#[macro_use]
extern crate korome;

use korome::*;

fn main() {
    // Create the draw object, which creates a window with the given title and dimensions
    let draw = Draw::new("korome works!", 800, 600);

    // Load a texture, whose bytes have been loaded at compile-time with the given dimensions
    let planet = include_texture!(draw, "planet.png", 64, 64).unwrap();

    // Create a vector and push the objects to it
    let mut objs = Vec::new();
    objs.push(Object::new(&planet, -400., 300., 0.));

    // Create the game instance with objs as the shared
    let game = Game::with_shared(draw, objs, logic, render);
    game.run_until_closed();
}

struct Object<'a>{
    pos: Vector2<f32>,
    theta: f32,
    tex: &'a Texture
}

impl<'a> Object<'a>{
    fn new(tex: &'a Texture, x: f32, y: f32, theta: f32) -> Self{
        Object{
            tex: tex,
            pos: Vector2(x, y),
            theta: theta,
        }
    }
}

impl<'a> Sprite for Object<'a>{
    fn get_pos(&self) -> (f32, f32){
        self.pos.into()
    }

    fn get_rotation(&self) -> f32{
        self.theta
    }

    fn get_texture(&self) -> &Texture{
        self.tex
    }
}

fn logic(objs: &mut Vec<Object>, l_args: LogicArgs){
    // Get a mutable reference so we can move it
    let ref mut planet = objs[0];

    let delta = l_args.delta as f32;

    // Set the velocity the 200 pixels per second
    let vel = 200.0 * delta;
    let pos = &mut planet.pos;

    // Make the planet move with WASD and the arrow keys and rotate with Q and E
    is_down!{
        l_args;

        Left, A => {
            pos.0 -= vel
        },
        Right, D => {
            pos.0 += vel
        },
        Down , S => {
            pos.1 -= vel
        },
        Up   , W => {
            pos.1 += vel
        },
        E => {
            planet.theta += delta
        },
        Q => {
            planet.theta -= delta
        }
    }
}

fn render(objs: &Vec<Object>, mut r_args: RenderArgs){
    // Draw all sprites in objs
    r_args.draw_sprites(objs).unwrap();
}
<|endoftext|>


<commit_before>extern crate nock;
extern crate urbit;
extern crate num;

use std::env;
use std::io::prelude::*;
use std::fs::File;
use num::bigint::BigUint;
use num::traits::One;
use nock::{Noun, Shape};
use urbit::VM;

fn main() {
    let mut file = File::open(env::args()
                                  .nth(1)
                                  .expect("Usage urbit [urbit.pill]"))
                       .unwrap();

    let mut buf = Vec::new();
    file.read_to_end(&mut buf).unwrap();
    println!("Unpacking pill");
    let noun = urbit::unpack_pill(buf).unwrap();
    println!("Unpacked pill");

    let count: BigUint = noun.fold(|x| {
        match x {
            Shape::Cell(p, q) => p + q,
            _ => One::one(),
        }
    });

    println!("Pill has {} atoms", count);

    println!("Nocking pill");
    let mut vm = VM::new();
    let noun = vm.nock_on(Noun::from(0u32), noun).unwrap();
    println!("Result: {}", noun);
}
<commit_msg>Handle eval failure in urbit example<commit_after>extern crate nock;
extern crate urbit;
extern crate num;

use std::env;
use std::io::prelude::*;
use std::fs::File;
use num::bigint::BigUint;
use num::traits::One;
use nock::{Noun, Shape};
use urbit::VM;

fn main() {
    let mut file = File::open(env::args()
                                  .nth(1)
                                  .expect("Usage urbit [urbit.pill]"))
                       .unwrap();

    let mut buf = Vec::new();
    file.read_to_end(&mut buf).unwrap();
    println!("Unpacking pill");
    let noun = urbit::unpack_pill(buf).unwrap();
    println!("Unpacked pill");

    let count: BigUint = noun.fold(|x| {
        match x {
            Shape::Cell(p, q) => p + q,
            _ => One::one(),
        }
    });

    println!("Pill has {} atoms", count);

    println!("Nocking pill");
    let mut vm = VM::new();
    let noun = vm.nock_on(Noun::from(0u32), noun);
    vm.print_status();
    println!("Result: {:?}", noun);
}
<|endoftext|>


<commit_before>//  notty is a new kind of terminal emulator.
//  Copyright (C) 2015 without boats
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
use std::io;

use command::*;
use datatypes::args::*;
use grapheme_tables as gr;

mod ansi;
mod notty;

use self::ansi::AnsiData;
use self::notty::NottyData;
use self::State::*;

/// The `Output` struct processes data written to the terminal from the controlling process,
/// parsing it into structured commands. It is implemented as an `Iterator`.
pub struct Output<R: io::BufRead> {
    tty: io::Chars<R>,
    state: State,
    ansi: AnsiData,
    notty: NottyData,
}

impl<R: io::BufRead> Output<R> {

    /// Create a new output processor wrapping a buffered read interface to the tty.
    pub fn new(tty: R) -> Output<R> {
        Output {
            tty: tty.chars(),
            state: Character,
            ansi: AnsiData::default(),
            notty: NottyData::default(),
        }
    }

    fn character(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        use grapheme_tables::GraphemeCat::*;
        match gr::grapheme_category(ch) {
            GC_Any                      => (Character, wrap(Put::new_char(ch))),
            GC_Control                  => match ch {
                '\x07'      => (Character, wrap(Bell)),
                '\x08'      => (Character, wrap(Move::new(To(Left, 1, true)))),
                '\t'        => (Character, wrap(Move::new(Tab(Right, 1, true)))),
                '\n'        => (Character, wrap(Move::new(NextLine(1)))),
                '\r'        => (Character, wrap(Move::new(ToEdge(Left)))),
                '\x1b'      => (EscCode, None),
                '\x7f'      => (Character, wrap(Erase::new(CursorCell))),
                '\u{90}'    => (DcsCode, None),
                '\u{9b}'    => (CsiCode, None),
                '\u{9d}'    => (OscCode, None),
                '\u{9e}'    => (PrivMsg, None),
                '\u{9f}'    => (ApmCode, None),
                _           => (Character, None),
            },
            GC_Extend | GC_SpacingMark  => (Character, wrap(Put::new_extension(ch))),
            _                           => unimplemented!(),
        }
    }

    fn esc_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        match ch {
            ' ' => {
                static IGNORE: &'static [char] = &['F', 'G', 'L', 'N'];
                (Ignore(IGNORE), None)
            }
            '#' => {
                static IGNORE: &'static [char] = &['3', '4', '5', '6', '8'];
                (Ignore(IGNORE), None)
            }
            '%' => {
                static IGNORE: &'static [char] = &['@', 'G'];
                (Ignore(IGNORE), None)
            }
            '('...'/'   => {
                static IGNORE: &'static [char] = &[
                    '0', '<', '>', '%', 'A', 'B', '4', 'C', '5', 'R', 'f', 'Q', '9', 'K', 'Y',
                    '`', 'E', '6', 'Z', 'H', '7', '=',
                ];
                (Ignore(IGNORE), None)
            }
            'E' => (Character, wrap(Move::new(NextLine(1)))),
            'P' => (DcsCode, None),
            '[' => (CsiCode, None),
            ']' => (OscCode, None),
            '^' => (PrivMsg, None),
            '_' => (ApmCode, None),
            _   => (Character, wrap(NoFeature(ch.to_string()))),
        }
    }

    fn csi_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        static CSI_PRIVATE_MODES:   &'static [char] = &['>', '?'];
        static CSI_PRETERMINALS:    &'static [char] = &[' ', '!', '"', '$', '\'', '*'];
        static CSI_TERMINALS:       &'static [char] = &[
            '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'P', 'S',
            'T', 'X', 'Z', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l', 'm', 'n',
            'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
        ];

        // Private mode.
        if self.ansi.private_mode == '\0' && self.ansi.args.len() == 0 &&
            CSI_PRIVATE_MODES.contains(&ch) {
                self.ansi.private_mode = ch;
                (CsiCode, None)
        }
        // Digit.
        else if self.ansi.preterminal == '\0' && ch.is_digit(10) {
            self.ansi.arg_buf.push(ch);
            (CsiCode, None)
        }
        // Arg separator.
        else if self.ansi.preterminal == '\0' && ch == ';' {
            let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
            self.ansi.args.push(n);
            self.ansi.arg_buf.clear();
            (CsiCode, None)
        }
        // Preterminal.
        else if self.ansi.preterminal == '\0' && CSI_PRETERMINALS.contains(&ch) {
            if self.ansi.arg_buf.len() > 0 {
                let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
                self.ansi.args.push(n);
                self.ansi.arg_buf.clear();
            }
            self.ansi.preterminal = ch;
            (CsiCode, None)
        }
        // Terminal.
        else if CSI_TERMINALS.contains(&ch) {
            if self.ansi.arg_buf.len() > 0 {
                let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
                self.ansi.args.push(n);
                self.ansi.arg_buf.clear();
            }
            let ret = (Character, self.ansi.csi(ch));
            self.ansi.clear();
            ret
        }
        // Invalid.
        else {
            self.ansi.clear();
            (Character, None)
        }
    }

    #[allow(unused)]
    fn dcs_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        unimplemented!()
    }

    fn osc_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        if ch.is_digit(10) && self.ansi.private_mode == '\0' {
            self.ansi.arg_buf.push(ch);
            (OscCode, None)
        }
        else if ch == ';' && self.ansi.private_mode == '\0' {
            let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
            self.ansi.args.push(n);
            self.ansi.arg_buf.clear();
            self.ansi.private_mode = ';';
            (OscCode, None)
        }
        else if ch == '\x1b' && self.ansi.preterminal == '\0' {
            self.ansi.preterminal == '\x1b';
            (OscCode, None)
        }
        else if ch == '\u{9c}' || ch == '\x07' || (ch == '\\' && self.ansi.preterminal == '\x1b') {
            let ret = (Character, self.ansi.osc());
            self.ansi.clear();
            ret
        }
        else if self.ansi.private_mode == ';' {
            if self.ansi.preterminal == '\x1b' {
                self.ansi.arg_buf.push('\x1b');
                self.ansi.preterminal = '\0';
            }
            self.ansi.arg_buf.push(ch);
            (OscCode, None)
        }
        else {
            self.ansi.clear();
            self.character(ch)
        }
    }

    fn apm_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        match ch {
            '[' => (NottyCode, None),
            _   => self.privacy_message(ch),
        }
    }

    fn privacy_message(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        match (self.ansi.preterminal, ch) {
            ('\0', '\x1b')                                  => {
                self.ansi.preterminal = ch;
                (PrivMsg, None)
            }
            (_, '\u{9c}') | (_, '\x07') | ('\x1b', '\\')    => (Character, None),
            ('\0', _)                                       => (PrivMsg, None),
            (_, _)                                          => self.character(ch),
        }
    }

    fn notty_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        if ch.is_digit(16) || ch == ';' || ch == '.' {
            self.notty.args.push(ch);
            (NottyCode, None)
        }
        else if ch == '#' {
            (NottyAttach, None)
        }
        else if ch == '\x07' {
            let ret = (Character, self.notty.parse());
            self.notty.clear();
            ret
        }
        else {
            self.notty.clear();
            (Character, None)
        }
    }

}

impl<R: io::BufRead> Iterator for super::Output<R> {
    type Item = io::Result<Box<Command>>;
    fn next(&mut self) -> Option<io::Result<Box<Command>>> {
        loop {
            match self.tty.next() {
                Some(Ok(ch))                            => {
                    let (state, cmd) = match self.state {
                        Character       => self.character(ch),
                        EscCode         => self.esc_code(ch),
                        CsiCode         => self.csi_code(ch),
                        DcsCode         => self.dcs_code(ch),
                        OscCode         => self.osc_code(ch),
                        ApmCode         => self.apm_code(ch),
                        PrivMsg         => self.privacy_message(ch),
                        NottyCode       => self.notty_code(ch),
                        NottyAttach     => {
                            match self.notty.attachments.append(ch) {
                                Some(true)  => (Character, self.notty.parse()),
                                Some(false) => (Character, None),
                                None        => (NottyAttach, None),
                            }
                        }
                        Ignore(chars)   => {
                            if chars.contains(&ch) { continue }
                            else { self.character(ch) }
                        }
                    };
                    self.state = state;
                    match cmd {
                        Some(cmd)   => return Some(Ok(cmd)),
                        None        => continue
                    }
                },
                Some(Err(io::CharsError::NotUtf8))      => continue,
                Some(Err(io::CharsError::Other(err)))   => return Some(Err(err)),
                None                                    => return None,
            }
        }
    }
}

enum State {
    Character,
    EscCode,
    CsiCode,
    #[allow(dead_code)]
    DcsCode,
    OscCode,
    ApmCode,
    PrivMsg,
    NottyCode,
    NottyAttach,
    Ignore(&'static [char]),
}

fn wrap<T: Command>(cmd: T) -> Option<Box<Command>> {
    Some(Box::new(cmd) as Box<Command>)
}

#[cfg(test)]
mod tests {

    use std::io::BufReader;

    use command::*;
    use super::*;

    fn setup(data: &[u8]) -> Output<BufReader<&[u8]>> {
        Output::new(BufReader::new(data))
    }

    #[test]
    fn graphemes() {
        let mut output = setup("E\u{301}\u{1f4a9}E".as_bytes());
        assert_eq!(&output.next().unwrap().unwrap().repr(), "E");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "\u{301}");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "\u{1f4a9}");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "E");
    }

    #[test]
    fn ctrl_codes() {
        let mut output = setup(b"AB\x07C\n");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "BELL");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "C");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "MOVE NEXT LINE 1");
    }

    #[test]
    fn csi_code() {
        let mut output = setup(b"\x1b[7;7HB\x1b[7A\x1b[$rA\x1b[?12h");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "MOVE TO 6,6");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "MOVE UP 7");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "DEFAULT STYLE IN AREA");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SERIES: SET CURSOR STYLE");
    }

    #[test]
    fn osc_code() {
        let mut output = setup(b"A\x1b]0;Hello, world!\x07B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SET TITLE");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
    }

    #[test]
    fn notty_code() {
        let mut output = setup(b"A\x1b_[30;8.ff.ff.ff\x07\x1b_[19;1;2\x07B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SET TEXT STYLE");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SCROLL SCREEN");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
    }

}
<commit_msg>Fixed acronym typo.<commit_after>//  notty is a new kind of terminal emulator.
//  Copyright (C) 2015 without boats
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
use std::io;

use command::*;
use datatypes::args::*;
use grapheme_tables as gr;

mod ansi;
mod notty;

use self::ansi::AnsiData;
use self::notty::NottyData;
use self::State::*;

/// The `Output` struct processes data written to the terminal from the controlling process,
/// parsing it into structured commands. It is implemented as an `Iterator`.
pub struct Output<R: io::BufRead> {
    tty: io::Chars<R>,
    state: State,
    ansi: AnsiData,
    notty: NottyData,
}

impl<R: io::BufRead> Output<R> {

    /// Create a new output processor wrapping a buffered read interface to the tty.
    pub fn new(tty: R) -> Output<R> {
        Output {
            tty: tty.chars(),
            state: Character,
            ansi: AnsiData::default(),
            notty: NottyData::default(),
        }
    }

    fn character(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        use grapheme_tables::GraphemeCat::*;
        match gr::grapheme_category(ch) {
            GC_Any                      => (Character, wrap(Put::new_char(ch))),
            GC_Control                  => match ch {
                '\x07'      => (Character, wrap(Bell)),
                '\x08'      => (Character, wrap(Move::new(To(Left, 1, true)))),
                '\t'        => (Character, wrap(Move::new(Tab(Right, 1, true)))),
                '\n'        => (Character, wrap(Move::new(NextLine(1)))),
                '\r'        => (Character, wrap(Move::new(ToEdge(Left)))),
                '\x1b'      => (EscCode, None),
                '\x7f'      => (Character, wrap(Erase::new(CursorCell))),
                '\u{90}'    => (DcsCode, None),
                '\u{9b}'    => (CsiCode, None),
                '\u{9d}'    => (OscCode, None),
                '\u{9e}'    => (PrivMsg, None),
                '\u{9f}'    => (ApcCode, None),
                _           => (Character, None),
            },
            GC_Extend | GC_SpacingMark  => (Character, wrap(Put::new_extension(ch))),
            _                           => unimplemented!(),
        }
    }

    fn esc_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        match ch {
            ' ' => {
                static IGNORE: &'static [char] = &['F', 'G', 'L', 'N'];
                (Ignore(IGNORE), None)
            }
            '#' => {
                static IGNORE: &'static [char] = &['3', '4', '5', '6', '8'];
                (Ignore(IGNORE), None)
            }
            '%' => {
                static IGNORE: &'static [char] = &['@', 'G'];
                (Ignore(IGNORE), None)
            }
            '('...'/'   => {
                static IGNORE: &'static [char] = &[
                    '0', '<', '>', '%', 'A', 'B', '4', 'C', '5', 'R', 'f', 'Q', '9', 'K', 'Y',
                    '`', 'E', '6', 'Z', 'H', '7', '=',
                ];
                (Ignore(IGNORE), None)
            }
            'E' => (Character, wrap(Move::new(NextLine(1)))),
            'P' => (DcsCode, None),
            '[' => (CsiCode, None),
            ']' => (OscCode, None),
            '^' => (PrivMsg, None),
            '_' => (ApcCode, None),
            _   => (Character, wrap(NoFeature(ch.to_string()))),
        }
    }

    fn csi_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        static CSI_PRIVATE_MODES:   &'static [char] = &['>', '?'];
        static CSI_PRETERMINALS:    &'static [char] = &[' ', '!', '"', '$', '\'', '*'];
        static CSI_TERMINALS:       &'static [char] = &[
            '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'P', 'S',
            'T', 'X', 'Z', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l', 'm', 'n',
            'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
        ];

        // Private mode.
        if self.ansi.private_mode == '\0' && self.ansi.args.len() == 0 &&
            CSI_PRIVATE_MODES.contains(&ch) {
                self.ansi.private_mode = ch;
                (CsiCode, None)
        }
        // Digit.
        else if self.ansi.preterminal == '\0' && ch.is_digit(10) {
            self.ansi.arg_buf.push(ch);
            (CsiCode, None)
        }
        // Arg separator.
        else if self.ansi.preterminal == '\0' && ch == ';' {
            let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
            self.ansi.args.push(n);
            self.ansi.arg_buf.clear();
            (CsiCode, None)
        }
        // Preterminal.
        else if self.ansi.preterminal == '\0' && CSI_PRETERMINALS.contains(&ch) {
            if self.ansi.arg_buf.len() > 0 {
                let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
                self.ansi.args.push(n);
                self.ansi.arg_buf.clear();
            }
            self.ansi.preterminal = ch;
            (CsiCode, None)
        }
        // Terminal.
        else if CSI_TERMINALS.contains(&ch) {
            if self.ansi.arg_buf.len() > 0 {
                let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
                self.ansi.args.push(n);
                self.ansi.arg_buf.clear();
            }
            let ret = (Character, self.ansi.csi(ch));
            self.ansi.clear();
            ret
        }
        // Invalid.
        else {
            self.ansi.clear();
            (Character, None)
        }
    }

    #[allow(unused)]
    fn dcs_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        unimplemented!()
    }

    fn osc_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        if ch.is_digit(10) && self.ansi.private_mode == '\0' {
            self.ansi.arg_buf.push(ch);
            (OscCode, None)
        }
        else if ch == ';' && self.ansi.private_mode == '\0' {
            let n = u32::from_str_radix(&self.ansi.arg_buf, 10).unwrap();
            self.ansi.args.push(n);
            self.ansi.arg_buf.clear();
            self.ansi.private_mode = ';';
            (OscCode, None)
        }
        else if ch == '\x1b' && self.ansi.preterminal == '\0' {
            self.ansi.preterminal == '\x1b';
            (OscCode, None)
        }
        else if ch == '\u{9c}' || ch == '\x07' || (ch == '\\' && self.ansi.preterminal == '\x1b') {
            let ret = (Character, self.ansi.osc());
            self.ansi.clear();
            ret
        }
        else if self.ansi.private_mode == ';' {
            if self.ansi.preterminal == '\x1b' {
                self.ansi.arg_buf.push('\x1b');
                self.ansi.preterminal = '\0';
            }
            self.ansi.arg_buf.push(ch);
            (OscCode, None)
        }
        else {
            self.ansi.clear();
            self.character(ch)
        }
    }

    fn apc_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        match ch {
            '[' => (NottyCode, None),
            _   => self.privacy_message(ch),
        }
    }

    fn privacy_message(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        match (self.ansi.preterminal, ch) {
            ('\0', '\x1b')                                  => {
                self.ansi.preterminal = ch;
                (PrivMsg, None)
            }
            (_, '\u{9c}') | (_, '\x07') | ('\x1b', '\\')    => (Character, None),
            ('\0', _)                                       => (PrivMsg, None),
            (_, _)                                          => self.character(ch),
        }
    }

    fn notty_code(&mut self, ch: char) -> (State, Option<Box<Command>>) {
        if ch.is_digit(16) || ch == ';' || ch == '.' {
            self.notty.args.push(ch);
            (NottyCode, None)
        }
        else if ch == '#' {
            (NottyAttach, None)
        }
        else if ch == '\x07' {
            let ret = (Character, self.notty.parse());
            self.notty.clear();
            ret
        }
        else {
            self.notty.clear();
            (Character, None)
        }
    }

}

impl<R: io::BufRead> Iterator for super::Output<R> {
    type Item = io::Result<Box<Command>>;
    fn next(&mut self) -> Option<io::Result<Box<Command>>> {
        loop {
            match self.tty.next() {
                Some(Ok(ch))                            => {
                    let (state, cmd) = match self.state {
                        Character       => self.character(ch),
                        EscCode         => self.esc_code(ch),
                        CsiCode         => self.csi_code(ch),
                        DcsCode         => self.dcs_code(ch),
                        OscCode         => self.osc_code(ch),
                        ApcCode         => self.apc_code(ch),
                        PrivMsg         => self.privacy_message(ch),
                        NottyCode       => self.notty_code(ch),
                        NottyAttach     => {
                            match self.notty.attachments.append(ch) {
                                Some(true)  => (Character, self.notty.parse()),
                                Some(false) => (Character, None),
                                None        => (NottyAttach, None),
                            }
                        }
                        Ignore(chars)   => {
                            if chars.contains(&ch) { continue }
                            else { self.character(ch) }
                        }
                    };
                    self.state = state;
                    match cmd {
                        Some(cmd)   => return Some(Ok(cmd)),
                        None        => continue
                    }
                },
                Some(Err(io::CharsError::NotUtf8))      => continue,
                Some(Err(io::CharsError::Other(err)))   => return Some(Err(err)),
                None                                    => return None,
            }
        }
    }
}

enum State {
    Character,
    EscCode,
    CsiCode,
    #[allow(dead_code)]
    DcsCode,
    OscCode,
    ApcCode,
    PrivMsg,
    NottyCode,
    NottyAttach,
    Ignore(&'static [char]),
}

fn wrap<T: Command>(cmd: T) -> Option<Box<Command>> {
    Some(Box::new(cmd) as Box<Command>)
}

#[cfg(test)]
mod tests {

    use std::io::BufReader;

    use command::*;
    use super::*;

    fn setup(data: &[u8]) -> Output<BufReader<&[u8]>> {
        Output::new(BufReader::new(data))
    }

    #[test]
    fn graphemes() {
        let mut output = setup("E\u{301}\u{1f4a9}E".as_bytes());
        assert_eq!(&output.next().unwrap().unwrap().repr(), "E");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "\u{301}");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "\u{1f4a9}");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "E");
    }

    #[test]
    fn ctrl_codes() {
        let mut output = setup(b"AB\x07C\n");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "BELL");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "C");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "MOVE NEXT LINE 1");
    }

    #[test]
    fn csi_code() {
        let mut output = setup(b"\x1b[7;7HB\x1b[7A\x1b[$rA\x1b[?12h");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "MOVE TO 6,6");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "MOVE UP 7");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "DEFAULT STYLE IN AREA");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SERIES: SET CURSOR STYLE");
    }

    #[test]
    fn osc_code() {
        let mut output = setup(b"A\x1b]0;Hello, world!\x07B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SET TITLE");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
    }

    #[test]
    fn notty_code() {
        let mut output = setup(b"A\x1b_[30;8.ff.ff.ff\x07\x1b_[19;1;2\x07B");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "A");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SET TEXT STYLE");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "SCROLL SCREEN");
        assert_eq!(&output.next().unwrap().unwrap().repr(), "B");
    }

}
<|endoftext|>


<commit_before>//! stdio convenience fns
#[allow(unused_must_use)]

use std::io::{stderr, stdout, Write};
use std::env;

pub const EXIT_OK: i32 = 0;
pub const EXIT_ERR: i32 = 1;

pub fn err_msg(msg: &str) {
    let exe_path = match env::current_exe() {
        Ok(p) => p.to_string_lossy().into_owned(),
        _ => String::from(""),
    };
    writeln!(&mut stderr(), "{}: {}", exe_path, msg).unwrap();
}

// by default stdout only flushes
// to console when a newline is passed.
#[allow(unused_must_use)]
pub fn flush_char(c: &char) {
    print!("{}", c);
    stdout().flush();
}
#[allow(unused_must_use)]
pub fn flush_str(s: &str) {
    print!("{}", s);
    stdout().flush();
}
#[allow(unused_must_use)]
pub fn flush_bytes(bslice: &[u8]) {
    stdout().write(bslice);
    stdout().flush();
}
<commit_msg>refactor/polish ~ fix `cargo clippy` complaints (remove allow unused_must_use)<commit_after>//! stdio convenience fns

use std::io::{stderr, stdout, Write};
use std::env;

pub const EXIT_OK: i32 = 0;
pub const EXIT_ERR: i32 = 1;

pub fn err_msg(msg: &str) {
    let exe_path = match env::current_exe() {
        Ok(p) => p.to_string_lossy().into_owned(),
        _ => String::from(""),
    };
    writeln!(&mut stderr(), "{}: {}", exe_path, msg).unwrap();
}

// by default stdout only flushes
// to console when a newline is passed.
#[allow(unused_must_use)]
pub fn flush_char(c: &char) {
    print!("{}", c);
    stdout().flush();
}
#[allow(unused_must_use)]
pub fn flush_str(s: &str) {
    print!("{}", s);
    stdout().flush();
}
#[allow(unused_must_use)]
pub fn flush_bytes(bslice: &[u8]) {
    stdout().write(bslice);
    stdout().flush();
}
<|endoftext|>