<commit_before>// leave this to allow easy breakpoints on assembly wrappers like _write for now
#![allow(private_no_mangle_fns)]

use std::str;
use std::slice;

#[macro_export]
macro_rules! dbg {
    ($dbg:expr, $fmt:expr) =>
        (if $dbg {
        ( print!(
            concat!(
                concat!(
                    colorify!(green: "<dryad> "),
                    $fmt),
                "\n")));

        });
    ($dbg:expr, $fmt:expr, $($arg:tt)*) =>
        (if $dbg {
        ( print!(
            concat!(
                concat!(
                    colorify!(green: "<dryad> "),
                    $fmt),
                "\n"),
            $($arg)*) );
        });

}

#[macro_export]
macro_rules! dbgc {
    ($c:ident: $dbg:expr, $prefix:expr, $fmt:expr) =>
        ( if $dbg {
            ( print!(
                concat!(
                    concat!(
                        colorify!($c: concat!($prefix, " ")),
                        $fmt),
                    "\n")));
        } );

    ($c:ident: $dbg:expr, $prefix:expr, $fmt:expr, $($arg:tt)*) =>
        ( if $dbg {
            ( print!(
                concat!(
                    concat!(
                        colorify!($c: concat!($prefix, " ")),
                        $fmt),
                    "\n"),
                $($arg)*) );
        } );
}

// TODO: make this a mod like asm::

#[no_mangle]
pub extern fn _exit(code: u64) {
    unsafe {
        asm!("movq $$60, %rax
              syscall"
             :
             : "{rdi}"(code)
             );
    }
}

// this comes from asm.s
extern {
    pub fn _print(msg: *const u8, len: u64);
}

/*
fn _print(msg: *const u8, len: u64) {
    unsafe {
        let slice = slice::from_raw_parts(msg, len as usize);
        println!("{:?}", &slice);
    }
}
*/

#[no_mangle]
pub unsafe extern fn write(msg: &str){
    _print(msg.as_ptr(), msg.len() as u64);
}

/*
#[cfg(debug_assertions)]
macro_rules! debug_write {
    ($($t:tt)*) => {
        unsafe {
            write($($t)*)
        }
    }
}

#[cfg(not(debug_assertions))]
macro_rules! debug_write {
    ($($t:tt)*) => {
    }
}
*/

// this is _totally_ broken and is massively side-effectful and unpredicatable
/*
#[no_mangle]
pub extern fn write(msg: &str) {
    unsafe {
        asm!("pushq %rdi
              pushq %rax
              pushq %rdx
              pushq %rsi
              movq $$1, %rax
              movq $$2, %rdi
              syscall
              popq %rsi
              popq %rdx
              popq %rax
              popq %rdi
              "
             :
             : "{rsi}"(msg.as_ptr()), "{rdx}"(msg.len())
//             : "{rdi}","{rax}", "{rdx}", "{rsi}"
             //             :"{rsi}"(msg.as_ptr()), "{rdx}"(msg.len())
             //
             );
    }
}
*/
fn digit_to_char_code(i: u8) -> u8 {
    if i <= 9 {
        i + 48
    }else{
        0
    }
}

fn num_digits(i: u64) -> usize {
    if i == 0 {
        1
    } else {
        let mut count = 0;
        let mut current = i;
        while current > 0 {
            current /= 10;
            count += 1;
        }
        count
    }
}

#[test]
fn num_digits_t() {
    assert_eq!(num_digits(0), 1);
    assert_eq!(num_digits(10), 2);
    assert_eq!(num_digits(99), 2);
    assert_eq!(num_digits(999), 3);
}

#[no_mangle]
pub unsafe extern fn write_u64(i: u64, base16: bool) {
    if base16 {
        write(to_hex(&i, &mut [0; 16]));
    } else {
        let count = num_digits(i);
        let mut _stack = [0; 20];
        let mut chars = &mut _stack[0..count];
        let mut place = count;
        let mut current = i;
        let mut digit;
        loop {
            digit = current % 10;
            current = (current - digit) / 10;
            place -= 1;
            chars[place] = digit_to_char_code(digit as u8);
            if current <= 0 { break; }
        }
        write(str::from_utf8(chars).unwrap());
    }
}

fn to_hex<'a>(i: &u64, output: &'a mut[u8; 16]) -> &'a str {
    let mut input = *i;
    let hex = b"0123456789abcdef";
    let mut buffer = [0; 16];
    let mut i = 0;
    let mut j = 0;
    if input == 0 {
        buffer[0] = hex[0];
        i = 1;
    } else {
        while input > 0 {
            buffer[i] = hex[(input % 16) as usize];
            input = input / 16;
            i += 1;
        }
    }

    while i > 0 {
        i -= 1;
        output[j] = buffer[i];
        j += 1;
    }
    str::from_utf8(output).unwrap().trim_matches('\0')
}

pub fn as_str<'a>(cs: *const u8) -> &'a str {
    if cs.is_null() {
        ""
    }else {
        let mut i = 0;
        unsafe {
            let mut c = *cs;
            while c != 0 {
                i += 1;
                c = *cs.offset(i);
            }
            let slice = slice::from_raw_parts(cs, i as usize);
            str::from_utf8(slice).unwrap()
        }
    }
}

pub fn str_at<'a>(cs: *const u8, offset: isize) -> &'a str {
    if cs.is_null() {
        ""
    }else {
        let mut i = 0;
        unsafe {
            let ptr = cs.offset(offset);
            let mut c = *ptr;
            while c != 0 {
                i += 1;
                c = *ptr.offset(i);
            }
            let slice = slice::from_raw_parts(ptr, i as usize);
            str::from_utf8(slice).unwrap()
        }
    }
}

pub unsafe extern fn write_chars_at(cs: *const u8) {
    write(as_str(cs));
}

extern {
    /// libc #defines errno *(__errno_location()) ... so errno isn't a symbol in the actual binary and accesses will segfault us. yay.
    fn __errno_location() -> *const i32;
}

#[inline(always)]
pub fn get_errno () -> i32 {
    unsafe { *__errno_location() }
}

/// We're required to set the rust panic hook/handler because otherwise we segfault in `static_dl_iterate_phdr` when libstd tries to unwind the stack
/// **NB**: Make sure this is called _after_ relocation, since we need to allocate the closure on the heap
pub fn set_panic () {
    ::std::panic::set_hook(Box::new(|panic| {
        dbgc!(orange_bold: true, "<dryad>", r#"Thamus, are you there? When you reach Palodes, take care to proclaim that the great god Pan is dead."#);
        if let Some(location) = panic.location() {
            println!("-=|dryad====- died in {}:{}", location.file(), location.line());
        }
        let payload = panic.payload ();
        // pretty much copied from libstd's panicking default, cause it's pretty
        let msg = match payload.downcast_ref::<&'static str>() {
            Some(s) => s,
            None => match payload.downcast_ref::<String>() {
                Some(s) => &s[..],
                None => "Box<Any>",
            }
        };
        dbgc!(orange_bold: true, "<dryad>", "Died because {}", msg);
        _exit(1);
    }));
}

pub mod page {
   // from <sys/user.h>
    pub const PAGE_SHIFT: u64    = 12;
    pub const PAGE_SIZE: u64     = 1 << PAGE_SHIFT;
    const PAGE_SIZE_MINUS_1: u64 = PAGE_SIZE - 1;
    pub const PAGE_MASK: u64     = !PAGE_SIZE_MINUS_1;

    // from bionic
    /// Returns the address of the page containing address 'x'.
    #[inline(always)]
    pub fn page_start (x: u64) -> u64 { x & PAGE_MASK }

    /// Returns the offset of address 'x' in its page.
    #[inline(always)]
    pub fn page_offset (x: u64) -> u64 { x & PAGE_SIZE_MINUS_1 }

    /// Returns the address of the next page after address 'x', unless 'x' is
    /// itself at the start of a page.
    #[inline(always)]
    pub fn page_end (x: u64) -> u64 { page_start(x + PAGE_SIZE_MINUS_1) }

    #[test]
    fn t_page_start () {
        assert_eq!(page_start(0x1000), 0x1000)
    }

}

pub mod mmap {
    use std::os::raw::{c_int};
    use std::fs::File;
    use std::os::unix::io::AsRawFd;

    pub const PROT_READ: isize = 0x1; /* Page can be read.  */
    pub const PROT_WRITE: isize = 0x2; /* Page can be written.  */
    pub const PROT_EXEC: isize = 0x4; /* Page can be executed.  */
    pub const PROT_NONE: isize = 0x0; /* Page can not be accessed.  */
    pub const PROT_GROWSDOWN: isize = 0x01000000; /* Extend change to start of growsdown vma (mprotect only).  */
    pub const PROT_GROWSUP: isize = 0x02000000; /* Extend change to start of growsup vma (mprotect only).  */

    /* Sharing types (must choose one and only one of these).  */
    pub const MAP_FILE: isize = 0x0; /* no flag bits to map a file  */
    pub const MAP_SHARED: isize = 0x01; /* Share changes.  */
    pub const MAP_PRIVATE: isize = 0x02; /* Changes are private.  */
    pub const MAP_ANONYMOUS: isize = 0x20; // just guessing, this is wrapped in a ifdef with __MAP_ANONYMOUS as the value
    /* Other flags.  */
    pub const MAP_DENYWRITE: isize = 0x800;
    pub const MAP_COPY: isize = MAP_PRIVATE | MAP_DENYWRITE;
    pub const MAP_FIXED: isize = 0x10; /* Interpret addr exactly.  */

