<commit_before>extern crate libc;
extern crate x11;

use x11::xlib;
use std::ptr;
use super::layout::{ self, Rectangle };
use super::super::libx;

pub enum Mode {
    Normal,
    Fullscreen,
    Resize(usize, i32, i32),
}

pub enum Type {
    App,
    Container,
    Workspace,
}

pub struct Container {
    pub id: Option<xlib::Window>,
    pub visible: bool,
    pub titlebar_height: u32,
    parent: *mut Container,
    pub clients: Vec<Container>,
    pub mode: Mode,
    pub category: Type,
    pub titlebar: Option<Rectangle>,
    pub portion: f32,
    pub context: libx::Context,

    pub layout: layout::Type,
    pub direction: layout::Direction,
}

impl PartialEq for Container {
    fn eq(&self, other: &Self) -> bool {
        self.raw_id() == other.raw_id()
    }
}

impl Container {
    pub fn new(context: libx::Context) -> Container{
        let pid = context.root;
        let attrs = libx::get_window_attributes(context, pid);

        let id = libx::create_window(context, pid,
                                     attrs.x, attrs.y,
                                     attrs.width as u32,
                                     attrs.height as u32);
        let mask = xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask | xlib::ButtonPressMask | xlib::ButtonReleaseMask | xlib::Button1MotionMask | xlib::Button3MotionMask | xlib::ExposureMask;
        libx::select_input(context, id, mask);
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            category: Type::Container,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,
            portion: 1.0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn from_id(context: libx::Context, id: xlib::Window) -> Container {
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            category: Type::App,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,
            portion: 1.0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn print_tree(&self, indent: i32) {
        for i in 0..indent {
            print!(" ");
        }
        let attrs = libx::get_window_attributes(self.context, self.raw_id());
        let pid = match self.get_parent() {
            Some(p) => { p.raw_id() }
            None => { 0}
        };
        println!("C {} pid:{} x:{} y:{} w:{} h:{}", self.raw_id(), pid, attrs.x, attrs.y, attrs.width, attrs.height);
        for client in self.clients.iter() {
            client.print_tree(indent+4);
        }
    }

    pub fn raw_id(&self) -> xlib::Window {
        self.id.unwrap()
    }

    // pub fn is_top(&self) -> bool {
    //     let top = self.get_top();
    //     match top {
    //         Some(w) => {
    //             w.id == self.id
    //         }
    //         Noen => false
    //     }
    // }

    pub fn is_empty(&self) -> bool{
        self.clients.is_empty()
    }

    pub fn size(&self) -> usize {
        self.clients.len()
    }

    pub fn be_parent(&mut self, client: &mut Container) {
        let need_reprent = match client.get_parent() {
            Some(p) => {
                if p.raw_id() == self.raw_id() { false } else { true }
            }
            None => {
                true
            }
        };
        if need_reprent {
            libx::reparent(self.context, client.raw_id(), self.raw_id(), 0, 0);
            client.parent = self;
        }
    }

    pub fn add(&mut self, mut client: Container) {
        self.be_parent(&mut client);
        let portion = 1.0 / (self.size() as f32 + 1.0);
        for client in self.clients.iter_mut() {
            client.portion = client.portion * (1.0-portion);
        }
        client.portion = portion;
        self.clients.push(client);
    }

    pub fn insert(&mut self, index: usize,  mut client: Container) {
        self.be_parent(&mut client);
        let portion = 1.0 / (self.size() as f32 + 1.0);
        client.portion = portion;
        for client in self.clients.iter_mut() {
            client.portion = client.portion * (1.0-portion);
        }
        self.clients.insert(index, client);
    }

    pub fn remove(&mut self, id: xlib::Window) -> Option<Container>{
        let res = self.contain(id);
        match res {
            Some(index) => {
                self.remove_by_index(index)
            }
            None => {
                None
            }
        }
    }

    fn remove_by_index(&mut self, index: usize) -> Option<Container>{
        if index >= self.size() {
            None
        }
        else{
            let r = self.clients.remove(index);
            let portion = 1.0 - r.portion;
            for client in self.clients.iter_mut() {
                client.portion = client.portion / portion;
            }
            Some(r)
        }
    }

    /// remove App container and destroy all its parent containers that are empty
    pub fn tree_remove(&mut self, id: xlib::Window) -> Option<Container> {
        println!("try remove {} from {}", id, self.raw_id());
        let res = self.remove(id);
        match res {
            Some(c) => {
                Some(c)
            }
            None => {
                let mut r: Option<Container> = None;
                let mut index: i32 = -1;
                for (i, c) in self.clients.iter_mut().enumerate() {
                    r = c.tree_remove(id);
                    if r.is_some(){
                        index = i as i32;
                        break
                    }
                }
                if index >= 0 {
                    let i = index as usize;
                    let size = self.get_child(i).unwrap().size();
                    if size == 0 {
                        let container = self.remove_by_index(i);
                        container.unwrap().destroy();
                    }
                }
                r
            }
        }
    }
    pub fn get_child(&mut self, index: usize) -> Option<&mut Container> {
        self.clients.get_mut(index)
    }

    pub fn get_parent(&self) -> Option<&mut Container> {
        if self.parent == ptr::null_mut() {
            None
        }
        else{
            Some(unsafe{ &mut *self.parent })
        }
    }

    pub fn pid(&self) -> xlib::Window {
        match self.get_parent() {
            Some(p) => { p.raw_id() }
            None => { self.context.root }
        }
    }

    pub fn tree_search(&mut self, id: xlib::Window) -> Option<&mut Container>{
        if self.raw_id() == id {
            return Some(self);
        }

        for client in self.clients.iter_mut() {
            let r = client.tree_search(id);
            if r.is_some(){
                return r
            }
        }
        None
    }

    pub fn contain(&self, id: xlib::Window) -> Option<usize>{
        self.clients.iter().position(|x| (*x).raw_id() == id)
    }

    pub fn configure(&mut self, x: i32, y: i32, width: u32, height: u32) {
        libx::resize_window(self.context, self.raw_id(), x, y, width, height);
        // layout for children clients
        self.update_layout();
    }

    pub fn resize_children(&mut self, index: usize, neighbor: usize, step: f32) {
        let size = self.size();
        if index >= 0 && index < size && neighbor >= 0 && neighbor < size {
            {
                let a = self.clients.get(index).unwrap();
                let b = self.clients.get(neighbor).unwrap();
                if (a.portion + step) <= 0.0 || (b.portion - step) < 0.0 {
                    return
                }
            }

            {
                let mut a = self.clients.get_mut(index).unwrap();
                a.portion = a.portion + step;
            }
            {
                let mut b = self.clients.get_mut(neighbor).unwrap();
                b.portion = b.portion - step;
            }
        }
    }

    pub fn update_layout(&mut self) {
        layout::update_layout(self);
    }

    pub fn map(&self) {
        // self.visible = true;
        libx::map_window(self.context, self.raw_id());
        for client in self.clients.iter() {
            client.map();
        }
    }

    pub fn unmap(&self) {
        // self.visible = false;
        for client in self.clients.iter() {
            client.unmap();
        }
        libx::unmap_window(self.context, self.raw_id());
    }

    pub fn destroy(&self) -> bool {
        // can distroy only if it has no clients
        if self.clients.is_empty() {
            unsafe{
                xlib::XDestroyWindow(self.context.display, self.raw_id());
                true
            }
        }
        else {
            false
        }
    }

    pub fn next_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get_child(next)
            }
            None => {
                None
            }
        }
    }

    pub fn last_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get_child(last)
            }
            None => {
                None
            }
        }
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        if self.layout == layout_type {
            match self.direction {
                layout::Direction::Horizontal => {
                    self.direction = layout::Direction::Vertical;
                }
                layout::Direction::Vertical => {
                    self.direction = layout::Direction::Horizontal;
                }
                _ => {}
            }
        }
        else{
            self.layout = layout_type;
            self.direction = layout::Direction::Horizontal;
        }
    }

    pub fn split(&mut self) -> bool {
        if !self.is_empty() || self.raw_id() == self.context.root {
            return false;
        }

        let mut container = Container::new(self.context);
        // add to parent
        match self.get_parent() {
            Some(p) => {
                let attrs = self.rec();

                libx::reparent(self.context, container.raw_id(), p.raw_id(),
                               0, 0);
                // configure to the same size and position like old one
                container.configure(attrs.x, attrs.y,
                                    attrs.width,
                                    attrs.height);
            }
            None => {}
        }

        // swap the property
        let id = self.id;
        self.id = container.id;
        container.id = id;
        container.titlebar_height = self.titlebar_height;
        self.add(container);
        self.map();
        true
    }

    pub fn focus(&self) {
        let id = self.raw_id();
        libx::set_input_focus(self.context, id);
        libx::raise_window(self.context, id);
        self.decorate(true);
    }

    pub fn unfocus(&self) {
        // libx::lower_window(self.context, self.id);
        self.decorate(false);
    }

    pub fn is_focused(&self) -> bool{
        let (w, _) = libx::get_input_focus(self.context);
        w == self.raw_id()
    }

    pub fn switch_client(&self) {
        let (x, _) = libx::get_input_focus(self.context);

    }

    pub fn decorate(&self, focused: bool) {
        match self.get_parent() {
            Some(p) => {
                layout::decorate(self, focused);
            }
            None => {}
        }

    }

    // fullscreen & normal toggle
    pub fn mode_toggle(&mut self) {
        let context = self.context;
        let id = self.raw_id();
        match self.mode {
            Mode::Normal => {
                self.mode = Mode::Fullscreen;
                println!("fullscreen {} {}", id, context.root);
                libx::reparent(context, id, context.root, 0, 0);

                let width = libx::display_width(context, context.screen_num);
                let height = libx::display_height(context, context.screen_num);
                libx::resize_window(context, id, 0, 0,
                                    width,
                                    height);
            }
            Mode::Fullscreen => {
                self.mode = Mode::Normal;

                match self.get_parent() {
                    Some(p) => {
                        let pid = p.raw_id();
                        libx::reparent(context, id, pid, 0, 0);
                        p.update_layout();
                    }
                    None => {
                        let pid =  context.root;
                        libx::reparent(context, id, pid, 0, 0);
                    }
                };
            }
            _ => {}
        }
    }

    // decide which client when click on titlebar
    pub fn query_point(&self, x: i32, y: i32) -> Option<&Container>{
        for client in self.clients.iter() {
            match client.titlebar {
                Some(rec) => {
                    if rec.contain(x, y) {
                        return Some(client);
                    }
                }
                None => {}
            }
        }
        None
    }

    // decide if the point is on the border
    pub fn query_border(&self, x: i32, y: i32) -> Option<usize> {
        for (i, client) in self.clients.iter().enumerate() {
            let rec = client.rec();
            match self.direction {
                layout::Direction::Vertical => {
                    if (y-rec.y).abs() <= 2 {
                        return Some(i)
                    }
                }
                layout::Direction::Horizontal => {
                    if (x-rec.x).abs() <= 2 {
                        return Some(i)
                    }
                }
                _ => {}
            }
        }
        None
    }

    pub fn rec(&self) -> layout::Rectangle {
        let attrs = libx::get_window_attributes(self.context, self.raw_id());
        layout::Rectangle {
            x: attrs.x,
            y: attrs.y,
            width: attrs.width as u32,
            height: attrs.height as u32
        }
    }
}