    /// map failed, from sys/mman.h, technically ((void *) - 1) ...
    pub const MAP_FAILED: u64 = !0;

    // from musl libc
    extern {
        fn mmap64(addr: *const u64, len: usize, prot: isize, flags: c_int, fildes: c_int, off: usize) -> u64;
    }

    #[inline(always)]
    pub unsafe fn mmap(addr: *const u64, len: usize, prot: isize, flags: c_int, fildes: c_int, off: usize) -> u64 {
        mmap64(addr, len, prot, flags, fildes, off)
    }

    #[inline(always)]
    fn map_fragment(fd: &File, base: u64, offset: u64, size: usize) -> Result<(u64, usize, *const u64), String> {
        use utils::page;
        let offset = base + offset;
        let page_min = page::page_start(offset);
        let end_offset = offset + size as u64;
        let end_offset = end_offset + page::page_offset(offset);

        let map_size: usize = (end_offset - page_min) as usize;

        if map_size < size {
            return Err (format!("<dryad> Error: file {:#?} has map_size = {} < size = {}, aborting", fd, map_size, size))
        }

        let map_start = unsafe { mmap(0 as *const u64,
                                            map_size,
                                            PROT_READ,
                                            MAP_PRIVATE as c_int,
                                            fd.as_raw_fd() as c_int,
                                            page_min as usize) };

        if map_start == MAP_FAILED {

            Err (format!("<dryad> Error: mmap failed for {:#?} with errno {}, aborting", fd, super::get_errno()))

        } else {

            let data = (map_start + page::page_offset(offset)) as *const u64;
            Ok ((map_start, map_size, data))
        }
    }

}
<commit_msg>utils: use dryad_panic as dbg prefix<commit_after>// leave this to allow easy breakpoints on assembly wrappers like _write for now
#![allow(private_no_mangle_fns)]

use std::str;
use std::slice;

#[macro_export]
macro_rules! dbg {
    ($dbg:expr, $fmt:expr) =>
        (if $dbg {
        ( print!(
            concat!(
                concat!(
                    colorify!(green: "<dryad> "),
                    $fmt),
                "\n")));

        });
    ($dbg:expr, $fmt:expr, $($arg:tt)*) =>
        (if $dbg {
        ( print!(
            concat!(
                concat!(
                    colorify!(green: "<dryad> "),
                    $fmt),
                "\n"),
            $($arg)*) );
        });

}

#[macro_export]
macro_rules! dbgc {
    ($c:ident: $dbg:expr, $prefix:expr, $fmt:expr) =>
        ( if $dbg {
            ( print!(
                concat!(
                    concat!(
                        colorify!($c: concat!($prefix, " ")),
                        $fmt),
                    "\n")));
        } );

    ($c:ident: $dbg:expr, $prefix:expr, $fmt:expr, $($arg:tt)*) =>
        ( if $dbg {
            ( print!(
                concat!(
                    concat!(
                        colorify!($c: concat!($prefix, " ")),
                        $fmt),
                    "\n"),
                $($arg)*) );
        } );
}

// TODO: make this a mod like asm::

#[no_mangle]
pub extern fn _exit(code: u64) {
    unsafe {
        asm!("movq $$60, %rax
              syscall"
             :
             : "{rdi}"(code)
             );
    }
}

// this comes from asm.s
extern {
    pub fn _print(msg: *const u8, len: u64);
}

/*
fn _print(msg: *const u8, len: u64) {
    unsafe {
        let slice = slice::from_raw_parts(msg, len as usize);
        println!("{:?}", &slice);
    }
}
*/

#[no_mangle]
pub unsafe extern fn write(msg: &str){
    _print(msg.as_ptr(), msg.len() as u64);
}

/*
#[cfg(debug_assertions)]
macro_rules! debug_write {
    ($($t:tt)*) => {
        unsafe {
            write($($t)*)
        }
    }
}

#[cfg(not(debug_assertions))]
macro_rules! debug_write {
    ($($t:tt)*) => {
    }
}
*/

// this is _totally_ broken and is massively side-effectful and unpredicatable
/*
#[no_mangle]
pub extern fn write(msg: &str) {
    unsafe {
        asm!("pushq %rdi
              pushq %rax
              pushq %rdx
              pushq %rsi
              movq $$1, %rax
              movq $$2, %rdi
              syscall
              popq %rsi
              popq %rdx
              popq %rax
              popq %rdi
              "
             :
             : "{rsi}"(msg.as_ptr()), "{rdx}"(msg.len())
//             : "{rdi}","{rax}", "{rdx}", "{rsi}"
             //             :"{rsi}"(msg.as_ptr()), "{rdx}"(msg.len())
             //
             );
    }
}
*/
fn digit_to_char_code(i: u8) -> u8 {
    if i <= 9 {
        i + 48
    }else{
        0
    }
}

fn num_digits(i: u64) -> usize {
    if i == 0 {
        1
    } else {
        let mut count = 0;
        let mut current = i;
        while current > 0 {
            current /= 10;
            count += 1;
        }
        count
    }
}

#[test]
fn num_digits_t() {
    assert_eq!(num_digits(0), 1);
    assert_eq!(num_digits(10), 2);
    assert_eq!(num_digits(99), 2);
    assert_eq!(num_digits(999), 3);
}

#[no_mangle]
pub unsafe extern fn write_u64(i: u64, base16: bool) {
    if base16 {
        write(to_hex(&i, &mut [0; 16]));
    } else {
        let count = num_digits(i);
        let mut _stack = [0; 20];
        let mut chars = &mut _stack[0..count];
        let mut place = count;
        let mut current = i;
        let mut digit;
        loop {
            digit = current % 10;
            current = (current - digit) / 10;
            place -= 1;
            chars[place] = digit_to_char_code(digit as u8);
            if current <= 0 { break; }
        }
        write(str::from_utf8(chars).unwrap());
    }
}

fn to_hex<'a>(i: &u64, output: &'a mut[u8; 16]) -> &'a str {
    let mut input = *i;
    let hex = b"0123456789abcdef";
    let mut buffer = [0; 16];
    let mut i = 0;
    let mut j = 0;
    if input == 0 {
        buffer[0] = hex[0];
        i = 1;
    } else {
        while input > 0 {
            buffer[i] = hex[(input % 16) as usize];
            input = input / 16;
            i += 1;
        }
    }

    while i > 0 {
        i -= 1;
        output[j] = buffer[i];
        j += 1;
    }
    str::from_utf8(output).unwrap().trim_matches('\0')
}

pub fn as_str<'a>(cs: *const u8) -> &'a str {
    if cs.is_null() {
        ""
    }else {
        let mut i = 0;
        unsafe {
            let mut c = *cs;
            while c != 0 {
                i += 1;
                c = *cs.offset(i);
            }
            let slice = slice::from_raw_parts(cs, i as usize);
            str::from_utf8(slice).unwrap()
        }
    }
}

pub fn str_at<'a>(cs: *const u8, offset: isize) -> &'a str {
    if cs.is_null() {
        ""
    }else {
        let mut i = 0;
        unsafe {
            let ptr = cs.offset(offset);
            let mut c = *ptr;
            while c != 0 {
                i += 1;
                c = *ptr.offset(i);
            }
            let slice = slice::from_raw_parts(ptr, i as usize);
            str::from_utf8(slice).unwrap()
        }
    }
}

pub unsafe extern fn write_chars_at(cs: *const u8) {
    write(as_str(cs));
}

extern {
    /// libc #defines errno *(__errno_location()) ... so errno isn't a symbol in the actual binary and accesses will segfault us. yay.
    fn __errno_location() -> *const i32;
}

#[inline(always)]
pub fn get_errno () -> i32 {
    unsafe { *__errno_location() }
}

/// We're required to set the rust panic hook/handler because otherwise we segfault in `static_dl_iterate_phdr` when libstd tries to unwind the stack
/// **NB**: Make sure this is called _after_ relocation, since we need to allocate the closure on the heap
pub fn set_panic () {
    ::std::panic::set_hook(Box::new(|panic| {
        dbgc!(orange_bold: true, "<dryad_panic>", r#"Thamus, are you there? When you reach Palodes, take care to proclaim that the great god Pan is dead."#);
        if let Some(location) = panic.location() {
            println!("-=|dryad====- died in {}:{}", location.file(), location.line());
        }
        let payload = panic.payload ();
        // pretty much copied from libstd's panicking default, cause it's pretty
        let msg = match payload.downcast_ref::<&'static str>() {
            Some(s) => s,
            None => match payload.downcast_ref::<String>() {
                Some(s) => &s[..],
                None => "Box<Any>",
            }
        };
        dbgc!(orange_bold: true, "<dryad_dryad>", "Died because {}", msg);
        _exit(1);
    }));
}

pub mod page {
   // from <sys/user.h>
    pub const PAGE_SHIFT: u64    = 12;
    pub const PAGE_SIZE: u64     = 1 << PAGE_SHIFT;
    const PAGE_SIZE_MINUS_1: u64 = PAGE_SIZE - 1;
    pub const PAGE_MASK: u64     = !PAGE_SIZE_MINUS_1;

    // from bionic
    /// Returns the address of the page containing address 'x'.
    #[inline(always)]
    pub fn page_start (x: u64) -> u64 { x & PAGE_MASK }

    /// Returns the offset of address 'x' in its page.
    #[inline(always)]
    pub fn page_offset (x: u64) -> u64 { x & PAGE_SIZE_MINUS_1 }

    /// Returns the address of the next page after address 'x', unless 'x' is
    /// itself at the start of a page.
    #[inline(always)]
    pub fn page_end (x: u64) -> u64 { page_start(x + PAGE_SIZE_MINUS_1) }

    #[test]
    fn t_page_start () {
        assert_eq!(page_start(0x1000), 0x1000)
    }

}

pub mod mmap {
    use std::os::raw::{c_int};
    use std::fs::File;
    use std::os::unix::io::AsRawFd;

    pub const PROT_READ: isize = 0x1; /* Page can be read.  */
    pub const PROT_WRITE: isize = 0x2; /* Page can be written.  */
    pub const PROT_EXEC: isize = 0x4; /* Page can be executed.  */
    pub const PROT_NONE: isize = 0x0; /* Page can not be accessed.  */
    pub const PROT_GROWSDOWN: isize = 0x01000000; /* Extend change to start of growsdown vma (mprotect only).  */
    pub const PROT_GROWSUP: isize = 0x02000000; /* Extend change to start of growsup vma (mprotect only).  */

    /* Sharing types (must choose one and only one of these).  */
    pub const MAP_FILE: isize = 0x0; /* no flag bits to map a file  */
    pub const MAP_SHARED: isize = 0x01; /* Share changes.  */
    pub const MAP_PRIVATE: isize = 0x02; /* Changes are private.  */
    pub const MAP_ANONYMOUS: isize = 0x20; // just guessing, this is wrapped in a ifdef with __MAP_ANONYMOUS as the value
    /* Other flags.  */
    pub const MAP_DENYWRITE: isize = 0x800;
    pub const MAP_COPY: isize = MAP_PRIVATE | MAP_DENYWRITE;
    pub const MAP_FIXED: isize = 0x10; /* Interpret addr exactly.  */

    /// map failed, from sys/mman.h, technically ((void *) - 1) ...
    pub const MAP_FAILED: u64 = !0;

    // from musl libc
    extern {
        fn mmap64(addr: *const u64, len: usize, prot: isize, flags: c_int, fildes: c_int, off: usize) -> u64;
    }

    #[inline(always)]
    pub unsafe fn mmap(addr: *const u64, len: usize, prot: isize, flags: c_int, fildes: c_int, off: usize) -> u64 {
        mmap64(addr, len, prot, flags, fildes, off)
    }

    #[inline(always)]
    fn map_fragment(fd: &File, base: u64, offset: u64, size: usize) -> Result<(u64, usize, *const u64), String> {
        use utils::page;
        let offset = base + offset;
        let page_min = page::page_start(offset);
        let end_offset = offset + size as u64;
        let end_offset = end_offset + page::page_offset(offset);

        let map_size: usize = (end_offset - page_min) as usize;

        if map_size < size {
            return Err (format!("<dryad> Error: file {:#?} has map_size = {} < size = {}, aborting", fd, map_size, size))
        }

        let map_start = unsafe { mmap(0 as *const u64,
                                            map_size,
                                            PROT_READ,
                                            MAP_PRIVATE as c_int,
                                            fd.as_raw_fd() as c_int,
                                            page_min as usize) };

        if map_start == MAP_FAILED {

            Err (format!("<dryad> Error: mmap failed for {:#?} with errno {}, aborting", fd, super::get_errno()))

        } else {

            let data = (map_start + page::page_offset(offset)) as *const u64;
            Ok ((map_start, map_size, data))
        }
    }

}
<|endoftext|>


<commit_before>#![feature(globs)]
#![feature(phase)]
#[phase(plugin, link)]
extern crate log;
extern crate getopts;
extern crate serialize;
extern crate wtftw_core;
extern crate wtftw_xlib;

use std::ops::Fn;
use std::os;
use getopts::{ optopt, getopts };
use serialize::json;
use wtftw_core::config::Config;
use wtftw_core::logger::FileLogger;
use wtftw_core::window_manager::WindowManager;
use wtftw_core::window_system::*;
use wtftw_xlib::XlibWindowSystem;

pub fn parse_window_ids(ids: &str) -> Vec<(Window, u32)> {
    json::decode(ids).unwrap()
}

fn main() {
    // Parse command line arguments
    let args : Vec<String> = os::args();

    let opts = [
        optopt("r", "resume", "list of window IDs to capture in resume", "WINDOW")
    ];

    let matches = match getopts(args.tail(), &opts) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };

    // Create a default config.generaluration
    let mut config = Config::initialize();
    log::set_logger(box FileLogger::new(&config.general.logfile, false));
    // Initialize window system. Use xlib here for now
    let window_system = XlibWindowSystem::new();
    // Create the actual window manager
    let mut window_manager = WindowManager::new(&window_system, &config.general);

    // If available, compile the config.general file at ~/.wtftw/config.general.rs
    // and call the config.generalure method
    config.compile_and_call(&mut window_manager, &window_system);
    window_manager = WindowManager::new(&window_system, &config.general);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    // Output information about displays
    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    debug!("Size of keyhandlers after config.generaluration: {}", config.internal.key_handlers.len());

    for (command, _) in config.internal.key_handlers.iter() {
        debug!("grabbing command {}", command);
        window_system.grab_keys(vec!(command.clone()));
    }

    let window_ids = if matches.opt_present("r") {
        debug!("found {}", matches.opt_str("r").unwrap());
        parse_window_ids(matches.opt_str("r").unwrap().as_slice())
    } else {
        Vec::new()
    };

    for &(window, workspace) in window_ids.iter() {
        debug!("re-inserting window {}", window);
        window_manager = window_manager.view(&window_system, workspace, &config.general)
            .manage(&window_system, window, &config.general);
    }

    // Enter the event loop and just listen for events
    while window_manager.running {
        let event = window_system.get_event();
        match event {
            WindowSystemEvent::ClientMessageEvent(_) => {
            },
            // The X11/Wayland configuration changed, so we need to readjust the
            // screen configurations.
            WindowSystemEvent::ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("screen config.generaluration changed. Rescreen");
                    window_manager = window_manager.rescreen(&window_system);
                }
            },
            // A window asked to be reconfig.generalured (i.e. resized, border change, etc.)
            WindowSystemEvent::ConfigurationRequest(window, window_changes, mask) => {
                window_system.configure_window(window, window_changes, mask);
                window_manager = window_manager.windows(&window_system, &config.general, |x| x.clone());
            },
            // A new window was created, so we need to manage
            // it unless it is already managed by us.
            WindowSystemEvent::WindowCreated(window) => {
                if window_manager.is_window_managed(window) {
                    continue;
                }

                window_manager = window_manager.manage(&window_system, window, &config.general);
                window_manager = window_manager.windows(&window_system, &config.general,
                                                        |x| config.internal.manage_hook.call((x.clone(),
                                                        &window_system, window)));
            },
            WindowSystemEvent::WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager.unmanage(&window_system, window, &config.general);
                    // TODO: remove from mapped stack and from waitingUnmap stack
                }
            },
            WindowSystemEvent::WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager = window_manager.unmanage(&window_system, window, &config.general);
                }
            },
            // The mouse pointer entered a window's region. If focus following
            // is enabled, we need to set focus to it.
            WindowSystemEvent::Enter(window) => {
                if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
                    debug!("enter event on {}", window_system.get_window_name(window));
                    window_manager = window_manager.focus(window, &window_system, &config.general);
                }
            },
            WindowSystemEvent::ButtonPressed(window, _, _, _, _) => {
                println!("HAHA!");
                if window_system.get_root() != window {
                    window_manager = window_manager.focus(window, &window_system, &config.general);
                }
            },
            // The mouse pointer left a window's reagion. If focus following is enabled,
            // we need to reset the border color
            //Leave(window) => {
            //    if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
            //        window_system.set_window_border_color(window, config.general.border_color);
            //    }
            //},
            WindowSystemEvent::KeyPressed(_, key) => {
                for (command, ref handler) in config.internal.key_handlers.iter() {
                    if command == &key {
                        let local_window_manager = window_manager.clone();
                        debug!("calling handler");
                        window_manager = handler.call((local_window_manager,
                                                       &window_system, &config.general));
                        continue;
                    }
                }
            },
            _ => ()
        };

        if let Some(ref mut loghook) = config.internal.loghook {
            loghook.call_mut((window_manager.clone(), &window_system));
        }
    }
}
<commit_msg>cleanup<commit_after>#![feature(globs)]
#![feature(phase)]
#![feature(unboxed_closures)]
#[phase(plugin, link)]
extern crate log;
extern crate getopts;
extern crate serialize;
extern crate wtftw_core;
extern crate wtftw_xlib;

use std::ops::Fn;
use std::os;
use getopts::{ optopt, getopts };
use serialize::json;
use wtftw_core::config::Config;
use wtftw_core::logger::FileLogger;
use wtftw_core::window_manager::WindowManager;
use wtftw_core::window_system::*;
use wtftw_xlib::XlibWindowSystem;

pub fn parse_window_ids(ids: &str) -> Vec<(Window, u32)> {
    json::decode(ids).unwrap()
}