#[cfg(test)]
mod test{
    use super::*;
    use super::super::WindowManager;
    use super::super::super::libx;

    fn init() -> WindowManager{
        let mut wm = WindowManager::new();
        wm.init();
        wm
    }

    fn clean() {

    }

    #[test]
    fn new() {
        let mut wm = init();
        let c = Container::new(wm.context);
        assert!(c.id.is_some());
    }
}
<commit_msg>clear dirty area when container is empty<commit_after>extern crate libc;
extern crate x11;

use x11::xlib;
use std::ptr;
use super::layout::{ self, Rectangle };
use super::super::libx;

pub enum Mode {
    Normal,
    Fullscreen,
    Resize(usize, i32, i32),
}

pub enum Type {
    App,
    Container,
    Workspace,
}

pub struct Container {
    pub id: Option<xlib::Window>,
    pub visible: bool,
    pub titlebar_height: u32,
    parent: *mut Container,
    pub clients: Vec<Container>,
    pub mode: Mode,
    pub category: Type,
    pub titlebar: Option<Rectangle>,
    pub portion: f32,
    pub context: libx::Context,

    pub layout: layout::Type,
    pub direction: layout::Direction,
}

impl PartialEq for Container {
    fn eq(&self, other: &Self) -> bool {
        self.raw_id() == other.raw_id()
    }
}