fn main() {
    // Parse command line arguments
    let args : Vec<String> = os::args();

    let opts = [
        optopt("r", "resume", "list of window IDs to capture in resume", "WINDOW")
    ];

    let matches = match getopts(args.tail(), &opts) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };

    // Create a default config.generaluration
    let mut config = Config::initialize();
    log::set_logger(box FileLogger::new(&config.general.logfile, false));
    // Initialize window system. Use xlib here for now
    let window_system = XlibWindowSystem::new();
    // Create the actual window manager
    let mut window_manager = WindowManager::new(&window_system, &config.general);

    // If available, compile the config.general file at ~/.wtftw/config.general.rs
    // and call the config.generalure method
    config.compile_and_call(&mut window_manager, &window_system);
    window_manager = WindowManager::new(&window_system, &config.general);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    // Output information about displays
    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    debug!("Size of keyhandlers after config.generaluration: {}", config.internal.key_handlers.len());

    for (command, _) in config.internal.key_handlers.iter() {
        debug!("grabbing command {}", command);
        window_system.grab_keys(vec!(command.clone()));
    }

    let window_ids = if matches.opt_present("r") {
        debug!("found {}", matches.opt_str("r").unwrap());
        parse_window_ids(matches.opt_str("r").unwrap().as_slice())
    } else {
        Vec::new()
    };

    for &(window, workspace) in window_ids.iter() {
        debug!("re-inserting window {}", window);
        window_manager = window_manager.view(&window_system, workspace, &config.general)
            .manage(&window_system, window, &config.general);
    }

    // Enter the event loop and just listen for events
    while window_manager.running {
        let event = window_system.get_event();
        match event {
            WindowSystemEvent::ClientMessageEvent(_) => {
            },
            // The X11/Wayland configuration changed, so we need to readjust the
            // screen configurations.
            WindowSystemEvent::ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("screen config.generaluration changed. Rescreen");
                    window_manager = window_manager.rescreen(&window_system);
                }
            },
            // A window asked to be reconfig.generalured (i.e. resized, border change, etc.)
            WindowSystemEvent::ConfigurationRequest(window, window_changes, mask) => {
                window_system.configure_window(window, window_changes, mask);
                window_manager = window_manager.windows(&window_system, &config.general, |x| x.clone());
            },
            // A new window was created, so we need to manage
            // it unless it is already managed by us.
            WindowSystemEvent::WindowCreated(window) => {
                if window_manager.is_window_managed(window) {
                    continue;
                }

                window_manager = window_manager.manage(&window_system, window, &config.general);
                window_manager = window_manager.windows(&window_system, &config.general,
                                                        |x| config.internal.manage_hook.call((x.clone(),
                                                        &window_system, window)));
            },
            WindowSystemEvent::WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager.unmanage(&window_system, window, &config.general);
                    // TODO: remove from mapped stack and from waitingUnmap stack
                }
            },
            WindowSystemEvent::WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager = window_manager.unmanage(&window_system, window, &config.general);
                }
            },
            // The mouse pointer entered a window's region. If focus following
            // is enabled, we need to set focus to it.
            WindowSystemEvent::Enter(window) => {
                if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
                    debug!("enter event on {}", window_system.get_window_name(window));
                    window_manager = window_manager.focus(window, &window_system, &config.general);
                }
            },
            WindowSystemEvent::ButtonPressed(window, _, _, _, _) => {
                if window_system.get_root() != window {
                    window_manager = window_manager.focus(window, &window_system, &config.general);
                }
            },
            // The mouse pointer left a window's reagion. If focus following is enabled,
            // we need to reset the border color
            //Leave(window) => {
            //    if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
            //        window_system.set_window_border_color(window, config.general.border_color);
            //    }
            //},
            WindowSystemEvent::KeyPressed(_, key) => {
                for (command, ref handler) in config.internal.key_handlers.iter() {
                    if command == &key {
                        let local_window_manager = window_manager.clone();
                        debug!("calling handler");
                        window_manager = handler.call((local_window_manager,
                                                       &window_system, &config.general));
                        continue;
                    }
                }
            },
            _ => ()
        };

        if let Some(ref mut loghook) = config.internal.loghook {
            loghook.call_mut((window_manager.clone(), &window_system));
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate getopts;
extern crate rustc_serialize;
extern crate wtftw_core;
extern crate wtftw_xlib;
extern crate zombie;

use std::env;
use std::rc::Rc;
use std::ops::Deref;
use getopts::Options;
use rustc_serialize::json;
use wtftw_core::config::Config;
use wtftw_core::window_manager::WindowManager;
use wtftw_core::window_system::*;
use wtftw_xlib::XlibWindowSystem;

pub fn parse_window_ids(ids: &str) -> Vec<(Window, u32)> {
    match json::decode(ids) {
        Ok(x) => x,
        _     => Vec::new()
    }
}

fn main() {
    // Parse command line arguments
    let args : Vec<String> = env::args().collect();

    let mut options = Options::new();
    options.optopt("r", "resume", "list of window IDs to capture in resume", "WINDOW");
    let matches = match options.parse(args.into_iter().skip(1).collect::<Vec<_>>()) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };

    // Create a default config.generaluration
    let mut config = Config::initialize();
    // Initialize window system. Use xlib here for now
    debug!("initialize window system");
    let xlib = XlibWindowSystem::new();
    let window_system : Rc<WindowSystem> = Rc::new(xlib);
    // Create the actual window manager
    debug!("create window manager");
    let mut window_manager = WindowManager::new(window_system.deref(), &config.general);

    // If available, compile the config.general file at ~/.wtftw/config.general.rs
    // and call the config.generalure method
    config.compile_and_call(&mut window_manager, window_system.deref());
    window_manager = WindowManager::new(window_system.deref(), &config.general);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    // Output information about displays
    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    debug!("Size of keyhandlers after config.generaluration: {}", config.internal.key_handlers.len());

    for (command, _) in config.internal.key_handlers.iter() {
        window_system.grab_keys(vec!(command.clone()));
    }

    for (&command, _) in config.internal.mouse_handlers.iter() {
        window_system.grab_button(command);
    }

    let window_ids = if matches.opt_present("r") {
        debug!("trying to manage pre-existing windows");
        debug!("found {}", matches.opt_str("r").unwrap());
        parse_window_ids(&matches.opt_str("r").unwrap())
    } else {
        Vec::new()
    };

    for (window, workspace) in window_ids {
        debug!("re-inserting window {}", window);
        window_manager = window_manager.view(window_system.deref(), workspace, &config.general)
            .manage(window_system.deref(), window, &config.general);
    }

    window_manager = (*config.internal.startup_hook)(window_manager, window_system.clone(), &config);

    // Enter the event loop and just listen for events
    while window_manager.running {
        let event = window_system.clone().get_event();
        match event {
            WindowSystemEvent::ClientMessageEvent(_, _, _, _) => {
            },
            WindowSystemEvent::PropertyMessageEvent(process, window, atom) => {
                if process {
                    window_manager = window_system.process_message(&window_manager, &config.general, window, atom);
                }
            },
            // The X11/Wayland configuration changed, so we need to readjust the
            // screen configurations.
            WindowSystemEvent::ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("screen configuration changed. rescreen");
                    window_manager = window_manager.rescreen(window_system.deref());
                }
            },
            // A window asked to be reconfigured (i.e. resized, border change, etc.)
            WindowSystemEvent::ConfigurationRequest(window, window_changes, mask) => {
                let floating = window_manager.workspaces.floating.iter().any(|(&x, _)| x == window) ||
                    !window_manager.workspaces.contains(window);
                window_system.configure_window(window, window_changes, mask, floating);
                window_manager = window_manager.windows(window_system.deref(), &config.general, &|x| x.clone());
            },
            // A new window was created, so we need to manage
            // it unless it is already managed by us.
            WindowSystemEvent::WindowCreated(window) => {
                if window_manager.is_window_managed(window) || window_system.overrides_redirect(window) {
                    continue;
                }

                window_manager = window_manager.manage(window_system.deref(), window, &config.general)
                                               .windows(window_system.deref(), &config.general,
                                                        &|x| (config.internal.manage_hook)(x.clone(),
                                                        window_system.clone(), window));
            },
            WindowSystemEvent::WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager = if synthetic || !window_manager.is_waiting_unmap(window) {
                        window_manager.unmanage(window_system.deref(), window, &config.general)
                    } else {
                        window_manager.update_unmap(window)
                    };
                }
                zombie::collect_zombies();
            },
            WindowSystemEvent::WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager = window_manager.unmanage(window_system.deref(), window, &config.general)
                        .remove_from_unmap(window);
                }
            },
            // The mouse pointer entered a window's region. If focus following
            // is enabled, we need to set focus to it.
            WindowSystemEvent::Enter(window) => {
                if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                }
            },
            // Mouse button has been pressed. We need to check if there is a mouse handler
            // associated and if necessary, call it. Otherwise it results in a focus action.
            WindowSystemEvent::ButtonPressed(window, subwindow, button, _, _) => {
                let is_root = window_system.get_root() == window;
                let is_sub_root = window_system.get_root() == subwindow || subwindow == 0;
                let act = config.internal.mouse_handlers.get(&button);

                match act {
                    Some(ref action) => {
                        // If it's a root window, then it's an event we grabbed
                        if is_root && !is_sub_root {
                            let local_window_manager = window_manager.clone();
                            window_manager = action(local_window_manager, window_system.clone(),
                                                          &config.general, subwindow);
                        }
                    }
                    None => {
                        // Otherwise just clock to focus
                        if !is_root {
                            window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                        }
                    }
                }
            },
            WindowSystemEvent::ButtonReleased => {
                // If we were dragging, release the pointer and
                // reset the dragging closure
                if let Some(_) = window_manager.dragging {
                    window_system.ungrab_pointer();
                    window_manager.dragging = None;
                }
            }
            WindowSystemEvent::KeyPressed(_, key) => {
                if config.internal.key_handlers.contains_key(&key) {
                    let local_window_manager = window_manager.clone();
                    window_manager = config.internal.key_handlers[&key](local_window_manager,
                        window_system.clone(), &config.general);
                }
            },
            WindowSystemEvent::MouseMotion(x, y) => {
                let local_window_manager = window_manager.clone();
                if let Some(drag) = window_manager.dragging {
                    window_manager = drag(x, y, local_window_manager, window_system.deref());
                    window_system.remove_motion_events();
                }
            },
            _ => ()
        };

        if let Some(ref mut loghook) = config.internal.loghook {
            loghook(window_manager.clone(), window_system.clone());
        }

        window_system.update_server_state(&window_manager);
    }
}
<commit_msg>CHORE: Apply manage hook on resume<commit_after>#[macro_use]
extern crate log;
extern crate getopts;
extern crate rustc_serialize;
extern crate wtftw_core;
extern crate wtftw_xlib;
extern crate zombie;

use std::env;
use std::rc::Rc;
use std::ops::Deref;
use getopts::Options;
use rustc_serialize::json;
use wtftw_core::config::Config;
use wtftw_core::window_manager::WindowManager;
use wtftw_core::window_system::*;
use wtftw_xlib::XlibWindowSystem;

pub fn parse_window_ids(ids: &str) -> Vec<(Window, u32)> {
    match json::decode(ids) {
        Ok(x) => x,
        _     => Vec::new()
    }
}

fn main() {
    // Parse command line arguments
    let args : Vec<String> = env::args().collect();

    let mut options = Options::new();
    options.optopt("r", "resume", "list of window IDs to capture in resume", "WINDOW");
    let matches = match options.parse(args.into_iter().skip(1).collect::<Vec<_>>()) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };

    // Create a default config.generaluration
    let mut config = Config::initialize();
    // Initialize window system. Use xlib here for now
    debug!("initialize window system");
    let xlib = XlibWindowSystem::new();
    let window_system : Rc<WindowSystem> = Rc::new(xlib);
    // Create the actual window manager
    debug!("create window manager");
    let mut window_manager = WindowManager::new(window_system.deref(), &config.general);

    // If available, compile the config.general file at ~/.wtftw/config.general.rs
    // and call the config.generalure method
    config.compile_and_call(&mut window_manager, window_system.deref());
    window_manager = WindowManager::new(window_system.deref(), &config.general);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    // Output information about displays
    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    debug!("Size of keyhandlers after config.generaluration: {}", config.internal.key_handlers.len());

    for (command, _) in config.internal.key_handlers.iter() {
        window_system.grab_keys(vec!(command.clone()));
    }

    for (&command, _) in config.internal.mouse_handlers.iter() {
        window_system.grab_button(command);
    }

    let window_ids = if matches.opt_present("r") {
        debug!("trying to manage pre-existing windows");
        debug!("found {}", matches.opt_str("r").unwrap());
        parse_window_ids(&matches.opt_str("r").unwrap())
    } else {
        Vec::new()
    };

    for (window, workspace) in window_ids {
        debug!("re-inserting window {}", window);
        window_manager = window_manager.view(window_system.deref(), workspace, &config.general)
            .manage(window_system.deref(), window, &config.general).windows(window_system.deref(), &config.general,
                                                        &|x| (config.internal.manage_hook)(x.clone(),
                                                        window_system.clone(), window));
    }

    window_manager = (*config.internal.startup_hook)(window_manager, window_system.clone(), &config);

    // Enter the event loop and just listen for events
    while window_manager.running {
        let event = window_system.clone().get_event();
        match event {
            WindowSystemEvent::ClientMessageEvent(_, _, _, _) => {
            },
            WindowSystemEvent::PropertyMessageEvent(process, window, atom) => {
                if process {
                    window_manager = window_system.process_message(&window_manager, &config.general, window, atom);
                }
            },
            // The X11/Wayland configuration changed, so we need to readjust the
            // screen configurations.
            WindowSystemEvent::ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("screen configuration changed. rescreen");
                    window_manager = window_manager.rescreen(window_system.deref());
                }
            },
            // A window asked to be reconfigured (i.e. resized, border change, etc.)
            WindowSystemEvent::ConfigurationRequest(window, window_changes, mask) => {
                let floating = window_manager.workspaces.floating.iter().any(|(&x, _)| x == window) ||
                    !window_manager.workspaces.contains(window);
                window_system.configure_window(window, window_changes, mask, floating);
                window_manager = window_manager.windows(window_system.deref(), &config.general, &|x| x.clone());
            },
            // A new window was created, so we need to manage
            // it unless it is already managed by us.
            WindowSystemEvent::WindowCreated(window) => {
                if window_manager.is_window_managed(window) || window_system.overrides_redirect(window) {
                    continue;
                }

                window_manager = window_manager.manage(window_system.deref(), window, &config.general)
                                               .windows(window_system.deref(), &config.general,
                                                        &|x| (config.internal.manage_hook)(x.clone(),
                                                        window_system.clone(), window));
            },
            WindowSystemEvent::WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager = if synthetic || !window_manager.is_waiting_unmap(window) {
                        window_manager.unmanage(window_system.deref(), window, &config.general)
                    } else {
                        window_manager.update_unmap(window)
                    };
                }
                zombie::collect_zombies();
            },
            WindowSystemEvent::WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager = window_manager.unmanage(window_system.deref(), window, &config.general)
                        .remove_from_unmap(window);
                }
            },
            // The mouse pointer entered a window's region. If focus following
            // is enabled, we need to set focus to it.
            WindowSystemEvent::Enter(window) => {
                if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                }
            },
            // Mouse button has been pressed. We need to check if there is a mouse handler
            // associated and if necessary, call it. Otherwise it results in a focus action.
            WindowSystemEvent::ButtonPressed(window, subwindow, button, _, _) => {
                let is_root = window_system.get_root() == window;
                let is_sub_root = window_system.get_root() == subwindow || subwindow == 0;
                let act = config.internal.mouse_handlers.get(&button);

                match act {
                    Some(ref action) => {
                        // If it's a root window, then it's an event we grabbed
                        if is_root && !is_sub_root {
                            let local_window_manager = window_manager.clone();
                            window_manager = action(local_window_manager, window_system.clone(),
                                                          &config.general, subwindow);
                        }
                    }
                    None => {
                        // Otherwise just clock to focus
                        if !is_root {
                            window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                        }
                    }
                }
            },
            WindowSystemEvent::ButtonReleased => {
                // If we were dragging, release the pointer and
                // reset the dragging closure
                if let Some(_) = window_manager.dragging {
                    window_system.ungrab_pointer();
                    window_manager.dragging = None;
                }
            }
            WindowSystemEvent::KeyPressed(_, key) => {
                if config.internal.key_handlers.contains_key(&key) {
                    let local_window_manager = window_manager.clone();
                    window_manager = config.internal.key_handlers[&key](local_window_manager,
                        window_system.clone(), &config.general);
                }
            },
            WindowSystemEvent::MouseMotion(x, y) => {
                let local_window_manager = window_manager.clone();
                if let Some(drag) = window_manager.dragging {
                    window_manager = drag(x, y, local_window_manager, window_system.deref());
                    window_system.remove_motion_events();
                }
            },
            _ => ()
        };

        if let Some(ref mut loghook) = config.internal.loghook {
            loghook(window_manager.clone(), window_system.clone());
        }

        window_system.update_server_state(&window_manager);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::convert;
use std::slice;
use std::vec;

pub struct Collection<T> {
    items: Vec<T>,
}

impl<T> fmt::Debug for Collection<T> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_list().entries(self.items.iter()).finish()
    }
}

impl<T> Collection<T> {
    pub fn new() -> Collection<T> {
        Collection {
            items: Vec::new()
        }
    }

    pub fn push(&mut self, item: T) {
        self.items.push(item)
    }
}

impl<T> convert::AsRef<[T]> for Collection<T> {
    fn as_ref(&self) -> &[T] {
        &self.items
    }
}

impl<'a, T> IntoIterator for &'a Collection<T> {
    type IntoIter = slice::Iter<'a, T>;
    type Item = &'a T;

    fn into_iter(self) -> slice::Iter<'a, T> {
        self.items.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Collection<T> {
    type IntoIter = slice::IterMut<'a, T>;
    type Item = &'a mut T;

    fn into_iter(self) -> slice::IterMut<'a, T> {
        self.items.iter_mut()
    }
}

impl<T> IntoIterator for Collection<T> {
    type IntoIter = vec::IntoIter<T>;
    type Item = T;

    fn into_iter(self) -> vec::IntoIter<T> {
        self.items.into_iter()
    }
}

impl<T> Into<Vec<T>> for Collection<T> {
    fn into(self) -> Vec<T> {
        self.items
    }
}
<commit_msg>Mutable iterator fo collection should not be available.<commit_after>use std::fmt;
use std::convert;
use std::slice;
use std::vec;

pub struct Collection<T> {
    items: Vec<T>,
}

impl<T> fmt::Debug for Collection<T> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_list().entries(self.items.iter()).finish()
    }
}

impl<T> Collection<T> {
    pub fn new() -> Collection<T> {
        Collection {
            items: Vec::new()
        }
    }

    pub fn push(&mut self, item: T) {
        self.items.push(item)
    }

    pub fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
        self.into_iter()
    }
}

impl<T> convert::AsRef<[T]> for Collection<T> {
    fn as_ref(&self) -> &[T] {
        &self.items
    }
}