impl Container {
    pub fn new(context: libx::Context) -> Container{
        let pid = context.root;
        let attrs = libx::get_window_attributes(context, pid);

        let id = libx::create_window(context, pid,
                                     attrs.x, attrs.y,
                                     attrs.width as u32,
                                     attrs.height as u32);
        let mask = xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask | xlib::ButtonPressMask | xlib::ButtonReleaseMask | xlib::Button1MotionMask | xlib::Button3MotionMask | xlib::ExposureMask;
        libx::select_input(context, id, mask);
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            category: Type::Container,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,
            portion: 1.0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn from_id(context: libx::Context, id: xlib::Window) -> Container {
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            category: Type::App,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,
            portion: 1.0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn print_tree(&self, indent: i32) {
        for i in 0..indent {
            print!(" ");
        }
        let attrs = libx::get_window_attributes(self.context, self.raw_id());
        let pid = match self.get_parent() {
            Some(p) => { p.raw_id() }
            None => { 0}
        };
        println!("C {} pid:{} x:{} y:{} w:{} h:{}", self.raw_id(), pid, attrs.x, attrs.y, attrs.width, attrs.height);
        for client in self.clients.iter() {
            client.print_tree(indent+4);
        }
    }

    pub fn raw_id(&self) -> xlib::Window {
        self.id.unwrap()
    }

    // pub fn is_top(&self) -> bool {
    //     let top = self.get_top();
    //     match top {
    //         Some(w) => {
    //             w.id == self.id
    //         }
    //         Noen => false
    //     }
    // }

    pub fn is_empty(&self) -> bool{
        self.clients.is_empty()
    }

    pub fn size(&self) -> usize {
        self.clients.len()
    }

    pub fn be_parent(&mut self, client: &mut Container) {
        let need_reprent = match client.get_parent() {
            Some(p) => {
                if p.raw_id() == self.raw_id() { false } else { true }
            }
            None => {
                true
            }
        };
        if need_reprent {
            libx::reparent(self.context, client.raw_id(), self.raw_id(), 0, 0);
            client.parent = self;
        }
    }

    pub fn add(&mut self, mut client: Container) {
        self.be_parent(&mut client);
        let portion = 1.0 / (self.size() as f32 + 1.0);
        for client in self.clients.iter_mut() {
            client.portion = client.portion * (1.0-portion);
        }
        client.portion = portion;
        self.clients.push(client);
    }

    pub fn insert(&mut self, index: usize,  mut client: Container) {
        self.be_parent(&mut client);
        let portion = 1.0 / (self.size() as f32 + 1.0);
        client.portion = portion;
        for client in self.clients.iter_mut() {
            client.portion = client.portion * (1.0-portion);
        }
        self.clients.insert(index, client);
    }

    pub fn remove(&mut self, id: xlib::Window) -> Option<Container>{
        let res = self.contain(id);
        match res {
            Some(index) => {
                self.remove_by_index(index)
            }
            None => {
                None
            }
        }
    }

    fn remove_by_index(&mut self, index: usize) -> Option<Container>{
        if index >= self.size() {
            None
        }
        else{
            let r = self.clients.remove(index);
            let portion = 1.0 - r.portion;
            for client in self.clients.iter_mut() {
                client.portion = client.portion / portion;
            }
            if self.size() == 0 {
                unsafe {
                    xlib::XClearWindow(self.context.display, self.raw_id());
                }
            }
            Some(r)
        }
    }

    /// remove App container and destroy all its parent containers that are empty
    pub fn tree_remove(&mut self, id: xlib::Window) -> Option<Container> {
        println!("try remove {} from {}", id, self.raw_id());
        let res = self.remove(id);
        match res {
            Some(c) => {
                Some(c)
            }
            None => {
                let mut r: Option<Container> = None;
                let mut index: i32 = -1;
                for (i, c) in self.clients.iter_mut().enumerate() {
                    r = c.tree_remove(id);
                    if r.is_some(){
                        index = i as i32;
                        break
                    }
                }
                if index >= 0 {
                    let i = index as usize;
                    let size = self.get_child(i).unwrap().size();
                    if size == 0 {
                        let container = self.remove_by_index(i);
                        container.unwrap().destroy();
                    }
                }
                r
            }
        }
    }
    pub fn get_child(&mut self, index: usize) -> Option<&mut Container> {
        self.clients.get_mut(index)
    }

    pub fn get_parent(&self) -> Option<&mut Container> {
        if self.parent == ptr::null_mut() {
            None
        }
        else{
            Some(unsafe{ &mut *self.parent })
        }
    }

    pub fn pid(&self) -> xlib::Window {
        match self.get_parent() {
            Some(p) => { p.raw_id() }
            None => { self.context.root }
        }
    }

    pub fn tree_search(&mut self, id: xlib::Window) -> Option<&mut Container>{
        if self.raw_id() == id {
            return Some(self);
        }

        for client in self.clients.iter_mut() {
            let r = client.tree_search(id);
            if r.is_some(){
                return r
            }
        }
        None
    }

    pub fn contain(&self, id: xlib::Window) -> Option<usize>{
        self.clients.iter().position(|x| (*x).raw_id() == id)
    }

    pub fn configure(&mut self, x: i32, y: i32, width: u32, height: u32) {
        libx::resize_window(self.context, self.raw_id(), x, y, width, height);
        // layout for children clients
        self.update_layout();
    }

    pub fn resize_children(&mut self, index: usize, neighbor: usize, step: f32) {
        let size = self.size();
        if index >= 0 && index < size && neighbor >= 0 && neighbor < size {
            {
                let a = self.clients.get(index).unwrap();
                let b = self.clients.get(neighbor).unwrap();
                if (a.portion + step) <= 0.0 || (b.portion - step) < 0.0 {
                    return
                }
            }

            {
                let mut a = self.clients.get_mut(index).unwrap();
                a.portion = a.portion + step;
            }
            {
                let mut b = self.clients.get_mut(neighbor).unwrap();
                b.portion = b.portion - step;
            }
        }
    }

    pub fn update_layout(&mut self) {
        layout::update_layout(self);
    }

    pub fn map(&self) {
        // self.visible = true;
        libx::map_window(self.context, self.raw_id());
        for client in self.clients.iter() {
            client.map();
        }
    }

    pub fn unmap(&self) {
        // self.visible = false;
        for client in self.clients.iter() {
            client.unmap();
        }
        libx::unmap_window(self.context, self.raw_id());
    }

    pub fn destroy(&self) -> bool {
        // can distroy only if it has no clients
        if self.clients.is_empty() {
            unsafe{
                xlib::XDestroyWindow(self.context.display, self.raw_id());
                true
            }
        }
        else {
            false
        }
    }

    pub fn next_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get_child(next)
            }
            None => {
                None
            }
        }
    }

    pub fn last_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get_child(last)
            }
            None => {
                None
            }
        }
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        if self.layout == layout_type {
            match self.direction {
                layout::Direction::Horizontal => {
                    self.direction = layout::Direction::Vertical;
                }
                layout::Direction::Vertical => {
                    self.direction = layout::Direction::Horizontal;
                }
                _ => {}
            }
        }
        else{
            self.layout = layout_type;
            self.direction = layout::Direction::Horizontal;
        }
    }

    pub fn split(&mut self) -> bool {
        if !self.is_empty() || self.raw_id() == self.context.root {
            return false;
        }

        let mut container = Container::new(self.context);
        // add to parent
        match self.get_parent() {
            Some(p) => {
                let attrs = self.rec();

                libx::reparent(self.context, container.raw_id(), p.raw_id(),
                               0, 0);
                // configure to the same size and position like old one
                container.configure(attrs.x, attrs.y,
                                    attrs.width,
                                    attrs.height);
            }
            None => {}
        }

        // swap the property
        let id = self.id;
        self.id = container.id;
        container.id = id;
        container.titlebar_height = self.titlebar_height;
        self.add(container);
        self.map();
        true
    }

    pub fn focus(&self) {
        let id = self.raw_id();
        libx::set_input_focus(self.context, id);
        libx::raise_window(self.context, id);
        self.decorate(true);
    }

    pub fn unfocus(&self) {
        // libx::lower_window(self.context, self.id);
        self.decorate(false);
    }

    pub fn is_focused(&self) -> bool{
        let (w, _) = libx::get_input_focus(self.context);
        w == self.raw_id()
    }

    pub fn switch_client(&self) {
        let (x, _) = libx::get_input_focus(self.context);

    }

    pub fn decorate(&self, focused: bool) {
        match self.get_parent() {
            Some(p) => {
                layout::decorate(self, focused);
            }
            None => {}
        }

    }

    // fullscreen & normal toggle
    pub fn mode_toggle(&mut self) {
        let context = self.context;
        let id = self.raw_id();
        match self.mode {
            Mode::Normal => {
                self.mode = Mode::Fullscreen;
                println!("fullscreen {} {}", id, context.root);
                libx::reparent(context, id, context.root, 0, 0);

                let width = libx::display_width(context, context.screen_num);
                let height = libx::display_height(context, context.screen_num);
                libx::resize_window(context, id, 0, 0,
                                    width,
                                    height);
            }
            Mode::Fullscreen => {
                self.mode = Mode::Normal;

                match self.get_parent() {
                    Some(p) => {
                        let pid = p.raw_id();
                        libx::reparent(context, id, pid, 0, 0);
                        p.update_layout();
                    }
                    None => {
                        let pid =  context.root;
                        libx::reparent(context, id, pid, 0, 0);
                    }
                };
            }
            _ => {}
        }
    }

    // decide which client when click on titlebar
    pub fn query_point(&self, x: i32, y: i32) -> Option<&Container>{
        for client in self.clients.iter() {
            match client.titlebar {
                Some(rec) => {
                    if rec.contain(x, y) {
                        return Some(client);
                    }
                }
                None => {}
            }
        }
        None
    }

    // decide if the point is on the border
    pub fn query_border(&self, x: i32, y: i32) -> Option<usize> {
        for (i, client) in self.clients.iter().enumerate() {
            let rec = client.rec();
            match self.direction {
                layout::Direction::Vertical => {
                    if (y-rec.y).abs() <= 2 {
                        return Some(i)
                    }
                }
                layout::Direction::Horizontal => {
                    if (x-rec.x).abs() <= 2 {
                        return Some(i)
                    }
                }
                _ => {}
            }
        }
        None
    }

    pub fn rec(&self) -> layout::Rectangle {
        let attrs = libx::get_window_attributes(self.context, self.raw_id());
        layout::Rectangle {
            x: attrs.x,
            y: attrs.y,
            width: attrs.width as u32,
            height: attrs.height as u32
        }
    }
}