impl<'a, T> IntoIterator for &'a Collection<T> {
    type IntoIter = slice::Iter<'a, T>;
    type Item = &'a T;

    fn into_iter(self) -> slice::Iter<'a, T> {
        self.items.iter()
    }
}

impl<T> IntoIterator for Collection<T> {
    type IntoIter = vec::IntoIter<T>;
    type Item = T;

    fn into_iter(self) -> vec::IntoIter<T> {
        self.items.into_iter()
    }
}

impl<T> Into<Vec<T>> for Collection<T> {
    fn into(self) -> Vec<T> {
        self.items
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::vec::Vec;
use js_types::js_type::{JsType,JsT};

pub struct JsObjStruct {
    pub proto: JsProto,
    pub dict: HashMap<JsT, JsT>,
}

impl JsObjStruct {
    pub fn new(proto: JsProto, kv_pairs: Vec<(JsT, JsT)>) -> JsObjStruct {
        let mut obj_map = HashMap::new();
        kv_pairs.into_iter().map(|(k,v)| obj_map.insert(k, v));
        JsObjStruct {
            proto: None,
            dict: obj_map,
        }
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

#[cfg(test)]
mod test {
    use js_types::js_obj::JsObjStruct;
    use js_types::js_type::{JsType,JsT};
    use js_types::js_str::JsStrStruct;

    #[test]
    fn test_js_obj() {
        let mut vec: Vec<(JsT, JsT)> = Vec::new();
        for i in 0..10 {
            let k = JsT::new(JsType::JsNum(i as f64));
            let v = JsT::new(JsType::JsStr(JsStrStruct::new(
                                            &format!("test{}", i))));
            vec.push((k,v));
        }
        let o = JsObjStruct::new(None, vec);
        for (k, v) in o.dict {
            match k.t {
                JsType::JsNum(ki) => { assert!(ki >= 0.0f64);
                                       assert!(ki < 10.0f64) },
                _ => panic!("Expected a JsNum!"),
            };
            match v.t {
                JsType::JsStr(vs) => assert!(vs.text.starts_with("test")),
                _ => panic!("Expected a JsStr!"),
            };
        }
    }

}
<commit_msg>Add name field to JSObj<commit_after>use std::collections::hash_map::HashMap;
use std::string::String;
use std::vec::Vec;
use js_types::js_type::{JsType,JsT};

pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsT, JsT>,
}

impl JsObjStruct {
    pub fn new(proto: JsProto, name: &str, kv_pairs: Vec<(JsT, JsT)>) -> JsObjStruct {
        let mut dict = HashMap::new();
        kv_pairs.into_iter().map(|(k,v)| dict.insert(k, v));
        JsObjStruct {
            proto: None,
            name: String::from(name),
            dict: dict,
        }
    }

    pub fn add_key(&mut self, k: JsT, v: JsT) {
        self.dict.insert(k, v);
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

// TODO nice JS object creation macro
//macro_rules! js_obj {
//    ( $kt:ty : $ke:expr => $vt:ty : $ve:expr ),* {
//        {
//
//        }
//    };
//}

#[cfg(test)]
mod tests {
    use super::*;
    use js_types::js_type::{JsType,JsT};
    use js_types::js_str::{JsStrStruct};

    #[test]
    fn test_js_obj() {
        let mut vec: Vec<(JsT, JsT)> = Vec::new();
        for i in 0..10 {
            let k = JsT::new(JsType::JsNum(i as f64));
            let v = JsT::new(JsType::JsStr(JsStrStruct::new(
                                            &format!("test{}", i))));
            vec.push((k,v));
        }
        let o = JsObjStruct::new(None, "test", vec);
        for (k, v) in o.dict {
            match k.t {
                JsType::JsNum(ki) => { assert!(ki >= 0.0f64);
                                       assert!(ki < 10.0f64) },
                _ => panic!("Expected a JsNum!"),
            };
            match v.t {
                JsType::JsStr(vs) => assert!(vs.text.starts_with("test")),
                _ => panic!("Expected a JsStr!"),
            };
        }
        assert_eq!(&o.name, "test");
    }

}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Some various other I/O types

// FIXME(#3660): should move to libextra

use prelude::*;
use super::*;

/// A Writer decorator that compresses using the 'deflate' scheme
pub struct DeflateWriter<W> {
    priv inner_writer: W
}

impl<W: Writer> DeflateWriter<W> {
    pub fn new(inner_writer: W) -> DeflateWriter<W> {
        DeflateWriter {
            inner_writer: inner_writer
        }
    }
}

impl<W: Writer> Writer for DeflateWriter<W> {
    fn write(&mut self, _buf: &[u8]) { fail!() }

    fn flush(&mut self) { fail!() }
}

/// A Reader decorator that decompresses using the 'deflate' scheme
pub struct InflateReader<R> {
    priv inner_reader: R
}

impl<R: Reader> InflateReader<R> {
    pub fn new(inner_reader: R) -> InflateReader<R> {
        InflateReader {
            inner_reader: inner_reader
        }
    }
}

impl<R: Reader> Reader for InflateReader<R> {
    fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
}
<commit_msg>std: Delete unused file<commit_after><|endoftext|>


<commit_before>use std::iter::FromIterator;
use std::collections::HashSet;

use regex::Regex;

use {TextRange, NodeType, File};
use node::imp::{FileBuilder, NodeId};

pub struct Rule {
    pub ty: NodeType,
    pub re: &'static str,
    pub f: Option<fn(&str) -> Option<usize>>,
}

#[derive(Debug, Clone, Copy)]
pub struct Token {
    pub ty: NodeType,
    pub range: TextRange,
}

pub struct TreeBuilder {
    text: String,
    skip: HashSet<NodeType>,
    tokens: Vec<Token>,
    pending: Vec<Frame>,
    current_token: usize,
}

#[derive(Debug)]
pub struct PreNode {
    pub ty: NodeType,
    pub range: TextRange,
    pub children: Vec<PreNode>,
}

#[derive(Debug)]
struct Frame {
    ty: NodeType,
    children: Vec<PreNode>,
    start_token: usize,
}

impl TreeBuilder {
    pub fn start(&mut self, ty: NodeType) {
        self.pending.push(Frame { ty: ty, children: vec![], start_token: self.current_token })
    }

    pub fn finish(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let mut top = self.pending.pop().unwrap();

        while let Some(ty) = top.children.last().map(|n| n.ty) {
            if !self.is_skip(ty) {
                break
            }
            top.children.pop();
            self.current_token -= 1;
        }
        let node = self.to_prenode(top);

        if let Some(t) = node.children.first() {
            assert!(!self.is_skip(t.ty));
        }
        if let Some(t) = node.children.last() {
            assert!(!self.is_skip(t.ty));
        }

        self.top().children.push(node);
        self.do_skip();
    }

    fn to_prenode(&self, frame: Frame) -> PreNode {
        let range = if frame.children.is_empty() {
            let start = self.tokens.get(frame.start_token).map(|t| t.range.start()).unwrap_or(0);
            TextRange::from_to(start, start)
        } else {
            let first = frame.children.first().unwrap();
            let last = frame.children.last().unwrap();
            TextRange::from_to(first.range.start(), last.range.end())
        };

        PreNode { ty: frame.ty, range: range, children: frame.children }
    }

    pub fn rollback(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let top = self.pending.pop().unwrap();
        self.current_token = top.start_token;
    }

    pub fn try_eat(&mut self, ty: NodeType) -> bool {
        let t = match self.current() {
            None => return false,
            Some(t) => t
        };

        if t.ty == ty {
            self.bump();
            self.do_skip();
            true
        } else {
            false
        }
    }

    pub fn skip_until(&mut self, tys: &[NodeType]) {
        self.do_skip();
        self.start(::ERROR);
        let mut skipped = false;
        while let Some(t) = self.current() {
            if tys.contains(&t.ty) {
                break;
            }
            if !self.is_skip(t.ty) {
                skipped = true;
            }
            self.bump();
        }
        if skipped {
            self.finish(::ERROR);
        } else {
            self.rollback(::ERROR);
        }
    }

    pub fn parse_many(&mut self, f: &Fn(&mut TreeBuilder) -> bool) {
        loop {
            if !f(self) {
                break
            }
        }
    }

    pub fn next_is(&mut self, ty: NodeType) -> bool {
        self.do_skip();
        if let Some(t) = self.current() {
            t.ty == ty
        } else {
            false
        }
    }

    pub fn error(&mut self) {}

    fn new(text: String, file_type: NodeType, tokens: Vec<Token>) -> TreeBuilder {
        let skip = &[::WHITESPACE];
        let mut result = TreeBuilder {
            text: text,
            skip: skip.iter().cloned().collect(),
            tokens: tokens,
            pending: vec![Frame { ty: file_type, children: vec![], start_token: 0 }],
            current_token: 0,
        };
        result.do_skip();
        result
    }

    fn top(&mut self) -> &mut Frame {
        self.pending.last_mut().unwrap()
    }

    fn bump(&mut self) {
        let t = self.current().unwrap();
        self.current_token += 1;
        self.top().children.push(PreNode {
            ty: t.ty,
            range: t.range,
            children: vec![],
        })
    }

    fn do_skip(&mut self) {
        while let Some(t) = self.current() {
            if !self.is_skip(t.ty) {
                break;
            }
            self.bump();
        }
    }

    fn current(&self) -> Option<Token> {
        self.tokens.get(self.current_token).cloned()
    }

    fn into_file(mut self) -> File {
        while self.current().is_some() {
            self.bump();
        }
        let top = self.pending.pop().unwrap();
        assert!(self.pending.is_empty());
        let root = self.to_prenode(top);
        let mut builder = ::node::imp::FileBuilder::new();
        go(&mut builder, None, root);
        return builder.build(self.text);

        fn go(builder: &mut FileBuilder, parent: Option<NodeId>, node: PreNode) {
            let id = builder.node(parent, node.ty, node.range);
            for child in node.children {
                go(builder, Some(id), child)
            }
        }
    }

    fn is_skip(&self, ty: NodeType) -> bool {
        self.skip.contains(&ty)
    }
}

impl ::std::fmt::Debug for TreeBuilder {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        f.write_str("TreeBuilder {")?;
        let pending = self.pending.iter().map(|f| f.ty.name()).collect::<String>();
        f.write_str(&format!("  pending = {}", pending))?;
        f.write_str("}")?;
        Ok(())
    }
}

pub fn parse(
    text: String,
    file_type: NodeType,
    tokenizer: &[Rule],
    parser: &Fn(&mut TreeBuilder)
) -> File {
    let tokens = tokenize(&text, tokenizer);
    let mut builder = TreeBuilder::new(text, file_type, tokens);
    parser(&mut builder);
    builder.into_file()
}

fn tokenize(text: &str, tokenizer: &[Rule]) -> Vec<Token> {
    let mut result = vec![];

    let rules = Vec::from_iter(
        tokenizer.iter().map(|r| (r.ty, Regex::new(&format!("^{}", r.re)).unwrap(), r.f))
    );

    let mut offset = 0;
    let mut rest = text;

    'l: while rest.len() > 0 {
        for &(ty, ref re, f) in rules.iter() {
            if let Some(m) = re.find(rest) {
                assert!(m.start() == 0);
                assert!(m.end() > 0);
                let end = if let Some(f) = f {
                    if let Some(n) = f(rest) {
                        n
                    } else {
                        continue
                    }
                } else {
                    m.end()
                };
                let range = TextRange::from_to(offset as u32, (offset + end) as u32);
                result.push(Token { ty: ty, range: range });
                offset += end;
                rest = &rest[end..];
                continue 'l;
            }
        }
        let bad_char_len = rest.chars().next().unwrap().len_utf8();
        result.push(Token {
            ty: ::ERROR,
            range: TextRange::from_to(offset as u32, (offset + bad_char_len) as u32)
        });
        offset += bad_char_len;
        rest = &rest[bad_char_len..];
    }

    result
}
<commit_msg>Implement fist longest lexer rule<commit_after>use std::iter::FromIterator;
use std::collections::HashSet;

use regex::Regex;

use {TextRange, NodeType, File};
use node::imp::{FileBuilder, NodeId};

pub struct Rule {
    pub ty: NodeType,
    pub re: &'static str,
    pub f: Option<fn(&str) -> Option<usize>>,
}

#[derive(Debug, Clone, Copy)]
pub struct Token {
    pub ty: NodeType,
    pub range: TextRange,
}

pub struct TreeBuilder {
    text: String,
    skip: HashSet<NodeType>,
    tokens: Vec<Token>,
    pending: Vec<Frame>,
    current_token: usize,
}

#[derive(Debug)]
pub struct PreNode {
    pub ty: NodeType,
    pub range: TextRange,
    pub children: Vec<PreNode>,
}

#[derive(Debug)]
struct Frame {
    ty: NodeType,
    children: Vec<PreNode>,
    start_token: usize,
}

impl TreeBuilder {
    pub fn start(&mut self, ty: NodeType) {
        self.pending.push(Frame { ty: ty, children: vec![], start_token: self.current_token })
    }

    pub fn finish(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let mut top = self.pending.pop().unwrap();

        while let Some(ty) = top.children.last().map(|n| n.ty) {
            if !self.is_skip(ty) {
                break
            }
            top.children.pop();
            self.current_token -= 1;
        }
        let node = self.to_prenode(top);

        if let Some(t) = node.children.first() {
            assert!(!self.is_skip(t.ty));
        }
        if let Some(t) = node.children.last() {
            assert!(!self.is_skip(t.ty));
        }

        self.top().children.push(node);
        self.do_skip();
    }

    fn to_prenode(&self, frame: Frame) -> PreNode {
        let range = if frame.children.is_empty() {
            let start = self.tokens.get(frame.start_token).map(|t| t.range.start()).unwrap_or(0);
            TextRange::from_to(start, start)
        } else {
            let first = frame.children.first().unwrap();
            let last = frame.children.last().unwrap();
            TextRange::from_to(first.range.start(), last.range.end())
        };

        PreNode { ty: frame.ty, range: range, children: frame.children }
    }

    pub fn rollback(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let top = self.pending.pop().unwrap();
        self.current_token = top.start_token;
    }

    pub fn try_eat(&mut self, ty: NodeType) -> bool {
        let t = match self.current() {
            None => return false,
            Some(t) => t
        };

        if t.ty == ty {
            self.bump();
            self.do_skip();
            true
        } else {
            false
        }
    }

    pub fn skip_until(&mut self, tys: &[NodeType]) {
        self.do_skip();
        self.start(::ERROR);
        let mut skipped = false;
        while let Some(t) = self.current() {
            if tys.contains(&t.ty) {
                break;
            }
            if !self.is_skip(t.ty) {
                skipped = true;
            }
            self.bump();
        }
        if skipped {
            self.finish(::ERROR);
        } else {
            self.rollback(::ERROR);
        }
    }

    pub fn parse_many(&mut self, f: &Fn(&mut TreeBuilder) -> bool) {
        loop {
            if !f(self) {
                break
            }
        }
    }

    pub fn next_is(&mut self, ty: NodeType) -> bool {
        self.do_skip();
        if let Some(t) = self.current() {
            t.ty == ty
        } else {
            false
        }
    }

    pub fn error(&mut self) {}

    fn new(text: String, file_type: NodeType, tokens: Vec<Token>) -> TreeBuilder {
        let skip = &[::WHITESPACE];
        let mut result = TreeBuilder {
            text: text,
            skip: skip.iter().cloned().collect(),
            tokens: tokens,
            pending: vec![Frame { ty: file_type, children: vec![], start_token: 0 }],
            current_token: 0,
        };
        result.do_skip();
        result
    }

    fn top(&mut self) -> &mut Frame {
        self.pending.last_mut().unwrap()
    }

    fn bump(&mut self) {
        let t = self.current().unwrap();
        self.current_token += 1;
        self.top().children.push(PreNode {
            ty: t.ty,
            range: t.range,
            children: vec![],
        })
    }

    fn do_skip(&mut self) {
        while let Some(t) = self.current() {
            if !self.is_skip(t.ty) {
                break;
            }
            self.bump();
        }
    }

    fn current(&self) -> Option<Token> {
        self.tokens.get(self.current_token).cloned()
    }

    fn into_file(mut self) -> File {
        while self.current().is_some() {
            self.bump();
        }
        let top = self.pending.pop().unwrap();
        assert!(self.pending.is_empty());
        let root = self.to_prenode(top);
        let mut builder = ::node::imp::FileBuilder::new();
        go(&mut builder, None, root);
        return builder.build(self.text);

        fn go(builder: &mut FileBuilder, parent: Option<NodeId>, node: PreNode) {
            let id = builder.node(parent, node.ty, node.range);
            for child in node.children {
                go(builder, Some(id), child)
            }
        }
    }

    fn is_skip(&self, ty: NodeType) -> bool {
        self.skip.contains(&ty)
    }
}

impl ::std::fmt::Debug for TreeBuilder {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        f.write_str("TreeBuilder {")?;
        let pending = self.pending.iter().map(|f| f.ty.name()).collect::<String>();
        f.write_str(&format!("  pending = {}", pending))?;
        f.write_str("}")?;
        Ok(())
    }
}

pub fn parse(
    text: String,
    file_type: NodeType,
    tokenizer: &[Rule],
    parser: &Fn(&mut TreeBuilder)
) -> File {
    let tokens = tokenize(&text, tokenizer);
    let mut builder = TreeBuilder::new(text, file_type, tokens);
    parser(&mut builder);
    builder.into_file()
}

fn tokenize(text: &str, tokenizer: &[Rule]) -> Vec<Token> {
    let mut result = vec![];

    let rules = Vec::from_iter(
        tokenizer.iter().map(|r| (r.ty, Regex::new(&format!("^{}", r.re)).unwrap(), r.f))
    );

    let mut offset = 0;
    let mut rest = text;

    'l: while rest.len() > 0 {
        let matches: Vec<_> = rules.iter()
            .filter_map(|&(ty, ref re, f)| {
                re.find(rest).map(|m| (m.end(), (ty, f)))
            })
            .collect();

        let bad_char = (::ERROR, rest.chars().next().unwrap().len_utf8());
        let (ty, end) = if matches.is_empty() {
            bad_char
        } else {
            let longest_match = matches.iter().map(|&(l, _)| l).max().unwrap();
            let &(l, (ty, f)) = matches.iter().find(|&&(l, _)| l == longest_match).unwrap();
            assert!(l > 0);
            if let Some(f) = f {
                if let Some(n) = f(rest) {
                    (ty, n)
                } else {
                    bad_char
                }
            } else {
                (ty, l)
            }
        };

        let range = TextRange::from_to(offset as u32, (offset + end) as u32);
        result.push(Token { ty: ty, range: range });
        offset += end;
        rest = &rest[end..];
    }

    result
}

#[test]
fn tokenize_longest_first_wins() {
    let rules = &[
        Rule { ty: ::WHITESPACE, re: r"\s+", f: None },
        Rule { ty: NodeType(10), re: "foo", f: None },
        Rule { ty: NodeType(11), re: r"\w+", f: None },
        Rule { ty: NodeType(12), re: "foobar", f: None },
    ];

    let tokens: Vec<_> = tokenize("foo foob foobar", rules)
        .into_iter()
        .map(|t| t.ty.0)
        .collect();
    assert_eq!(tokens, vec![10, 1, 11, 1, 11]);
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CString;
use std::mem;
use std::os::unix::io;
use std::ptr;

use callbacks::{
    socket_callback,
    query_a_callback,
    query_aaaa_callback,
};
use types::{
    Flag,
    AresError,
    AResult,
    AAAAResult,
    DnsClass,
    QueryType,
};
use utils::ares_error;

/// Used to configure the behaviour of the name resolver.
pub struct Options {
    ares_options: c_ares_sys::Struct_ares_options,
    optmask: libc::c_int,
}

impl Options {
    /// Returns a fresh `Options`, on which no values are set.
    pub fn new() -> Options {
        Options {
            ares_options: c_ares_sys::Struct_ares_options::default(),
            optmask: 0,
        }
    }

    /// Set flags controlling the behaviour of the resolver.
    pub fn set_flags(&mut self, flags: &[Flag]) -> &mut Self {
        let c_flags: libc::c_int = flags
            .iter()
            .fold(0, |acc, &flag| acc | (flag as libc::c_int));
        self.ares_options.flags = c_flags;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_FLAGS;
        self
    }

    /// Set the number of milliseconds each name server is given to respond to
    /// a query on the first try.  (After the first try, the timeout algorithm
    /// becomes more complicated, but scales linearly with the value of
    /// timeout.) The default is five seconds.
    pub fn set_timeout(&mut self, ms: u32) -> &mut Self {
        self.ares_options.timeout = ms as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TIMEOUTMS;
        self
    }

    /// Set the number of tries the resolver will try contacting each name
    /// server before giving up. The default is four tries.
    pub fn set_tries(&mut self, tries: u32) -> &mut Self {
        self.ares_options.tries = tries as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TRIES;
        self
    }
}

/// A channel for name service lookups.
pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

impl Channel {
    /// Create a new channel for name service lookups, providing a callback
    /// for socket state changes.
    ///
    /// `callback(socket, read, write)` will be called when a socket changes
    /// state:
    ///
    /// -  `read` is set to true if the socket should listen for read events
    /// -  `write` is set to true if the socket should listen to write events.
    pub fn new<F>(
        callback: F,
        mut options: Options) -> Result<Channel, AresError>
        where F: FnMut(io::RawFd, bool, bool) + 'static {
        options.optmask = options.optmask | c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        options.ares_options.sock_state_cb = Some(socket_callback::<F>);
        options.ares_options.sock_state_cb_data = unsafe {
            mem::transmute(Box::new(callback))
        };
        Self::create_channel(options)
    }

    fn create_channel(mut options: Options) -> Result<Channel, AresError> {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        if lib_rc != c_ares_sys::ARES_SUCCESS {
            return Err(ares_error(lib_rc))
        }

        let mut ares_channel = ptr::null_mut();
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(
                &mut ares_channel,
                &mut options.ares_options,
                options.optmask)
        };
        if channel_rc != c_ares_sys::ARES_SUCCESS {
            unsafe { c_ares_sys::ares_library_cleanup(); }
            return Err(ares_error(channel_rc))
        }

        let channel = Channel {
            ares_channel: ares_channel,
        };
        Ok(channel)
    }

    /// Handle input, output, and timeout events associated with the specified
    /// file descriptors (sockets).
    ///
    /// Providing a value for `read_fd` indicates that the identified socket
    /// is readable; likewise providing a value for `write_fd` indicates that
    /// the identified socket is writable.  Use `INVALID_FD` for "no-action".
    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(
                self.ares_channel,
                read_fd as c_ares_sys::ares_socket_t,
                write_fd as c_ares_sys::ares_socket_t);
        }
    }

    /// Look up the A record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    /// Look up the AAAA record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

unsafe impl Send for Channel { }
<commit_msg>More config options<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CString;
use std::mem;
use std::os::unix::io;
use std::ptr;

use callbacks::{
    socket_callback,
    query_a_callback,
    query_aaaa_callback,
};
use types::{
    Flag,
    AresError,
    AResult,
    AAAAResult,
    DnsClass,
    QueryType,
};
use utils::ares_error;

/// Used to configure the behaviour of the name resolver.
pub struct Options {
    ares_options: c_ares_sys::Struct_ares_options,
    optmask: libc::c_int,
}

impl Options {
    /// Returns a fresh `Options`, on which no values are set.
    pub fn new() -> Options {
        Options {
            ares_options: c_ares_sys::Struct_ares_options::default(),
            optmask: 0,
        }
    }