#[cfg(test)]
mod test{
    use super::*;
    use super::super::WindowManager;
    use super::super::super::libx;

    fn init() -> WindowManager{
        let mut wm = WindowManager::new();
        wm.init();
        wm
    }

    fn clean() {

    }

    #[test]
    fn new() {
        let mut wm = init();
        let c = Container::new(wm.context);
        assert!(c.id.is_some());
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::fs;
use std::path::{Path, PathBuf};
use std::io;
use std::ops;
use std::fmt::{self, Display};
use rustup_utils::raw;

use rustup_utils::notify::NotificationLevel;

#[derive(Debug)]
pub enum Error {
    CreatingRoot {
        path: PathBuf,
        error: io::Error,
    },
    CreatingFile {
        path: PathBuf,
        error: io::Error,
    },
    CreatingDirectory {
        path: PathBuf,
        error: io::Error,
    },
}

pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Notification<'a> {
    CreatingRoot(&'a Path),
    CreatingFile(&'a Path),
    CreatingDirectory(&'a Path),
    FileDeletion(&'a Path, io::Result<()>),
    DirectoryDeletion(&'a Path, io::Result<()>),
}

pub struct Cfg {
    root_directory: PathBuf,
    notify_handler: Box<Fn(Notification)>,
}

#[derive(Debug)]
pub struct Dir<'a> {
    cfg: &'a Cfg,
    path: PathBuf,
}

#[derive(Debug)]
pub struct File<'a> {
    cfg: &'a Cfg,
    path: PathBuf,
}

impl<'a> Notification<'a> {
    pub fn level(&self) -> NotificationLevel {
        use self::Notification::*;
        match *self {
            CreatingRoot(_) | CreatingFile(_) | CreatingDirectory(_) => NotificationLevel::Verbose,
            FileDeletion(_, ref result) | DirectoryDeletion(_, ref result) => {
                if result.is_ok() {
                    NotificationLevel::Verbose
                } else {
                    NotificationLevel::Warn
                }
            }
        }
    }
}

impl<'a> Display for Notification<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use self::Notification::*;
        match *self {
            CreatingRoot(path) => write!(f, "creating temp root: {}", path.display()),
            CreatingFile(path) => write!(f, "creating temp file: {}", path.display()),
            CreatingDirectory(path) => write!(f, "creating temp directory: {}", path.display()),
            FileDeletion(path, ref result) => {
                if result.is_ok() {
                    write!(f, "deleted temp file: {}", path.display())
                } else {
                    write!(f, "could not delete temp file: {}", path.display())
                }
            }
            DirectoryDeletion(path, ref result) => {
                if result.is_ok() {
                    write!(f, "deleted temp directory: {}", path.display())
                } else {
                    write!(f, "could not delete temp directory: {}", path.display())
                }
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            CreatingRoot {..} => "could not create temp root",
            CreatingFile {..} => "could not create temp file",
            CreatingDirectory {..} => "could not create temp directory",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::Error::*;
        match *self {
            CreatingRoot { ref error, .. } |
            CreatingFile { ref error, .. } |
            CreatingDirectory { ref error, .. } => Some(error),
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use self::Error::*;
        match *self {
            CreatingRoot { ref path, error: _ } => {
                write!(f, "could not create temp root: {}", path.display())
            }
            CreatingFile { ref path, error: _ } => {
                write!(f, "could not create temp file: {}", path.display())
            }
            CreatingDirectory { ref path, error: _ } => {
                write!(f, "could not create temp directory: {}", path.display())
            }
        }
    }
}

impl Cfg {
    pub fn new(root_directory: PathBuf, notify_handler: Box<Fn(Notification)>) -> Self {
        Cfg {
            root_directory: root_directory,
            notify_handler: notify_handler,
        }
    }

    pub fn create_root(&self) -> Result<bool> {
        raw::ensure_dir_exists(&self.root_directory, |p| {
            (self.notify_handler)(Notification::CreatingRoot(p));
        })
            .map_err(|e| {
                Error::CreatingRoot {
                    path: PathBuf::from(&self.root_directory),
                    error: e,
                }
            })
    }

    pub fn new_directory(&self) -> Result<Dir> {
        try!(self.create_root());

        loop {
            let temp_name = raw::random_string(16) + "_dir";

            let temp_dir = self.root_directory.join(temp_name);

            // This is technically racey, but the probability of getting the same
            // random names at exactly the same time is... low.
            if !raw::path_exists(&temp_dir) {
                (self.notify_handler)(Notification::CreatingDirectory(&temp_dir));
                try!(fs::create_dir(&temp_dir).map_err(|e| {
                    Error::CreatingDirectory {
                        path: PathBuf::from(&temp_dir),
                        error: e,
                    }
                }));
                return Ok(Dir {
                    cfg: self,
                    path: temp_dir,
                });
            }
        }
    }

    pub fn new_file(&self) -> Result<File> {
        self.new_file_with_ext("", "")
    }

    pub fn new_file_with_ext(&self, prefix: &str, ext: &str) -> Result<File> {
        try!(self.create_root());

        loop {
            let temp_name = prefix.to_owned() + &raw::random_string(16) + "_file" + ext;

            let temp_file = self.root_directory.join(temp_name);

            // This is technically racey, but the probability of getting the same
            // random names at exactly the same time is... low.
            if !raw::path_exists(&temp_file) {
                (self.notify_handler)(Notification::CreatingFile(&temp_file));
                try!(fs::File::create(&temp_file).map_err(|e| {
                    Error::CreatingFile {
                        path: PathBuf::from(&temp_file),
                        error: e,
                    }
                }));
                return Ok(File {
                    cfg: self,
                    path: temp_file,
                });
            }
        }
    }
}

impl fmt::Debug for Cfg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Cfg")
         .field("root_directory", &self.root_directory)
         .field("notify_handler", &"...")
         .finish()
    }
}

impl<'a> ops::Deref for Dir<'a> {
    type Target = Path;

    fn deref(&self) -> &Path {
        ops::Deref::deref(&self.path)
    }
}

impl<'a> ops::Deref for File<'a> {
    type Target = Path;

    fn deref(&self) -> &Path {
        ops::Deref::deref(&self.path)
    }
}

impl<'a> Drop for Dir<'a> {
    fn drop(&mut self) {
        if raw::is_directory(&self.path) {
            let n = Notification::DirectoryDeletion(&self.path, fs::remove_dir_all(&self.path));
            (self.cfg.notify_handler)(n);
        }
    }
}

impl<'a> Drop for File<'a> {
    fn drop(&mut self) {
        if raw::is_file(&self.path) {
            let n = Notification::FileDeletion(&self.path, fs::remove_file(&self.path));
            (self.cfg.notify_handler)(n);
        }
    }
}
<commit_msg>rustup_dist::temp: Alter `struct Cfg`<commit_after>use std::error;
use std::fs;
use std::path::{Path, PathBuf};
use std::io;
use std::ops;
use std::fmt::{self, Display};
use rustup_utils::raw;

use rustup_utils::notify::NotificationLevel;

#[derive(Debug)]
pub enum Error {
    CreatingRoot {
        path: PathBuf,
        error: io::Error,
    },
    CreatingFile {
        path: PathBuf,
        error: io::Error,
    },
    CreatingDirectory {
        path: PathBuf,
        error: io::Error,
    },
}

pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Notification<'a> {
    CreatingRoot(&'a Path),
    CreatingFile(&'a Path),
    CreatingDirectory(&'a Path),
    FileDeletion(&'a Path, io::Result<()>),
    DirectoryDeletion(&'a Path, io::Result<()>),
}

pub struct Cfg {
    root_directory: PathBuf,
    pub dist_server: String,
    notify_handler: Box<Fn(Notification)>,
}

#[derive(Debug)]
pub struct Dir<'a> {
    cfg: &'a Cfg,
    path: PathBuf,
}

#[derive(Debug)]
pub struct File<'a> {
    cfg: &'a Cfg,
    path: PathBuf,
}

impl<'a> Notification<'a> {
    pub fn level(&self) -> NotificationLevel {
        use self::Notification::*;
        match *self {
            CreatingRoot(_) | CreatingFile(_) | CreatingDirectory(_) => NotificationLevel::Verbose,
            FileDeletion(_, ref result) | DirectoryDeletion(_, ref result) => {
                if result.is_ok() {
                    NotificationLevel::Verbose
                } else {
                    NotificationLevel::Warn
                }
            }
        }
    }
}

impl<'a> Display for Notification<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use self::Notification::*;
        match *self {
            CreatingRoot(path) => write!(f, "creating temp root: {}", path.display()),
            CreatingFile(path) => write!(f, "creating temp file: {}", path.display()),
            CreatingDirectory(path) => write!(f, "creating temp directory: {}", path.display()),
            FileDeletion(path, ref result) => {
                if result.is_ok() {
                    write!(f, "deleted temp file: {}", path.display())
                } else {
                    write!(f, "could not delete temp file: {}", path.display())
                }
            }
            DirectoryDeletion(path, ref result) => {
                if result.is_ok() {
                    write!(f, "deleted temp directory: {}", path.display())
                } else {
                    write!(f, "could not delete temp directory: {}", path.display())
                }
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            CreatingRoot {..} => "could not create temp root",
            CreatingFile {..} => "could not create temp file",
            CreatingDirectory {..} => "could not create temp directory",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::Error::*;
        match *self {
            CreatingRoot { ref error, .. } |
            CreatingFile { ref error, .. } |
            CreatingDirectory { ref error, .. } => Some(error),
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        use self::Error::*;
        match *self {
            CreatingRoot { ref path, error: _ } => {
                write!(f, "could not create temp root: {}", path.display())
            }
            CreatingFile { ref path, error: _ } => {
                write!(f, "could not create temp file: {}", path.display())
            }
            CreatingDirectory { ref path, error: _ } => {
                write!(f, "could not create temp directory: {}", path.display())
            }
        }
    }
}

impl Cfg {
    pub fn new(root_directory: PathBuf, dist_server: &str, notify_handler: Box<Fn(Notification)>) -> Self {
        Cfg {
            root_directory: root_directory,
            dist_server: dist_server.to_owned(),
            notify_handler: notify_handler,
        }
    }

    pub fn create_root(&self) -> Result<bool> {
        raw::ensure_dir_exists(&self.root_directory, |p| {
            (self.notify_handler)(Notification::CreatingRoot(p));
        })
            .map_err(|e| {
                Error::CreatingRoot {
                    path: PathBuf::from(&self.root_directory),
                    error: e,
                }
            })
    }

    pub fn new_directory(&self) -> Result<Dir> {
        try!(self.create_root());

        loop {
            let temp_name = raw::random_string(16) + "_dir";

            let temp_dir = self.root_directory.join(temp_name);

            // This is technically racey, but the probability of getting the same
            // random names at exactly the same time is... low.
            if !raw::path_exists(&temp_dir) {
                (self.notify_handler)(Notification::CreatingDirectory(&temp_dir));
                try!(fs::create_dir(&temp_dir).map_err(|e| {
                    Error::CreatingDirectory {
                        path: PathBuf::from(&temp_dir),
                        error: e,
                    }
                }));
                return Ok(Dir {
                    cfg: self,
                    path: temp_dir,
                });
            }
        }
    }

    pub fn new_file(&self) -> Result<File> {
        self.new_file_with_ext("", "")
    }

    pub fn new_file_with_ext(&self, prefix: &str, ext: &str) -> Result<File> {
        try!(self.create_root());

        loop {
            let temp_name = prefix.to_owned() + &raw::random_string(16) + "_file" + ext;

            let temp_file = self.root_directory.join(temp_name);

            // This is technically racey, but the probability of getting the same
            // random names at exactly the same time is... low.
            if !raw::path_exists(&temp_file) {
                (self.notify_handler)(Notification::CreatingFile(&temp_file));
                try!(fs::File::create(&temp_file).map_err(|e| {
                    Error::CreatingFile {
                        path: PathBuf::from(&temp_file),
                        error: e,
                    }
                }));
                return Ok(File {
                    cfg: self,
                    path: temp_file,
                });
            }
        }
    }
}

impl fmt::Debug for Cfg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Cfg")
         .field("root_directory", &self.root_directory)
         .field("notify_handler", &"...")
         .finish()
    }
}

impl<'a> ops::Deref for Dir<'a> {
    type Target = Path;

    fn deref(&self) -> &Path {
        ops::Deref::deref(&self.path)
    }
}

impl<'a> ops::Deref for File<'a> {
    type Target = Path;

    fn deref(&self) -> &Path {
        ops::Deref::deref(&self.path)
    }
}

impl<'a> Drop for Dir<'a> {
    fn drop(&mut self) {
        if raw::is_directory(&self.path) {
            let n = Notification::DirectoryDeletion(&self.path, fs::remove_dir_all(&self.path));
            (self.cfg.notify_handler)(n);
        }
    }
}

impl<'a> Drop for File<'a> {
    fn drop(&mut self) {
        if raw::is_file(&self.path) {
            let n = Notification::FileDeletion(&self.path, fs::remove_file(&self.path));
            (self.cfg.notify_handler)(n);
        }
    }
}
<|endoftext|>


<commit_before>use std::char::from_u32;
use std::env;
use std::error;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs;
use std::io::Write;
use std::io;
use std::path::Path;
use std::process::{Command, Stdio, ExitStatus};
use std::str;
use std::thread;
use std::time::Duration;

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
                                                           callback: F)
                                                           -> io::Result<bool> {
    if !is_directory(path.as_ref()) {
        callback(path.as_ref());
        fs::create_dir_all(path.as_ref()).map(|()| true)
    } else {
        Ok(false)
    }
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
    let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
    (0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
    if s == *"" {
        None
    } else {
        Some(s)
    }
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .write(true)
                            .truncate(true)
                            .create(true)
                            .open(path));

    try!(io::Write::write_all(&mut file, contents.as_bytes()));

    try!(file.sync_data());

    Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let mut contents = String::new();

    try!(io::Read::read_to_string(&mut file, &mut contents));

    Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path,
                                           dest: &Path,
                                           mut filter: F)
                                           -> io::Result<usize> {
    let src_file = try!(fs::File::open(src));
    let dest_file = try!(fs::File::create(dest));

    let mut reader = io::BufReader::new(src_file);
    let mut writer = io::BufWriter::new(dest_file);
    let mut removed = 0;

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if filter(&line) {
            try!(writeln!(&mut writer, "{}", &line));
        } else {
            removed += 1;
        }
    }

    try!(writer.flush());

    Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
    let src_file = try!(fs::File::open(src));

    let mut reader = io::BufReader::new(src_file);

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if let Some(r) = f(&line) {
            return Ok(Some(r));
        }
    }

    Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
    let mut dest_file = try!(fs::OpenOptions::new()
                                 .write(true)
                                 .append(true)
                                 .create(true)
                                 .open(dest));

    try!(writeln!(&mut dest_file, "{}", line));

    try!(dest_file.sync_data());

    Ok(())
}

pub fn tee_file<W: io::Write>(path: &Path, mut w: &mut W) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let buffer_size = 0x10000;
    let mut buffer = vec![0u8; buffer_size];