    /// Set flags controlling the behaviour of the resolver.
    pub fn set_flags(&mut self, flags: &[Flag]) -> &mut Self {
        let c_flags: libc::c_int = flags
            .iter()
            .fold(0, |acc, &flag| acc | (flag as libc::c_int));
        self.ares_options.flags = c_flags;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_FLAGS;
        self
    }

    /// Set the number of milliseconds each name server is given to respond to
    /// a query on the first try.  (After the first try, the timeout algorithm
    /// becomes more complicated, but scales linearly with the value of
    /// timeout.) The default is five seconds.
    pub fn set_timeout(&mut self, ms: u32) -> &mut Self {
        self.ares_options.timeout = ms as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TIMEOUTMS;
        self
    }

    /// Set the number of tries the resolver will try contacting each name
    /// server before giving up. The default is four tries.
    pub fn set_tries(&mut self, tries: u32) -> &mut Self {
        self.ares_options.tries = tries as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TRIES;
        self
    }

    /// Set the number of dots which must be present in a domain name for it to
    /// be queried for "as is" prior to querying for it with the default domain
    /// extensions appended. The default value is 1 unless set otherwise by
    /// resolv.conf or the RES_OPTIONS environment variable.
    pub fn set_ndots(&mut self, ndots: u32) -> &mut Self {
        self.ares_options.ndots = ndots as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_NDOTS;
        self
    }

    /// Set the UDP port to use for queries. The default value is 53, the
    /// standard name service port.
    pub fn set_udp_port(&mut self, udp_port: u16) -> &mut Self {
        self.ares_options.udp_port = udp_port as libc::c_ushort;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_UDP_PORT;
        self
    }

    /// Set the TCP port to use for queries. The default value is 53, the
    /// standard name service port.
    pub fn set_tcp_port(&mut self, tcp_port: u16) -> &mut Self {
        self.ares_options.tcp_port = tcp_port as libc::c_ushort;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TCP_PORT;
        self
    }
}

/// A channel for name service lookups.
pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

impl Channel {
    /// Create a new channel for name service lookups, providing a callback
    /// for socket state changes.
    ///
    /// `callback(socket, read, write)` will be called when a socket changes
    /// state:
    ///
    /// -  `read` is set to true if the socket should listen for read events
    /// -  `write` is set to true if the socket should listen to write events.
    pub fn new<F>(
        callback: F,
        mut options: Options) -> Result<Channel, AresError>
        where F: FnMut(io::RawFd, bool, bool) + 'static {
        options.optmask = options.optmask | c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        options.ares_options.sock_state_cb = Some(socket_callback::<F>);
        options.ares_options.sock_state_cb_data = unsafe {
            mem::transmute(Box::new(callback))
        };
        Self::create_channel(options)
    }

    fn create_channel(mut options: Options) -> Result<Channel, AresError> {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        if lib_rc != c_ares_sys::ARES_SUCCESS {
            return Err(ares_error(lib_rc))
        }

        let mut ares_channel = ptr::null_mut();
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(
                &mut ares_channel,
                &mut options.ares_options,
                options.optmask)
        };
        if channel_rc != c_ares_sys::ARES_SUCCESS {
            unsafe { c_ares_sys::ares_library_cleanup(); }
            return Err(ares_error(channel_rc))
        }

        let channel = Channel {
            ares_channel: ares_channel,
        };
        Ok(channel)
    }

    /// Handle input, output, and timeout events associated with the specified
    /// file descriptors (sockets).
    ///
    /// Providing a value for `read_fd` indicates that the identified socket
    /// is readable; likewise providing a value for `write_fd` indicates that
    /// the identified socket is writable.  Use `INVALID_FD` for "no-action".
    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(
                self.ares_channel,
                read_fd as c_ares_sys::ares_socket_t,
                write_fd as c_ares_sys::ares_socket_t);
        }
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is host[:port].  IPv6 addresses with ports require square
    /// brackets eg [2001:4860:4860::8888]:53
    pub fn set_servers(&mut self, servers: &[&str]) -> Result<(), AresError> {
        let servers_csv = servers.connect(",");
        let c_servers = CString::new(servers_csv).unwrap();
        let ares_rc = unsafe {
            c_ares_sys::ares_set_servers_csv(
                self.ares_channel,
                c_servers.as_ptr())
        };
        if ares_rc != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(ares_rc))
        } else {
            Ok(())
        }
    }

    /// Look up the A record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    /// Look up the AAAA record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

unsafe impl Send for Channel { }
<|endoftext|>