    loop {
        let bytes_read = try!(io::Read::read(&mut file, &mut buffer));

        if bytes_read != 0 {
            try!(io::Write::write_all(w, &mut buffer[0..bytes_read]));
        } else {
            return Ok(());
        }
    }
}

pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
    #[cfg(windows)]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        // std's symlink uses Windows's symlink function, which requires
        // admin. We can create directory junctions the hard way without
        // though.
        symlink_junction_inner(src, dest)
    }
    #[cfg(not(windows))]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        ::std::os::unix::fs::symlink(src, dest)
    }

    let _ = remove_dir(dest);
    symlink_dir_inner(src, dest)
}

// Creating a directory junction on windows involves dealing with reparse
// points and the DeviceIoControl function, and this code is a skeleton of
// what can be found here:
//
// http://www.flexhex.com/docs/articles/hard-links.phtml
//
// Copied from std
#[cfg(windows)]
#[allow(non_snake_case)]
fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
    use winapi::*;
    use kernel32::*;
    use std::ptr;
    use std::os::windows::ffi::OsStrExt;

    const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;

    #[repr(C)]
    pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
        pub ReparseTag: DWORD,
        pub ReparseDataLength: DWORD,
        pub Reserved: WORD,
        pub ReparseTargetLength: WORD,
        pub ReparseTargetMaximumLength: WORD,
        pub Reserved1: WORD,
        pub ReparseTarget: WCHAR,
    }

    fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
        fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
            let mut maybe_result: Vec<u16> = s.encode_wide().collect();
            if maybe_result.iter().any(|&u| u == 0) {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "strings passed to WinAPI cannot contain NULs"));
            }
            maybe_result.push(0);
            Ok(maybe_result)
        }
        inner(s.as_ref())
    }

    // We're using low-level APIs to create the junction, and these are more picky about paths.
    // For example, forward slashes cannot be used as a path separator, so we should try to
    // canonicalize the path first.
    let target = try!(fs::canonicalize(target));

    try!(fs::create_dir(junction));

    let path = try!(to_u16s(junction));

    unsafe {
        let h = CreateFileW(path.as_ptr(),
                            GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            0 as *mut _,
                            OPEN_EXISTING,
                            FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
                            ptr::null_mut());

        let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
        let mut db = data.as_mut_ptr()
                        as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
        let buf = &mut (*db).ReparseTarget as *mut _;
        let mut i = 0;
        // FIXME: this conversion is very hacky
        let v = br"\??\";
        let v = v.iter().map(|x| *x as u16);
        for c in v.chain(target.as_os_str().encode_wide().skip(4)) {
            *buf.offset(i) = c;
            i += 1;
        }
        *buf.offset(i) = 0;
        i += 1;
        (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
        (*db).ReparseTargetMaximumLength = (i * 2) as WORD;
        (*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
        (*db).ReparseDataLength =
                (*db).ReparseTargetLength as DWORD + 12;

        let mut ret = 0;
        let res = DeviceIoControl(h as *mut _,
                                  FSCTL_SET_REPARSE_POINT,
                                  data.as_ptr() as *mut _,
                                  (*db).ReparseDataLength + 8,
                                  ptr::null_mut(), 0,
                                  &mut ret,
                                  ptr::null_mut());

        if res == 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }
}

pub fn hardlink(src: &Path, dest: &Path) -> io::Result<()> {
    let _ = fs::remove_file(dest);
    fs::hard_link(src, dest)
}

#[derive(Debug)]
pub enum CommandError {
    Io(io::Error),
    Status(ExitStatus),
}

pub type CommandResult<T> = ::std::result::Result<T, CommandError>;

impl error::Error for CommandError {
    fn description(&self) -> &str {
        use self::CommandError::*;
        match *self {
            Io(_) => "could not execute command",
            Status(_) => "command exited with unsuccessful status",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::CommandError::*;
        match *self {
            Io(ref e) => Some(e),
            Status(_) => None,
        }
    }
}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandError::Io(ref e) => write!(f, "Io: {}", e),
            CommandError::Status(ref s) => write!(f, "Status: {}", s),
        }
    }
}

pub fn cmd_status(cmd: &mut Command) -> CommandResult<()> {
    cmd.status().map_err(CommandError::Io).and_then(|s| {
        if s.success() {
            Ok(())
        } else {
            Err(CommandError::Status(s))
        }
    })
}

pub fn remove_dir(path: &Path) -> io::Result<()> {
    if try!(fs::symlink_metadata(path)).file_type().is_symlink() {
        if cfg!(windows) {
            fs::remove_dir(path)
        } else {
            fs::remove_file(path)
        }
    } else {
        // Again because remove_dir all doesn't delete write-only files on windows,
        // this is a custom implementation, more-or-less copied from cargo.
        // cc rust-lang/rust#31944
        // cc https://github.com/rust-lang/cargo/blob/master/tests/support/paths.rs#L52
        ::remove_dir_all::remove_dir_all(path)
    }
}

pub fn copy_dir(src: &Path, dest: &Path) -> io::Result<()> {
    try!(fs::create_dir(dest));
    for entry in try!(src.read_dir()) {
        let entry = try!(entry);
        let kind = try!(entry.file_type());
        let src = entry.path();
        let dest = dest.join(entry.file_name());
        if kind.is_dir() {
            try!(copy_dir(&src, &dest));
        } else {
            try!(fs::copy(&src, &dest));
        }
    }
    Ok(())
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
    let mut arg = OsString::from(name);
    arg.push(s);
    arg
}

pub fn has_cmd(cmd: &str) -> bool {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    env::split_paths(&path).map(|p| {
        p.join(&cmd)
    }).any(|p| {
        p.exists()
    })
}

pub fn find_cmd<'a>(cmds: &[&'a str]) -> Option<&'a str> {
    cmds.into_iter().map(|&s| s).filter(|&s| has_cmd(s)).next()
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
    #[cfg(not(windows))]
    fn inner(path: &Path) -> io::Result<bool> {
        let commands = ["xdg-open", "open", "firefox", "chromium"];
        if let Some(cmd) = find_cmd(&commands) {
            Command::new(cmd)
                .arg(path)
                .stdin(Stdio::null())
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .spawn()
                .map(|_| true)
        } else {
            Ok(false)
        }
    }
    #[cfg(windows)]
    fn inner(path: &Path) -> io::Result<bool> {
        Command::new("cmd")
            .arg("/C")
            .arg("start")
            .arg(path)
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn()
            .map(|_| true)
    }
    inner(path)
}

#[cfg(windows)]
pub mod windows {
    use winapi::*;
    use std::io;
    use std::path::PathBuf;
    use std::ptr;
    use std::slice;
    use std::ffi::OsString;
    use std::os::windows::ffi::OsStringExt;
    use shell32;
    use ole32;

    #[allow(non_upper_case_globals)]
    pub const FOLDERID_LocalAppData: GUID = GUID {
        Data1: 0xF1B32785,
        Data2: 0x6FBA,
        Data3: 0x4FCF,
        Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
    };
    #[allow(non_upper_case_globals)]
    pub const FOLDERID_Profile: GUID = GUID {
        Data1: 0x5E6C858F,
        Data2: 0x0E22,
        Data3: 0x4760,
        Data4: [0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73],
    };

    pub fn get_special_folder(id: &shtypes::KNOWNFOLDERID) -> io::Result<PathBuf> {

        let mut path = ptr::null_mut();
        let result;

        unsafe {
            let code = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(), &mut path);
            if code == 0 {
                let mut length = 0usize;
                while *path.offset(length as isize) != 0 {
                    length += 1;
                }
                let slice = slice::from_raw_parts(path, length);
                result = Ok(OsString::from_wide(slice).into());
            } else {
                result = Err(io::Error::from_raw_os_error(code));
            }
            ole32::CoTaskMemFree(path as *mut _);
        }
        result
    }
}
<commit_msg>Add sensible-browser to the browser list<commit_after>use std::char::from_u32;
use std::env;
use std::error;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs;
use std::io::Write;
use std::io;
use std::path::Path;
use std::process::{Command, Stdio, ExitStatus};
use std::str;
use std::thread;
use std::time::Duration;

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
                                                           callback: F)
                                                           -> io::Result<bool> {
    if !is_directory(path.as_ref()) {
        callback(path.as_ref());
        fs::create_dir_all(path.as_ref()).map(|()| true)
    } else {
        Ok(false)
    }
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
    let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
    (0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
    if s == *"" {
        None
    } else {
        Some(s)
    }
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .write(true)
                            .truncate(true)
                            .create(true)
                            .open(path));

    try!(io::Write::write_all(&mut file, contents.as_bytes()));

    try!(file.sync_data());

    Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let mut contents = String::new();

    try!(io::Read::read_to_string(&mut file, &mut contents));

    Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path,
                                           dest: &Path,
                                           mut filter: F)
                                           -> io::Result<usize> {
    let src_file = try!(fs::File::open(src));
    let dest_file = try!(fs::File::create(dest));

    let mut reader = io::BufReader::new(src_file);
    let mut writer = io::BufWriter::new(dest_file);
    let mut removed = 0;

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if filter(&line) {
            try!(writeln!(&mut writer, "{}", &line));
        } else {
            removed += 1;
        }
    }

    try!(writer.flush());

    Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
    let src_file = try!(fs::File::open(src));

    let mut reader = io::BufReader::new(src_file);

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if let Some(r) = f(&line) {
            return Ok(Some(r));
        }
    }

    Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
    let mut dest_file = try!(fs::OpenOptions::new()
                                 .write(true)
                                 .append(true)
                                 .create(true)
                                 .open(dest));

    try!(writeln!(&mut dest_file, "{}", line));

    try!(dest_file.sync_data());

    Ok(())
}

pub fn tee_file<W: io::Write>(path: &Path, mut w: &mut W) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let buffer_size = 0x10000;
    let mut buffer = vec![0u8; buffer_size];

    loop {
        let bytes_read = try!(io::Read::read(&mut file, &mut buffer));

        if bytes_read != 0 {
            try!(io::Write::write_all(w, &mut buffer[0..bytes_read]));
        } else {
            return Ok(());
        }
    }
}

pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
    #[cfg(windows)]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        // std's symlink uses Windows's symlink function, which requires
        // admin. We can create directory junctions the hard way without
        // though.
        symlink_junction_inner(src, dest)
    }
    #[cfg(not(windows))]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        ::std::os::unix::fs::symlink(src, dest)
    }

    let _ = remove_dir(dest);
    symlink_dir_inner(src, dest)
}

// Creating a directory junction on windows involves dealing with reparse
// points and the DeviceIoControl function, and this code is a skeleton of
// what can be found here:
//
// http://www.flexhex.com/docs/articles/hard-links.phtml
//
// Copied from std
#[cfg(windows)]
#[allow(non_snake_case)]
fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
    use winapi::*;
    use kernel32::*;
    use std::ptr;
    use std::os::windows::ffi::OsStrExt;

    const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;

    #[repr(C)]
    pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
        pub ReparseTag: DWORD,
        pub ReparseDataLength: DWORD,
        pub Reserved: WORD,
        pub ReparseTargetLength: WORD,
        pub ReparseTargetMaximumLength: WORD,
        pub Reserved1: WORD,
        pub ReparseTarget: WCHAR,
    }

    fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
        fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
            let mut maybe_result: Vec<u16> = s.encode_wide().collect();
            if maybe_result.iter().any(|&u| u == 0) {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "strings passed to WinAPI cannot contain NULs"));
            }
            maybe_result.push(0);
            Ok(maybe_result)
        }
        inner(s.as_ref())
    }

    // We're using low-level APIs to create the junction, and these are more picky about paths.
    // For example, forward slashes cannot be used as a path separator, so we should try to
    // canonicalize the path first.
    let target = try!(fs::canonicalize(target));

    try!(fs::create_dir(junction));

    let path = try!(to_u16s(junction));

    unsafe {
        let h = CreateFileW(path.as_ptr(),
                            GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            0 as *mut _,
                            OPEN_EXISTING,
                            FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
                            ptr::null_mut());

        let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
        let mut db = data.as_mut_ptr()
                        as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
        let buf = &mut (*db).ReparseTarget as *mut _;
        let mut i = 0;
        // FIXME: this conversion is very hacky
        let v = br"\??\";
        let v = v.iter().map(|x| *x as u16);
        for c in v.chain(target.as_os_str().encode_wide().skip(4)) {
            *buf.offset(i) = c;
            i += 1;
        }
        *buf.offset(i) = 0;
        i += 1;
        (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
        (*db).ReparseTargetMaximumLength = (i * 2) as WORD;
        (*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
        (*db).ReparseDataLength =
                (*db).ReparseTargetLength as DWORD + 12;

        let mut ret = 0;
        let res = DeviceIoControl(h as *mut _,
                                  FSCTL_SET_REPARSE_POINT,
                                  data.as_ptr() as *mut _,
                                  (*db).ReparseDataLength + 8,
                                  ptr::null_mut(), 0,
                                  &mut ret,
                                  ptr::null_mut());

        if res == 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }
}

pub fn hardlink(src: &Path, dest: &Path) -> io::Result<()> {
    let _ = fs::remove_file(dest);
    fs::hard_link(src, dest)
}

#[derive(Debug)]
pub enum CommandError {
    Io(io::Error),
    Status(ExitStatus),
}

pub type CommandResult<T> = ::std::result::Result<T, CommandError>;

impl error::Error for CommandError {
    fn description(&self) -> &str {
        use self::CommandError::*;
        match *self {
            Io(_) => "could not execute command",
            Status(_) => "command exited with unsuccessful status",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::CommandError::*;
        match *self {
            Io(ref e) => Some(e),
            Status(_) => None,
        }
    }
}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandError::Io(ref e) => write!(f, "Io: {}", e),
            CommandError::Status(ref s) => write!(f, "Status: {}", s),
        }
    }
}

pub fn cmd_status(cmd: &mut Command) -> CommandResult<()> {
    cmd.status().map_err(CommandError::Io).and_then(|s| {
        if s.success() {
            Ok(())
        } else {
            Err(CommandError::Status(s))
        }
    })
}

pub fn remove_dir(path: &Path) -> io::Result<()> {
    if try!(fs::symlink_metadata(path)).file_type().is_symlink() {
        if cfg!(windows) {
            fs::remove_dir(path)
        } else {
            fs::remove_file(path)
        }
    } else {
        // Again because remove_dir all doesn't delete write-only files on windows,
        // this is a custom implementation, more-or-less copied from cargo.
        // cc rust-lang/rust#31944
        // cc https://github.com/rust-lang/cargo/blob/master/tests/support/paths.rs#L52
        ::remove_dir_all::remove_dir_all(path)
    }
}

pub fn copy_dir(src: &Path, dest: &Path) -> io::Result<()> {
    try!(fs::create_dir(dest));
    for entry in try!(src.read_dir()) {
        let entry = try!(entry);
        let kind = try!(entry.file_type());
        let src = entry.path();
        let dest = dest.join(entry.file_name());
        if kind.is_dir() {
            try!(copy_dir(&src, &dest));
        } else {
            try!(fs::copy(&src, &dest));
        }
    }
    Ok(())
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
    let mut arg = OsString::from(name);
    arg.push(s);
    arg
}

pub fn has_cmd(cmd: &str) -> bool {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    env::split_paths(&path).map(|p| {
        p.join(&cmd)
    }).any(|p| {
        p.exists()
    })
}

pub fn find_cmd<'a>(cmds: &[&'a str]) -> Option<&'a str> {
    cmds.into_iter().map(|&s| s).filter(|&s| has_cmd(s)).next()
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
    #[cfg(not(windows))]
    fn inner(path: &Path) -> io::Result<bool> {
        let commands = ["xdg-open", "open", "firefox", "chromium", "sensible-browser"];
        if let Some(cmd) = find_cmd(&commands) {
            Command::new(cmd)
                .arg(path)
                .stdin(Stdio::null())
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .spawn()
                .map(|_| true)
        } else {
            Ok(false)
        }
    }
    #[cfg(windows)]
    fn inner(path: &Path) -> io::Result<bool> {
        Command::new("cmd")
            .arg("/C")
            .arg("start")
            .arg(path)
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn()
            .map(|_| true)
    }
    inner(path)
}

#[cfg(windows)]
pub mod windows {
    use winapi::*;
    use std::io;
    use std::path::PathBuf;
    use std::ptr;
    use std::slice;
    use std::ffi::OsString;
    use std::os::windows::ffi::OsStringExt;
    use shell32;
    use ole32;

    #[allow(non_upper_case_globals)]
    pub const FOLDERID_LocalAppData: GUID = GUID {
        Data1: 0xF1B32785,
        Data2: 0x6FBA,
        Data3: 0x4FCF,
        Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
    };
    #[allow(non_upper_case_globals)]
    pub const FOLDERID_Profile: GUID = GUID {
        Data1: 0x5E6C858F,
        Data2: 0x0E22,
        Data3: 0x4760,
        Data4: [0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73],
    };

    pub fn get_special_folder(id: &shtypes::KNOWNFOLDERID) -> io::Result<PathBuf> {

        let mut path = ptr::null_mut();
        let result;

        unsafe {
            let code = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(), &mut path);
            if code == 0 {
                let mut length = 0usize;
                while *path.offset(length as isize) != 0 {
                    length += 1;
                }
                let slice = slice::from_raw_parts(path, length);
                result = Ok(OsString::from_wide(slice).into());
            } else {
                result = Err(io::Error::from_raw_os_error(code));
            }
            ole32::CoTaskMemFree(path as *mut _);
        }
        result
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::io::{stderr, Write};

use super::data_structures::*;

pub fn determine_column_type(attr: &ColumnInformation) -> Result<ColumnType, Box<Error>> {
    let is_array = attr.type_name.starts_with('_');
    let tpe = if is_array {
        &attr.type_name[1..]
    } else {
        &attr.type_name
    };

    let diesel_alias_without_postgres_coercion = match &*tpe.to_lowercase() {
        "varchar" | "citext" => Some(tpe),
        _ => None,
    };

    // Postgres doesn't coerce varchar[] to text[] so print out a message to inform
    // the user.
    if let (true, Some(tpe)) = (is_array, diesel_alias_without_postgres_coercion) {
        writeln!(
            &mut stderr(),
            "The column `{}` is of type `{}[]`. This will cause problems when using Diesel. You should consider changing the column type to `text[]`.",
            attr.column_name,
            tpe
        )?;
    }

    Ok(ColumnType {
        rust_name: capitalize(tpe),
        is_array,
        is_nullable: attr.nullable,
        is_unsigned: false,
    })
}

fn capitalize(name: &str) -> String {
    name[..1].to_uppercase() + &name[1..]
}
<commit_msg>Added a small change to automatically convert snake_case type names to CamelCase.<commit_after>use std::error::Error;
use std::io::{stderr, Write};

use super::data_structures::*;

pub fn determine_column_type(attr: &ColumnInformation) -> Result<ColumnType, Box<Error>> {
    let is_array = attr.type_name.starts_with('_');
    let tpe = if is_array {
        &attr.type_name[1..]
    } else {
        &attr.type_name
    };

    let diesel_alias_without_postgres_coercion = match &*tpe.to_lowercase() {
        "varchar" | "citext" => Some(tpe),
        _ => None,
    };

    // Postgres doesn't coerce varchar[] to text[] so print out a message to inform
    // the user.
    if let (true, Some(tpe)) = (is_array, diesel_alias_without_postgres_coercion) {
        writeln!(
            &mut stderr(),
            "The column `{}` is of type `{}[]`. This will cause problems when using Diesel. You should consider changing the column type to `text[]`.",
            attr.column_name,
            tpe
        )?;
    }

    let rust_name = tpe
        .split('_')
        .map(|word| capitalize(word))
        .collect::<String>();

    Ok(ColumnType {
        rust_name,
        is_array,
        is_nullable: attr.nullable,
        is_unsigned: false,
    })
}

fn capitalize(name: &str) -> String {
    name[..1].to_uppercase() + &name[1..]
}
<|endoftext|>


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

use std::io::{ BufRead, Write };
use std::iter::Iterator;
use std::marker::PhantomData;

use event::Event;
use context::Context;
use format::{ Encode, Decode };

use rustc_serialize::{ Encodable, Decodable };
use msgpack::{ Encoder, Decoder };

pub struct Msgpack;

pub struct Iter<'a, R: 'a> where R: BufRead {
    _phantom: PhantomData<&'a ()>,
    input: R
}

impl<'a, R: 'a> Iterator for Iter<'a, R> where R: BufRead {
    type Item = ::Result<Event<'a>>;
    fn next(&mut self) -> Option<::Result<Event<'a>>> {
        Some(Decodable::decode(&mut Decoder::new(&mut self.input))
             .map_err(|e| ::IlcError::MsgpackDecode(e)))
    }
}

impl<'a, W> Encode<'a, W> for Msgpack where W: Write {
    fn encode(&'a self, _context: &'a Context, mut output: W, event: &'a Event) -> ::Result<()> {
        event.encode(&mut Encoder::new(&mut output))
            .map_err(|e| ::IlcError::MsgpackEncode(e))
    }
}

impl<'a, R: 'a> Decode<'a, R> for Msgpack where R: BufRead {
    type Output = Iter<'a, R>;
    fn decode(&'a mut self, _context: &'a Context, input: R) -> Iter<R> {
        Iter { _phantom: PhantomData, input: input }
    }
}
<commit_msg>Properly handle EOF while reading msgpack markers<commit_after>// Copyright 2015 Till Höppner
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::{ BufRead, Write };
use std::iter::Iterator;
use std::marker::PhantomData;

use event::Event;
use context::Context;
use format::{ Encode, Decode };

use rustc_serialize::{ Encodable, Decodable };
use msgpack::{ Encoder, Decoder };

pub struct Msgpack;

pub struct Iter<'a, R: 'a> where R: BufRead {
    _phantom: PhantomData<&'a ()>,
    input: R
}

impl<'a, R: 'a> Iterator for Iter<'a, R> where R: BufRead {
    type Item = ::Result<Event<'a>>;
    fn next(&mut self) -> Option<::Result<Event<'a>>> {
        use msgpack::decode;
        match Event::decode(&mut Decoder::new(&mut self.input)) {
            Ok(e) => Some(Ok(e)),
            Err(decode::serialize::Error::InvalidMarkerRead(decode::ReadError::UnexpectedEOF)) => None,
            Err(e) => Some(Err(::IlcError::MsgpackDecode(e)))
        }
    }
}

impl<'a, W> Encode<'a, W> for Msgpack where W: Write {
    fn encode(&'a self, _context: &'a Context, mut output: W, event: &'a Event) -> ::Result<()> {
        event.encode(&mut Encoder::new(&mut output))
            .map_err(|e| ::IlcError::MsgpackEncode(e))
    }
}

impl<'a, R: 'a> Decode<'a, R> for Msgpack where R: BufRead {
    type Output = Iter<'a, R>;
    fn decode(&'a mut self, _context: &'a Context, input: R) -> Iter<R> {
        Iter { _phantom: PhantomData, input: input }
    }
}
<|endoftext|>