<commit_before>
use size_hint;

use std::cmp::Ordering;
use std::mem::replace;

macro_rules! clone_fields {
    ($name:ident, $base:expr, $($field:ident),+) => (
        $name {
            $(
                $field : $base . $field .clone()
            ),*
        }
    );
}

/// Head element and Tail iterator pair
///
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
/// first items (which are guaranteed to exist).
///
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
/// `KMerge` into a min-heap.
struct HeadTail<I>
    where I: Iterator
{
    head: I::Item,
    tail: I,
}

impl<I> HeadTail<I>
    where I: Iterator
{
    /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
    fn new(mut it: I) -> Option<HeadTail<I>> {
        let head = it.next();
        head.map(|h| {
            HeadTail {
                head: h,
                tail: it,
            }
        })
    }

    /// Hints at the size of the sequence, same as the `Iterator` method.
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.tail.size_hint(), 1)
    }
}

impl<I> Clone for HeadTail<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> Self {
        clone_fields!(HeadTail, self, head, tail)
    }
}

impl<I> PartialEq for HeadTail<I>
    where I: Iterator,
          I::Item: PartialEq
{
    fn eq(&self, other: &HeadTail<I>) -> bool {
        self.head.eq(&other.head)
    }
}

impl<I> Eq for HeadTail<I>
    where I: Iterator,
          I::Item: Eq
{}

impl<I> PartialOrd for HeadTail<I>
    where I: Iterator,
          I::Item: PartialOrd
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.head.partial_cmp(&self.head)
    }

    fn lt(&self, other: &Self) -> bool {
        other.head.lt(&self.head)
    }

    fn le(&self, other: &Self) -> bool {
        other.head.le(&self.head)
    }

    fn gt(&self, other: &Self) -> bool {
        other.head.gt(&self.head)
    }

    fn ge(&self, other: &Self) -> bool {
        other.head.ge(&self.head)
    }
}

impl<I> Ord for HeadTail<I>
    where I: Iterator,
          I::Item: Ord
{
    fn cmp(&self, other: &Self) -> Ordering {
        other.head.cmp(&self.head)
    }
}

/// Make `data` a heap (max-heap w.r.t T's Ord).
fn heapify<T: Ord>(data: &mut [T]) {
    for i in 0..data.len() / 2 {
        sift_down(data, i);
    }
}

/// Sift down element at `index` (`heap` is a max-heap wrt T's Ord).
fn sift_down<T: Ord>(heap: &mut [T], index: usize) {
    debug_assert!(index <= heap.len());
    let mut pos = index;
    let mut child = 2 * pos + 1;
    // the `pos` conditional is to avoid a bounds check
    while pos < heap.len() && child < heap.len() {
        let right = child + 1;

        // pick the bigger of the two children
        if right < heap.len() && heap[child] < heap[right] {
            child = right;
        }

        // sift down is done if we are already in order
        if heap[pos] > heap[child] {
            return;
        }
        heap.swap(pos, child);
        pos = child;
        child = 2 * pos + 1;
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
/// If all base iterators are sorted (ascending), the result is sorted.
///
/// Iterator element type is `I::Item`.
///
/// See [*.kmerge()*](trait.Itertools.html#method.kmerge) for more information.
pub struct KMerge<I>
    where I: Iterator
{
    heap: Vec<HeadTail<I>>,
}

/// Create a `KMerge` iterator.
pub fn kmerge_new<I>(iter: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
    where I: Iterator,
          I::Item: IntoIterator,
          <<I as Iterator>::Item as IntoIterator>::Item: Ord
{
    let (lower, _) = iter.size_hint();
    let mut heap = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap);
    KMerge { heap: heap }
}

impl<I> Clone for KMerge<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> KMerge<I> {
        clone_fields!(KMerge, self, heap)
    }
}

impl<I> Iterator for KMerge<I>
    where I: Iterator,
          I::Item: Ord
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next_0) = self.heap[0].tail.next() {
            replace(&mut self.heap[0].head, next_0)
        } else {
            self.heap.swap_remove(0).head
        };
        sift_down(&mut self.heap, 0);
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if !self.heap.is_empty() {
            let mut it = self.heap.iter();
            let sh0 = it.next().unwrap().size_hint();
            it.fold(sh0, |acc, it| size_hint::add(acc, it.size_hint()))
        } else {
            (0, Some(0))
        }
    }
}

<commit_msg>kmerge: sift_down stopping condition should use greater or equal<commit_after>
use size_hint;

use std::cmp::Ordering;
use std::mem::replace;

macro_rules! clone_fields {
    ($name:ident, $base:expr, $($field:ident),+) => (
        $name {
            $(
                $field : $base . $field .clone()
            ),*
        }
    );
}

/// Head element and Tail iterator pair
///
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
/// first items (which are guaranteed to exist).
///
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
/// `KMerge` into a min-heap.
struct HeadTail<I>
    where I: Iterator
{
    head: I::Item,
    tail: I,
}

impl<I> HeadTail<I>
    where I: Iterator
{
    /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
    fn new(mut it: I) -> Option<HeadTail<I>> {
        let head = it.next();
        head.map(|h| {
            HeadTail {
                head: h,
                tail: it,
            }
        })
    }

    /// Hints at the size of the sequence, same as the `Iterator` method.
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.tail.size_hint(), 1)
    }
}

impl<I> Clone for HeadTail<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> Self {
        clone_fields!(HeadTail, self, head, tail)
    }
}

impl<I> PartialEq for HeadTail<I>
    where I: Iterator,
          I::Item: PartialEq
{
    fn eq(&self, other: &HeadTail<I>) -> bool {
        self.head.eq(&other.head)
    }
}

impl<I> Eq for HeadTail<I>
    where I: Iterator,
          I::Item: Eq
{}

impl<I> PartialOrd for HeadTail<I>
    where I: Iterator,
          I::Item: PartialOrd
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.head.partial_cmp(&self.head)
    }

    fn lt(&self, other: &Self) -> bool {
        other.head.lt(&self.head)
    }

    fn le(&self, other: &Self) -> bool {
        other.head.le(&self.head)
    }

    fn gt(&self, other: &Self) -> bool {
        other.head.gt(&self.head)
    }

    fn ge(&self, other: &Self) -> bool {
        other.head.ge(&self.head)
    }
}

impl<I> Ord for HeadTail<I>
    where I: Iterator,
          I::Item: Ord
{
    fn cmp(&self, other: &Self) -> Ordering {
        other.head.cmp(&self.head)
    }
}

/// Make `data` a heap (max-heap w.r.t T's Ord).
fn heapify<T: Ord>(data: &mut [T]) {
    for i in 0..data.len() / 2 {
        sift_down(data, i);
    }
}

/// Sift down element at `index` (`heap` is a max-heap wrt T's Ord).
fn sift_down<T: Ord>(heap: &mut [T], index: usize) {
    debug_assert!(index <= heap.len());
    let mut pos = index;
    let mut child = 2 * pos + 1;
    // the `pos` conditional is to avoid a bounds check
    while pos < heap.len() && child < heap.len() {
        let right = child + 1;

        // pick the bigger of the two children
        if right < heap.len() && heap[child] < heap[right] {
            child = right;
        }

        // sift down is done if we are already in order
        if heap[pos] >= heap[child] {
            return;
        }
        heap.swap(pos, child);
        pos = child;
        child = 2 * pos + 1;
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
/// If all base iterators are sorted (ascending), the result is sorted.
///
/// Iterator element type is `I::Item`.
///
/// See [*.kmerge()*](trait.Itertools.html#method.kmerge) for more information.
pub struct KMerge<I>
    where I: Iterator
{
    heap: Vec<HeadTail<I>>,
}

/// Create a `KMerge` iterator.
pub fn kmerge_new<I>(iter: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
    where I: Iterator,
          I::Item: IntoIterator,
          <<I as Iterator>::Item as IntoIterator>::Item: Ord
{
    let (lower, _) = iter.size_hint();
    let mut heap = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap);
    KMerge { heap: heap }
}

impl<I> Clone for KMerge<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> KMerge<I> {
        clone_fields!(KMerge, self, heap)
    }
}

impl<I> Iterator for KMerge<I>
    where I: Iterator,
          I::Item: Ord
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next_0) = self.heap[0].tail.next() {
            replace(&mut self.heap[0].head, next_0)
        } else {
            self.heap.swap_remove(0).head
        };
        sift_down(&mut self.heap, 0);
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if !self.heap.is_empty() {
            let mut it = self.heap.iter();
            let sh0 = it.next().unwrap().size_hint();
            it.fold(sh0, |acc, it| size_hint::add(acc, it.size_hint()))
        } else {
            (0, Some(0))
        }
    }
}

<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(clippy::new_ret_no_self)]
use std::cmp::min;
use std::fmt;
use workspaces::Stack;
use xlib_window_system::XlibWindowSystem;
use xlib::Window;

#[derive(Clone, Copy)]
pub struct Rect {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32,
}

impl fmt::Debug for Rect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{{ x: {}, y: {}, width: {}, height: {} }}",
               self.x,
               self.y,
               self.width,
               self.height)
    }
}

#[derive(Clone)]
pub enum LayoutMsg {
    Increase,
    Decrease,
    IncreaseMaster,
    DecreaseMaster,
    SplitHorizontal,
    SplitVertical,
    NextLayout,
    PrevLayout,
    FirstLayout,
    LastLayout,
    Custom(String),
}

impl fmt::Debug for LayoutMsg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LayoutMsg::Increase => write!(f, "Increase"),
            LayoutMsg::Decrease => write!(f, "Decrease"),
            LayoutMsg::IncreaseMaster => write!(f, "IncreasMaster"),
            LayoutMsg::DecreaseMaster => write!(f, "DecreaseMaster"),
            LayoutMsg::SplitHorizontal => write!(f, "SplitHorizontal"),
            LayoutMsg::SplitVertical => write!(f, "SplitVertical"),
            LayoutMsg::NextLayout => write!(f, "NextLayout"),
            LayoutMsg::PrevLayout => write!(f, "PrevLayout"),
            LayoutMsg::FirstLayout => write!(f, "FirstLayout"),
            LayoutMsg::LastLayout => write!(f, "LastLayout"),
            LayoutMsg::Custom(ref val) => write!(f, "Custom({})", val.clone()),
        }
    }
}

pub trait Layout {
    fn name(&self) -> String;
    fn send_msg(&mut self, LayoutMsg);

    fn apply(&self, area: Rect, _: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        self.simple_apply(area, &stack.visible)
    }

    fn simple_apply(&self, Rect, &[Window]) -> Vec<Rect> {
        Vec::new()
    }

    fn copy<'a>(&self) -> Box<dyn Layout + 'a> {
        panic!("")
    }
}

pub struct ChooseLayout<'a> {
    layouts: Vec<Box<dyn Layout + 'a>>,
    current: usize,
}

impl<'a> ChooseLayout<'a> {
    pub fn new(layouts: Vec<Box<dyn Layout + 'a>>) -> Box<dyn Layout + 'a> {
        // add proper error handling
        if layouts.is_empty() {
            panic!("ChooseLayout needs at least one layout");
        }

        Box::new(ChooseLayout {
            layouts,
            current: 0,
        })
    }
}

impl<'a> Layout for ChooseLayout<'a> {
    fn name(&self) -> String {
        self.layouts[self.current].name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        let len = self.layouts.len();

        match msg {
            LayoutMsg::NextLayout => {
                self.current = (self.current + 1) % len;
            }
            LayoutMsg::PrevLayout => {
                self.current = (self.current + len - 1) % len;
            }
            LayoutMsg::FirstLayout => {
                self.current = 0;
            }
            LayoutMsg::LastLayout => {
                self.current = len - 1;
            }
            x => {
                self.layouts[self.current].send_msg(x);
            }
        }
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        self.layouts[self.current].apply(area, ws, stack)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        ChooseLayout::new(self.layouts.iter().map(|x| x.copy()).collect())
    }
}

#[derive(Clone, Copy)]
pub struct TallLayout {
    num_masters: usize,
    ratio: f32,
    ratio_increment: f32,
}

impl TallLayout {
    pub fn new<'a>(num_masters: usize, ratio: f32, ratio_increment: f32) -> Box<dyn Layout + 'a> {
        Box::new(TallLayout {
            num_masters,
            ratio,
            ratio_increment,
        })
    }
}

impl Layout for TallLayout {
    fn name(&self) -> String {
        "Tall".to_string()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        match msg {
            LayoutMsg::Increase => {
                if self.ratio + self.ratio_increment < 1.0 {
                    self.ratio += self.ratio_increment;
                }
            }
            LayoutMsg::Decrease => {
                if self.ratio - self.ratio_increment > self.ratio_increment {
                    self.ratio -= self.ratio_increment;
                }
            }
            LayoutMsg::IncreaseMaster => self.num_masters += 1,
            LayoutMsg::DecreaseMaster => {
                if self.num_masters > 1 {
                    self.num_masters -= 1;
                }
            }
            _ => {}
        }
    }

    fn simple_apply(&self, area: Rect, windows: &[Window]) -> Vec<Rect> {
        let nwindows = windows.len();

        (0..nwindows)
            .map(|i| {
                if i < self.num_masters {
                    let yoff = area.height / min(self.num_masters, nwindows) as u32;

                    Rect {
                        x: area.x,
                        y: area.y + (yoff * i as u32),
                        width: (area.width as f32 *
                                (1.0 -
                                 (nwindows > self.num_masters) as u32 as f32 *
                                 (1.0 - self.ratio)))
                            .floor() as u32,
                        height: yoff,
                    }
                } else {
                    let yoff = area.height / (nwindows - self.num_masters) as u32;

                    Rect {
                        x: area.x + (area.width as f32 * self.ratio).floor() as u32,
                        y: area.y + (yoff * (i - self.num_masters) as u32),
                        width: (area.width as f32 * (1.0 - self.ratio)).floor() as u32,
                        height: yoff,
                    }
                }
            })
            .collect()
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        Box::new(*self)
    }
}

pub struct StrutLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> StrutLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(StrutLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for StrutLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let mut new_area = Rect {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
        };
        let strut = ws.get_strut(area);

        new_area.x = area.x + strut.0;
        new_area.width = area.width - (strut.0 + strut.1);
        new_area.y = area.y + strut.2;
        new_area.height = area.height - (strut.2 + strut.3);

        self.layout.apply(new_area, ws, stack)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        StrutLayout::new(self.layout.copy())
    }
}

#[derive(Clone, Copy)]
pub struct FullLayout {
    focus: Option<Window>
}

impl FullLayout {
    pub fn new<'a>() -> Box<dyn Layout + 'a> {
        Box::new(FullLayout{
            focus: None
        })
    }
}

impl Layout for FullLayout {
    fn name(&self) -> String {
        "Full".to_string()
    }

    fn send_msg(&mut self, _msg: LayoutMsg) {}

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        stack.visible.iter()
            .map(|&window| {
                if window == stack.focused_window {
                    ws.raise_window(window);
                } else {
                    ws.lower_window(window);
                }

                Rect {
                    x: area.x,
                    y: area.y,
                    width: area.width,
                    height: area.height,
                }
            }).collect()
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        Box::new(*self)
    }
}

pub struct GapLayout<'a> {
    screen_gap: u32,
    window_gap: u32,
    layout: Box<dyn Layout + 'a>,
}

impl<'a> GapLayout<'a> {
    pub fn new(screen_gap: u32, window_gap: u32, layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(GapLayout {
            screen_gap,
            window_gap,
            layout: layout.copy(),
        })
    }
}

impl<'a> Layout for GapLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let area = Rect {
            x: area.x + self.screen_gap,
            y: area.y + self.screen_gap,
            width: area.width - (2 * self.screen_gap),
            height: area.height - (2 * self.screen_gap),
        };

        let mut rects = self.layout.apply(area, ws, stack);

        for rect in rects.iter_mut() {
            rect.x += self.window_gap;
            rect.y += self.window_gap;
            rect.width -= 2 * self.window_gap;
            rect.height -= 2 * self.window_gap;
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        GapLayout::new(self.screen_gap, self.window_gap, self.layout.copy())
    }
}

pub struct MirrorLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> MirrorLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(MirrorLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for MirrorLayout<'a> {
    fn name(&self) -> String {
        format!("Mirror({})", self.layout.name())
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let mut rects = self.layout.apply(area, ws, stack);

        for rect in rects.iter_mut() {
            rect.x = area.width - (rect.x + rect.width);
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        MirrorLayout::new(self.layout.copy())
    }
}
<commit_msg>Fix overlapped unmanaged windows using full layout<commit_after>#![allow(dead_code)]
#![allow(clippy::new_ret_no_self)]
use std::cmp::min;
use std::fmt;
use workspaces::Stack;
use xlib_window_system::XlibWindowSystem;
use xlib::Window;

#[derive(Clone, Copy)]
pub struct Rect {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32,
}

impl fmt::Debug for Rect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{{ x: {}, y: {}, width: {}, height: {} }}",
               self.x,
               self.y,
               self.width,
               self.height)
    }
}

#[derive(Clone)]
pub enum LayoutMsg {
    Increase,
    Decrease,
    IncreaseMaster,
    DecreaseMaster,
    SplitHorizontal,
    SplitVertical,
    NextLayout,
    PrevLayout,
    FirstLayout,
    LastLayout,
    Custom(String),
}

impl fmt::Debug for LayoutMsg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LayoutMsg::Increase => write!(f, "Increase"),
            LayoutMsg::Decrease => write!(f, "Decrease"),
            LayoutMsg::IncreaseMaster => write!(f, "IncreasMaster"),
            LayoutMsg::DecreaseMaster => write!(f, "DecreaseMaster"),
            LayoutMsg::SplitHorizontal => write!(f, "SplitHorizontal"),
            LayoutMsg::SplitVertical => write!(f, "SplitVertical"),
            LayoutMsg::NextLayout => write!(f, "NextLayout"),
            LayoutMsg::PrevLayout => write!(f, "PrevLayout"),
            LayoutMsg::FirstLayout => write!(f, "FirstLayout"),
            LayoutMsg::LastLayout => write!(f, "LastLayout"),
            LayoutMsg::Custom(ref val) => write!(f, "Custom({})", val.clone()),
        }
    }
}

pub trait Layout {
    fn name(&self) -> String;
    fn send_msg(&mut self, LayoutMsg);

    fn apply(&self, area: Rect, _: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        self.simple_apply(area, &stack.visible)
    }

    fn simple_apply(&self, Rect, &[Window]) -> Vec<Rect> {
        Vec::new()
    }

    fn copy<'a>(&self) -> Box<dyn Layout + 'a> {
        panic!("")
    }
}

pub struct ChooseLayout<'a> {
    layouts: Vec<Box<dyn Layout + 'a>>,
    current: usize,
}

impl<'a> ChooseLayout<'a> {
    pub fn new(layouts: Vec<Box<dyn Layout + 'a>>) -> Box<dyn Layout + 'a> {
        // add proper error handling
        if layouts.is_empty() {
            panic!("ChooseLayout needs at least one layout");
        }

        Box::new(ChooseLayout {
            layouts,
            current: 0,
        })
    }
}

impl<'a> Layout for ChooseLayout<'a> {
    fn name(&self) -> String {
        self.layouts[self.current].name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        let len = self.layouts.len();

        match msg {
            LayoutMsg::NextLayout => {
                self.current = (self.current + 1) % len;
            }
            LayoutMsg::PrevLayout => {
                self.current = (self.current + len - 1) % len;
            }
            LayoutMsg::FirstLayout => {
                self.current = 0;
            }
            LayoutMsg::LastLayout => {
                self.current = len - 1;
            }
            x => {
                self.layouts[self.current].send_msg(x);
            }
        }
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        self.layouts[self.current].apply(area, ws, stack)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        ChooseLayout::new(self.layouts.iter().map(|x| x.copy()).collect())
    }
}

#[derive(Clone, Copy)]
pub struct TallLayout {
    num_masters: usize,
    ratio: f32,
    ratio_increment: f32,
}

impl TallLayout {
    pub fn new<'a>(num_masters: usize, ratio: f32, ratio_increment: f32) -> Box<dyn Layout + 'a> {
        Box::new(TallLayout {
            num_masters,
            ratio,
            ratio_increment,
        })
    }
}

impl Layout for TallLayout {
    fn name(&self) -> String {
        "Tall".to_string()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        match msg {
            LayoutMsg::Increase => {
                if self.ratio + self.ratio_increment < 1.0 {
                    self.ratio += self.ratio_increment;
                }
            }
            LayoutMsg::Decrease => {
                if self.ratio - self.ratio_increment > self.ratio_increment {
                    self.ratio -= self.ratio_increment;
                }
            }
            LayoutMsg::IncreaseMaster => self.num_masters += 1,
            LayoutMsg::DecreaseMaster => {
                if self.num_masters > 1 {
                    self.num_masters -= 1;
                }
            }
            _ => {}
        }
    }

    fn simple_apply(&self, area: Rect, windows: &[Window]) -> Vec<Rect> {
        let nwindows = windows.len();

        (0..nwindows)
            .map(|i| {
                if i < self.num_masters {
                    let yoff = area.height / min(self.num_masters, nwindows) as u32;

                    Rect {
                        x: area.x,
                        y: area.y + (yoff * i as u32),
                        width: (area.width as f32 *
                                (1.0 -
                                 (nwindows > self.num_masters) as u32 as f32 *
                                 (1.0 - self.ratio)))
                            .floor() as u32,
                        height: yoff,
                    }
                } else {
                    let yoff = area.height / (nwindows - self.num_masters) as u32;

                    Rect {
                        x: area.x + (area.width as f32 * self.ratio).floor() as u32,
                        y: area.y + (yoff * (i - self.num_masters) as u32),
                        width: (area.width as f32 * (1.0 - self.ratio)).floor() as u32,
                        height: yoff,
                    }
                }
            })
            .collect()
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        Box::new(*self)
    }
}

pub struct StrutLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> StrutLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(StrutLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for StrutLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let mut new_area = Rect {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
        };
        let strut = ws.get_strut(area);

        new_area.x = area.x + strut.0;
        new_area.width = area.width - (strut.0 + strut.1);
        new_area.y = area.y + strut.2;
        new_area.height = area.height - (strut.2 + strut.3);

        self.layout.apply(new_area, ws, stack)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        StrutLayout::new(self.layout.copy())
    }
}

#[derive(Clone, Copy)]
pub struct FullLayout {
    focus: Option<Window>
}

impl FullLayout {
    pub fn new<'a>() -> Box<dyn Layout + 'a> {
        Box::new(FullLayout{
            focus: None
        })
    }
}

impl Layout for FullLayout {
    fn name(&self) -> String {
        "Full".to_string()
    }

    fn send_msg(&mut self, _msg: LayoutMsg) {}

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        stack.visible.iter()
            .map(|&window| {
                if window != stack.focused_window {
                    ws.lower_window(window);
                }

                Rect {
                    x: area.x,
                    y: area.y,
                    width: area.width,
                    height: area.height,
                }
            }).collect()
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        Box::new(*self)
    }
}

pub struct GapLayout<'a> {
    screen_gap: u32,
    window_gap: u32,
    layout: Box<dyn Layout + 'a>,
}

impl<'a> GapLayout<'a> {
    pub fn new(screen_gap: u32, window_gap: u32, layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(GapLayout {
            screen_gap,
            window_gap,
            layout: layout.copy(),
        })
    }
}

impl<'a> Layout for GapLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let area = Rect {
            x: area.x + self.screen_gap,
            y: area.y + self.screen_gap,
            width: area.width - (2 * self.screen_gap),
            height: area.height - (2 * self.screen_gap),
        };

        let mut rects = self.layout.apply(area, ws, stack);

        for rect in rects.iter_mut() {
            rect.x += self.window_gap;
            rect.y += self.window_gap;
            rect.width -= 2 * self.window_gap;
            rect.height -= 2 * self.window_gap;
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        GapLayout::new(self.screen_gap, self.window_gap, self.layout.copy())
    }
}

pub struct MirrorLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> MirrorLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(MirrorLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for MirrorLayout<'a> {
    fn name(&self) -> String {
        format!("Mirror({})", self.layout.name())
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let mut rects = self.layout.apply(area, ws, stack);

        for rect in rects.iter_mut() {
            rect.x = area.width - (rect.x + rect.width);
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        MirrorLayout::new(self.layout.copy())
    }
}
<|endoftext|>


<commit_before>use std;
use std::io::prelude::*;
use std::net::{UdpSocket, ToSocketAddrs};
use std::mem;
use std::hash::{Hash, Hasher, SipHasher};

use log::{Log, LogRecord, LogLevel, LogMetadata};
use flate2::Compression;
use flate2::write::GzEncoder;
use chrono::{DateTime, UTC};
use serde_json;
use byteorder::{BigEndian, WriteBytesExt};

use GraylogError;

const MAX_PACKET_SIZE: usize = 8192;
const MAGIC_BYTES: u16 = 0x1E0F;

struct GraylogLogger {
    server: A,
    sock: UdpSocket,
    level: LogLevel,
    hostname: String,
}

#[derive(Serialize, Deserialize)]
struct Gelf {
    version: String,
    host: String,
    short_message: String,
    full_message: Option<String>,
    timestamp: Option<i64>,
    level: Option<u8>,
}

struct GelfChunks<'a> {
    count: usize,
    total: usize,
    #[allow(dead_code)]
    data: &'a [u8],
    chunks: Vec<&'a [u8]>,
    message_id: u64,
}

struct Chunk<'a> {
    header: ChunkHeader,
    data: &'a [u8],
}

impl<'a> Chunk<'a> {
    fn to_binary(&self) -> Result<Vec<u8>, GraylogError> {
        let mut wrt = vec![];
        try!(wrt.write_u16::<BigEndian>(self.header.magic_bytes));
        try!(wrt.write_u64::<BigEndian>(self.header.message_id));
        try!(wrt.write_u8(self.header.seq_number));
        try!(wrt.write_u8(self.header.seq_count));
        wrt.extend(self.data.iter().cloned());
        Ok(wrt)
    }
}

struct ChunkHeader {
    magic_bytes: u16,
    message_id: u64,
    seq_number: u8,
    seq_count: u8,
}

impl<'a> GelfChunks<'a> {
    fn new(data: &'a [u8], message_id: u64) -> GelfChunks<'a> {
        let chunk_size = MAX_PACKET_SIZE - mem::size_of::<ChunkHeader>();
        let mut chunks = data.chunks(chunk_size).collect::<Vec<&[u8]>>();
        chunks.reverse();

        GelfChunks {
            count: 0,
            total: data.len() / chunk_size,
            chunks: chunks,
            data: data,
            message_id: message_id,
        }
    }
}

impl<'a> Iterator for GelfChunks<'a> {
    type Item = Chunk<'a>;

    fn next(&mut self) -> Option<Chunk<'a>> {
        self.chunks.pop().map(|data| {
            let header = ChunkHeader {
                magic_bytes: MAGIC_BYTES,
                message_id: self.message_id,
                seq_number: self.count as u8,
                seq_count: self.total as u8,
            };

            self.count += 1;

            Chunk {
                header: header,
                data: data,
            }
        })
    }
}

pub fn init(addr: A, level: LogLevel) -> Result<(), GraylogError>
    where A: std::marker::Send + std::marker::Sync
{
    use log;
    use std::process::Command;
    let sock = try!(UdpSocket::bind("0.0.0.0:0"));

    try!(log::set_logger(|max_log_level| {
        max_log_level.set(level.to_log_level_filter());
        let hostname = Command::new("hostname")
            .arg("-f")
            .output()
            .map(|out| String::from_utf8_lossy(&out.stdout).into_owned())
            .unwrap_or("unknown".to_string());

        Box::new(GraylogLogger {
            level: level,
            server: addr,
            sock: sock,
            hostname: hostname,
        })
    }));
    Ok(())
}

impl Gelf {
    fn message_id(&self) -> u64 {
        use chrono::Timelike;
        let mut s = SipHasher::new();
        self.host.hash(&mut s);
        self.timestamp.hash(&mut s);
        UTC::now().nanosecond().hash(&mut s);
        s.finish()
    }
}

impl GraylogLogger {
    fn send_as_gelf(&self, record: &LogRecord) -> Result<usize, GraylogError> {
        let mut e = GzEncoder::new(Vec::new(), Compression::Default);
        let utc: DateTime<UTC> = UTC::now();

        let gelf = Gelf {
            version: "1.1".to_string(),
            short_message: format!("{}", record.args()),
            full_message: None,
            timestamp: Some(utc.timestamp()),
            level: None,
            host: self.hostname.clone(),
        };

        let json = try!(serde_json::to_string(&gelf));
        try!(e.write(json.as_bytes()));

        let compressed_bytes = try!(e.finish());
        if compressed_bytes.len() > MAX_PACKET_SIZE {
            self.send_chunked_gelf(&compressed_bytes, gelf.message_id())
        } else {
            self.send(&compressed_bytes)
        }
    }

    fn send_chunked_gelf(&self, buffer: &[u8], message_id: u64) -> Result<usize, GraylogError> {
        let chunks = GelfChunks::new(buffer, message_id);
        println!("{:x}", message_id);
        for chunk in chunks {
            let data = try!(chunk.to_binary());
            try!(self.send(&data));
        }
        Ok(1)
    }

    fn send(&self, buffer: &[u8]) -> Result<usize, GraylogError> {
        let s = try!(self.sock.send_to(buffer, &self.server).or_else(|e| {
            println!("Error writing to Graylog: {}", e);
            Err(e)
        }));
        Ok(s)
    }
}

impl Log for GraylogLogger
    where A: std::marker::Send + std::marker::Sync
{
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if self.send_as_gelf(record).is_err() {
                println!("{} {} - {}", UTC::now(), record.level(), record.args());
            };
        }
    }
}
<commit_msg>we own the data so we don’t need to clone its slices<commit_after>use std;
use std::io::prelude::*;
use std::net::{UdpSocket, ToSocketAddrs};
use std::mem;
use std::hash::{Hash, Hasher, SipHasher};

use log::{Log, LogRecord, LogLevel, LogMetadata};
use flate2::Compression;
use flate2::write::GzEncoder;
use chrono::{DateTime, UTC};
use serde_json;
use byteorder::{BigEndian, WriteBytesExt};

use GraylogError;

const MAX_PACKET_SIZE: usize = 8192;
const MAGIC_BYTES: u16 = 0x1E0F;

struct GraylogLogger {
    server: A,
    sock: UdpSocket,
    level: LogLevel,
    hostname: String,
}

#[derive(Serialize, Deserialize)]
struct Gelf {
    version: String,
    host: String,
    short_message: String,
    full_message: Option<String>,
    timestamp: Option<i64>,
    level: Option<u8>,
}

struct GelfChunks<'a> {
    count: usize,
    total: usize,
    #[allow(dead_code)]
    data: &'a [u8],
    chunks: Vec<&'a [u8]>,
    message_id: u64,
}

struct Chunk<'a> {
    header: ChunkHeader,
    data: &'a [u8],
}

impl<'a> Chunk<'a> {
    fn to_binary(&self) -> Result<Vec<u8>, GraylogError> {
        let mut wrt = vec![];
        try!(wrt.write_u16::<BigEndian>(self.header.magic_bytes));
        try!(wrt.write_u64::<BigEndian>(self.header.message_id));
        try!(wrt.write_u8(self.header.seq_number));
        try!(wrt.write_u8(self.header.seq_count));
         wrt.extend(self.data.iter());
        Ok(wrt)
    }
}

struct ChunkHeader {
    magic_bytes: u16,
    message_id: u64,
    seq_number: u8,
    seq_count: u8,
}

impl<'a> GelfChunks<'a> {
    fn new(data: &'a [u8], message_id: u64) -> GelfChunks<'a> {
        let chunk_size = MAX_PACKET_SIZE - mem::size_of::<ChunkHeader>();
        let mut chunks = data.chunks(chunk_size).collect::<Vec<&[u8]>>();
        chunks.reverse();

        GelfChunks {
            count: 0,
            total: data.len() / chunk_size,
            chunks: chunks,
            data: data,
            message_id: message_id,
        }
    }
}

impl<'a> Iterator for GelfChunks<'a> {
    type Item = Chunk<'a>;

    fn next(&mut self) -> Option<Chunk<'a>> {
        self.chunks.pop().map(|data| {
            let header = ChunkHeader {
                magic_bytes: MAGIC_BYTES,
                message_id: self.message_id,
                seq_number: self.count as u8,
                seq_count: self.total as u8,
            };

            self.count += 1;

            Chunk {
                header: header,
                data: data,
            }
        })
    }
}

pub fn init(addr: A, level: LogLevel) -> Result<(), GraylogError>
    where A: std::marker::Send + std::marker::Sync
{
    use log;
    use std::process::Command;
    let sock = try!(UdpSocket::bind("0.0.0.0:0"));

    try!(log::set_logger(|max_log_level| {
        max_log_level.set(level.to_log_level_filter());
        let hostname = Command::new("hostname")
            .arg("-f")
            .output()
            .map(|out| String::from_utf8_lossy(&out.stdout).into_owned())
            .unwrap_or("unknown".to_string());

        Box::new(GraylogLogger {
            level: level,
            server: addr,
            sock: sock,
            hostname: hostname,
        })
    }));
    Ok(())
}

impl Gelf {
    fn message_id(&self) -> u64 {
        use chrono::Timelike;
        let mut s = SipHasher::new();
        self.host.hash(&mut s);
        self.timestamp.hash(&mut s);
        UTC::now().nanosecond().hash(&mut s);
        s.finish()
    }
}

impl GraylogLogger {
    fn send_as_gelf(&self, record: &LogRecord) -> Result<usize, GraylogError> {
        let mut e = GzEncoder::new(Vec::new(), Compression::Default);
        let utc: DateTime<UTC> = UTC::now();

        let gelf = Gelf {
            version: "1.1".to_string(),
            short_message: format!("{}", record.args()),
            full_message: None,
            timestamp: Some(utc.timestamp()),
            level: None,
            host: self.hostname.clone(),
        };

        let json = try!(serde_json::to_string(&gelf));
        try!(e.write(json.as_bytes()));

        let compressed_bytes = try!(e.finish());
        if compressed_bytes.len() > MAX_PACKET_SIZE {
            self.send_chunked_gelf(&compressed_bytes, gelf.message_id())
        } else {
            self.send(&compressed_bytes)
        }
    }

    fn send_chunked_gelf(&self, buffer: &[u8], message_id: u64) -> Result<usize, GraylogError> {
        let chunks = GelfChunks::new(buffer, message_id);
        println!("{:x}", message_id);
        for chunk in chunks {
            let data = try!(chunk.to_binary());
            try!(self.send(&data));
        }
        Ok(1)
    }

    fn send(&self, buffer: &[u8]) -> Result<usize, GraylogError> {
        let s = try!(self.sock.send_to(buffer, &self.server).or_else(|e| {
            println!("Error writing to Graylog: {}", e);
            Err(e)
        }));
        Ok(s)
    }
}

impl Log for GraylogLogger
    where A: std::marker::Send + std::marker::Sync
{
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if self.send_as_gelf(record).is_err() {
                println!("{} {} - {}", UTC::now(), record.level(), record.args());
            };
        }
    }
}
<|endoftext|>


<commit_before>use gpu;
use rom;
use timer;

pub struct Memory {
    pub rom: rom::Rom,
    pub gpu: gpu::Gpu,
    pub timer: timer::Timer,
    ram: [u8, ..0x4000],
    hram: [u8, ..0x79],
    if_: u8,
    ie: u8
}

impl Memory {
    pub fn new(rom: rom::Rom, gpu: gpu::Gpu, timer: timer::Timer) -> Memory {
        Memory {
            rom: rom,
            gpu: gpu,
            timer: timer,
            ram: [0x00, ..0x4000],
            hram: [0x00, ..0x79],
            if_: 0x00,
            ie: 0x00
        }
    }

    pub fn read_byte(&self, address: u16) -> u8 {
        match address {
            0x0000..0x7FFF => self.rom.bytes[address as uint],
            0x8000..0x9FFF => self.gpu.read_byte(address),
            0xA000..0xBFFF => {
                print!("External RAM not implemented!");
                0x00
            },
            0xC000..0xDFFF => self.ram[address as uint - 0xC000],
            0xE000..0xFDFF => self.ram[address as uint - 0xE000],
            0xFE00..0xFE9F => self.gpu.read_byte(address),
            0xFEA0..0xFEFF => fail!("0xFEA0..0xFEFF segment is no usable"),
            0xFF00..0xFF7F => {
                match address {
                    0xFF04..0xFF07 => {
                        self.timer.read_byte(address)
                    },
                    0xFF0F => {
                        self.if_
                    },
                    0xFF40..0xFF4B => {
                        self.gpu.read_byte(address)
                    },
                    _ => {
                        print!("Implement I/O ports stuff... ");
                        0x00
                    }
                }
            },
            0xFF80..0xFFFE => self.hram[address as uint - 0xFF80],
            0xFFFF => self.ie,
            _ => unreachable!()
        }
    }

    pub fn write_byte(&mut self, address: u16, value: u8) {
        match address {
            0x0000..0x7FFF => {
                fail!("Address not writable in MBC0: {:#06x}", address);
            },
            0x8000..0x9FFF => {
                self.gpu.write_byte(address, value);
            },
            0xA000..0xBFFF => {
                print!("External RAM not implemented!");
            }
            0xC000..0xDFFF => {
                self.ram[address as uint - 0xC000] = value;
            },
            0xE000..0xFDFF => {
                self.ram[address as uint - 0xE000] = value;
            },
            0xFE00..0xFE9F => {
                self.gpu.write_byte(address, value);
            },
            0xFEA0..0xFEFF => fail!("0xFEA0..0xFEFF segment is no usable"),
            0xFF00..0xFF7F => {
                match address {
                    0xFF04..0xFF07 => {
                        self.timer.write_byte(address, value);
                    },
                    0xFF0F => {
                        self.if_ = value;
                    },
                    0xFF40..0xFF4B => {
                        self.gpu.write_byte(address, value);
                    },
                    _ => print!("Implement I/O ports stuff... ")
                }
            },
            0xFF80..0xFFFE => {
                self.hram[address as uint - 0xFF80] = value;
            },
            0xFFFF => {
                self.ie = value;
            },
            _ => unreachable!()
        }
    }

    pub fn read_word(&self, address: u16) -> u16 {
        self.read_byte(address) as u16 |
            self.read_byte(address + 1) as u16 << 8
    }

    pub fn write_word(&mut self, address: u16, value: u16) {
        self.write_byte(address, (value & 0xFF) as u8);
        self.write_byte(address + 1, (value >> 8) as u8);
    }
}
<commit_msg>Print when writing to serial port<commit_after>use gpu;
use rom;
use timer;

pub struct Memory {
    pub rom: rom::Rom,
    pub gpu: gpu::Gpu,
    pub timer: timer::Timer,
    ram: [u8, ..0x4000],
    hram: [u8, ..0x79],
    if_: u8,
    ie: u8
}

impl Memory {
    pub fn new(rom: rom::Rom, gpu: gpu::Gpu, timer: timer::Timer) -> Memory {
        Memory {
            rom: rom,
            gpu: gpu,
            timer: timer,
            ram: [0x00, ..0x4000],
            hram: [0x00, ..0x79],
            if_: 0x00,
            ie: 0x00
        }
    }

    pub fn read_byte(&self, address: u16) -> u8 {
        match address {
            0x0000..0x7FFF => self.rom.bytes[address as uint],
            0x8000..0x9FFF => self.gpu.read_byte(address),
            0xA000..0xBFFF => {
                print!("External RAM not implemented!");
                0x00
            },
            0xC000..0xDFFF => self.ram[address as uint - 0xC000],
            0xE000..0xFDFF => self.ram[address as uint - 0xE000],
            0xFE00..0xFE9F => self.gpu.read_byte(address),
            0xFEA0..0xFEFF => fail!("0xFEA0..0xFEFF segment is no usable"),
            0xFF00..0xFF7F => {
                match address {
                    0xFF04..0xFF07 => {
                        self.timer.read_byte(address)
                    },
                    0xFF0F => {
                        self.if_
                    },
                    0xFF40..0xFF4B => {
                        self.gpu.read_byte(address)
                    },
                    _ => {
                        print!("Implement I/O ports stuff... ");
                        0x00
                    }
                }
            },
            0xFF80..0xFFFE => self.hram[address as uint - 0xFF80],
            0xFFFF => self.ie,
            _ => unreachable!()
        }
    }

    pub fn write_byte(&mut self, address: u16, value: u8) {
        match address {
            0x0000..0x7FFF => {
                fail!("Address not writable in MBC0: {:#06x}", address);
            },
            0x8000..0x9FFF => {
                self.gpu.write_byte(address, value);
            },
            0xA000..0xBFFF => {
                print!("External RAM not implemented!");
            }
            0xC000..0xDFFF => {
                self.ram[address as uint - 0xC000] = value;
            },
            0xE000..0xFDFF => {
                self.ram[address as uint - 0xE000] = value;
            },
            0xFE00..0xFE9F => {
                self.gpu.write_byte(address, value);
            },
            0xFEA0..0xFEFF => fail!("0xFEA0..0xFEFF segment is no usable"),
            0xFF00..0xFF7F => {
                match address {
                    0xFF01 => {
                        println!("SB: {:c}", value as char);
                    },
                    0xFF04..0xFF07 => {
                        self.timer.write_byte(address, value);
                    },
                    0xFF0F => {
                        self.if_ = value;
                    },
                    0xFF40..0xFF4B => {
                        self.gpu.write_byte(address, value);
                    },
                    _ => print!("Implement I/O ports stuff... ")
                }
            },
            0xFF80..0xFFFE => {
                self.hram[address as uint - 0xFF80] = value;
            },
            0xFFFF => {
                self.ie = value;
            },
            _ => unreachable!()
        }
    }

    pub fn read_word(&self, address: u16) -> u16 {
        self.read_byte(address) as u16 |
            self.read_byte(address + 1) as u16 << 8
    }

    pub fn write_word(&mut self, address: u16, value: u16) {
        self.write_byte(address, (value & 0xFF) as u8);
        self.write_byte(address + 1, (value >> 8) as u8);
    }
}
<|endoftext|>


<commit_before>use std::ffi::{OsStr, OsString};
use std::io::ErrorKind::NotFound;

use semver::Version;
use serde_json::Value;

use client::HttpClient;
use error::{Error, ErrorKind, Result};
use fs::Fs;
use os::OperatingSystem;
use process::exec_command;
use tags::Tags;
use util::{parse_major_minor_version, select_newer_version};

const MONGODB_GIT_TAGS_URL: &str = "https://api.github.com/repos/mongodb/mongo/tags?per_page=100";

pub struct Monger {
    client: HttpClient,
    fs: Fs,
}

impl Monger {
    pub fn new() -> Result<Self> {
        Ok(Self {
            client: HttpClient::new()?,
            fs: Fs::new().build()?,
        })
    }

    pub fn download_mongodb_version(&self, version_str: &str) -> Result<()> {
        let version = if version_str == "latest" {
            self.find_latest_mongodb_version()?
        } else if let Some((major, minor)) = parse_major_minor_version(version_str) {
            self.find_latest_matching_version(major, minor)?
        } else {
            Version::parse(version_str).map_err(|_| {
                let err: Error = ErrorKind::VersionNotFound(version_str.to_string()).into();
                err
            })?
        };

        let version_str = format!("{}", version);

        if self.fs.version_exists(&version_str) {
            return Ok(());
        }

        let url = OperatingSystem::get()?.download_url(&version);
        let file = url.filename();
        let dir = url.dirname();
        let url: String = url.into();
        let data = self.client.download_file(&url, &version_str)?;

        self.fs.write_mongodb_download(
            &file,
            &dir,
            &data[..],
            &version_str,
        )?;

        Ok(())
    }

    fn find_latest_matching_version(&self, major: u64, minor: u64) -> Result<Version> {
        let mut page = Some(MONGODB_GIT_TAGS_URL.to_string());

        while let Some(current_page) = page {
            let response = self.client.get(&current_page)?;
            let tags = Tags::from_response(response)?;

            {
                let array = match *tags.get_value() {
                    Value::Array(ref values) => values,
                    _ => bail!(ErrorKind::InvalidJson(MONGODB_GIT_TAGS_URL.to_string())),
                };

                for value in array {
                    let name = match value.get("name") {
                        Some(&Value::String(ref s)) => s,
                        _ => continue,
                    };

                    if !name.starts_with('r') {
                        continue;
                    }

                    let version = match Version::parse(&name[1..]) {
                        Ok(v) => v,
                        Err(_) => continue,
                    };

                    // Skip release candidates.
                    if !version.pre.is_empty() || !version.build.is_empty() {
                        continue;
                    }

                    if version.major == major && version.minor == minor {
                        return Ok(version);
                    }
                }
            }

            page = tags.next_page_url();
        }

        bail!(ErrorKind::VersionNotFound(format!("{}.{}", major, minor)))
    }

    fn find_latest_mongodb_version(&self) -> Result<Version> {
        let mut page = Some(MONGODB_GIT_TAGS_URL.to_string());
        let mut newest_stable = None;
        let mut newest_dev = None;

        while let Some(current_page) = page {
            let response = self.client.get(&current_page)?;
            let tags = Tags::from_response(response)?;

            {
                let array = match *tags.get_value() {
                    Value::Array(ref values) => values,
                    _ => bail!(ErrorKind::InvalidJson(MONGODB_GIT_TAGS_URL.to_string())),
                };

                for value in array {
                    let name = match value.get("name") {
                        Some(&Value::String(ref s)) => s,
                        _ => continue,
                    };

                    if !name.starts_with('r') {
                        continue;
                    }

                    let version = match Version::parse(&name[1..]) {
                        Ok(v) => v,
                        Err(_) => continue,
                    };

                    // Skip release candidates.
                    if !version.pre.is_empty() || !version.build.is_empty() {
                        continue;
                    }

                    if version.minor % 2 == 0 {
                        newest_stable = Some(select_newer_version(newest_stable, version));
                    } else if version.minor % 2 == 1 && newest_dev.is_none() {
                        newest_dev = Some(version);
                    }

                    newest_stable = match newest_stable {
                        Some(stable_version) => {
                            if let Some(ref dev_version) = newest_dev {
                                // Since there will only be one dev version in development at a
                                // given time, the newest stable version will never be older than
                                // one minor version less than the most recent dev version.
                                if dev_version.major == stable_version.major &&
                                    dev_version.minor <= stable_version.minor + 1
                                {
                                    return Ok(stable_version);
                                }
                            }

                            Some(stable_version)
                        }
                        None => None,
                    };
                }
            }

            page = tags.next_page_url();
        }

        bail!(ErrorKind::InvalidJson(MONGODB_GIT_TAGS_URL.to_string()))
    }

    pub fn delete_mongodb_version(&self, version: &str) -> Result<()> {
        if self.fs.delete_mongodb_version(version)? {
            println!("Deleted version {}", version);
        }

        Ok(())
    }

    pub fn list_versions(&self) -> Result<Vec<OsString>> {
        self.fs.list_versions()
    }

    pub fn prune(&self) -> Result<()> {
        self.fs.prune()
    }

    pub fn start_mongod<I>(&self, args: I, version: &str) -> Result<()>
    where
        I: Iterator<Item = OsString>,
    {
        if version == "system" {
            let db_dir = self.fs.create_or_get_db_dir("system")?;

            return self.system_exec(
                "mongod",
                args.chain(vec!["--dbpath".into(), db_dir.into_os_string()]),
            );
        }

        let version = self.fs.get_newest_matching_version(version)?;

        let db_dir = self.fs.create_or_get_db_dir(&version)?;
        self.exec(
            "mongod",
            args.chain(vec!["--dbpath".into(), db_dir.into_os_string()]),
            &version,
        )
    }

    fn system_exec<I, S>(&self, binary_name: &str, args: I) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        exec_command::<_, _, &str>(binary_name, args, None)
    }

    pub fn exec<I, S>(&self, binary_name: &str, args: I, version: &str) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        if version == "system" {
            return self.system_exec(binary_name, args);
        }

        let version = self.fs.get_newest_matching_version(version)?;

        match self.fs.exec(binary_name, args, &version) {
            Err(Error(ErrorKind::Io(ref io_err), _)) if io_err.kind() == NotFound => {
                bail!(ErrorKind::BinaryNotFound(
                    binary_name.to_string(),
                    version,
                ))
            }
            other => other,
        }
    }
}
<commit_msg>rustfmt fixes<commit_after>use std::ffi::{OsStr, OsString};
use std::io::ErrorKind::NotFound;

use semver::Version;
use serde_json::Value;

use client::HttpClient;
use error::{Error, ErrorKind, Result};
use fs::Fs;
use os::OperatingSystem;
use process::exec_command;
use tags::Tags;
use util::{parse_major_minor_version, select_newer_version};

const MONGODB_GIT_TAGS_URL: &str = "https://api.github.com/repos/mongodb/mongo/tags?per_page=100";

pub struct Monger {
    client: HttpClient,
    fs: Fs,
}

impl Monger {
    pub fn new() -> Result<Self> {
        Ok(Self {
            client: HttpClient::new()?,
            fs: Fs::new().build()?,
        })
    }

    pub fn download_mongodb_version(&self, version_str: &str) -> Result<()> {
        let version = if version_str == "latest" {
            self.find_latest_mongodb_version()?
        } else if let Some((major, minor)) = parse_major_minor_version(version_str) {
            self.find_latest_matching_version(major, minor)?
        } else {
            Version::parse(version_str).map_err(|_| {
                let err: Error = ErrorKind::VersionNotFound(version_str.to_string()).into();
                err
            })?
        };

        let version_str = format!("{}", version);

        if self.fs.version_exists(&version_str) {
            return Ok(());
        }

        let url = OperatingSystem::get()?.download_url(&version);
        let file = url.filename();
        let dir = url.dirname();
        let url: String = url.into();
        let data = self.client.download_file(&url, &version_str)?;

        self.fs.write_mongodb_download(
            &file,
            &dir,
            &data[..],
            &version_str,
        )?;

        Ok(())
    }

    fn find_latest_matching_version(&self, major: u64, minor: u64) -> Result<Version> {
        let mut page = Some(MONGODB_GIT_TAGS_URL.to_string());

        while let Some(current_page) = page {
            let response = self.client.get(&current_page)?;
            let tags = Tags::from_response(response)?;

            {
                let array = match *tags.get_value() {
                    Value::Array(ref values) => values,
                    _ => bail!(ErrorKind::InvalidJson(MONGODB_GIT_TAGS_URL.to_string())),
                };

                for value in array {
                    let name = match value.get("name") {
                        Some(&Value::String(ref s)) => s,
                        _ => continue,
                    };

                    if !name.starts_with('r') {
                        continue;
                    }

                    let version = match Version::parse(&name[1..]) {
                        Ok(v) => v,
                        Err(_) => continue,
                    };

                    // Skip release candidates.
                    if !version.pre.is_empty() || !version.build.is_empty() {
                        continue;
                    }

                    if version.major == major && version.minor == minor {
                        return Ok(version);
                    }
                }
            }

            page = tags.next_page_url();
        }

        bail!(ErrorKind::VersionNotFound(format!("{}.{}", major, minor)))
    }

    fn find_latest_mongodb_version(&self) -> Result<Version> {
        let mut page = Some(MONGODB_GIT_TAGS_URL.to_string());
        let mut newest_stable = None;
        let mut newest_dev = None;

        while let Some(current_page) = page {
            let response = self.client.get(&current_page)?;
            let tags = Tags::from_response(response)?;

            {
                let array = match *tags.get_value() {
                    Value::Array(ref values) => values,
                    _ => bail!(ErrorKind::InvalidJson(MONGODB_GIT_TAGS_URL.to_string())),
                };

                for value in array {
                    let name = match value.get("name") {
                        Some(&Value::String(ref s)) => s,
                        _ => continue,
                    };

                    if !name.starts_with('r') {
                        continue;
                    }

                    let version = match Version::parse(&name[1..]) {
                        Ok(v) => v,
                        Err(_) => continue,
                    };

                    // Skip release candidates.
                    if !version.pre.is_empty() || !version.build.is_empty() {
                        continue;
                    }

                    if version.minor % 2 == 0 {
                        newest_stable = Some(select_newer_version(newest_stable, version));
                    } else if version.minor % 2 == 1 && newest_dev.is_none() {
                        newest_dev = Some(version);
                    }

                    newest_stable = match newest_stable {
                        Some(stable_version) => {
                            if let Some(ref dev_version) = newest_dev {
                                // Since there will only be one dev version in development at a
                                // given time, the newest stable version will never be older than
                                // one minor version less than the most recent dev version.
                                if dev_version.major == stable_version.major &&
                                    dev_version.minor <= stable_version.minor + 1
                                {
                                    return Ok(stable_version);
                                }
                            }

                            Some(stable_version)
                        }
                        None => None,
                    };
                }
            }

            page = tags.next_page_url();
        }

        bail!(ErrorKind::InvalidJson(MONGODB_GIT_TAGS_URL.to_string()))
    }

    pub fn delete_mongodb_version(&self, version: &str) -> Result<()> {
        if self.fs.delete_mongodb_version(version)? {
            println!("Deleted version {}", version);
        }

        Ok(())
    }

    pub fn list_versions(&self) -> Result<Vec<OsString>> {
        self.fs.list_versions()
    }

    pub fn prune(&self) -> Result<()> {
        self.fs.prune()
    }

    pub fn start_mongod<I>(&self, args: I, version: &str) -> Result<()>
    where
        I: Iterator<Item = OsString>,
    {
        if version == "system" {
            let db_dir = self.fs.create_or_get_db_dir("system")?;

            return self.system_exec(
                "mongod",
                args.chain(vec!["--dbpath".into(), db_dir.into_os_string()]),
            );
        }

        let version = self.fs.get_newest_matching_version(version)?;

        let db_dir = self.fs.create_or_get_db_dir(&version)?;
        self.exec(
            "mongod",
            args.chain(vec!["--dbpath".into(), db_dir.into_os_string()]),
            &version,
        )
    }

    fn system_exec<I, S>(&self, binary_name: &str, args: I) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        exec_command::<_, _, &str>(binary_name, args, None)
    }

    pub fn exec<I, S>(&self, binary_name: &str, args: I, version: &str) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        if version == "system" {
            return self.system_exec(binary_name, args);
        }

        let version = self.fs.get_newest_matching_version(version)?;

        match self.fs.exec(binary_name, args, &version) {
            Err(Error(ErrorKind::Io(ref io_err), _)) if io_err.kind() == NotFound => {
                bail!(ErrorKind::BinaryNotFound(binary_name.to_string(), version))
            }
            other => other,
        }
    }
}
<|endoftext|>


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

use mio::tcp::*;
use mio::deprecated::TryRead;
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};

use constants::*;
use job::*;
use worker::Worker;
use queues::QueueHolder;

pub struct PacketType {
    pub name: &'static str,
    pub ptype: u32,
    pub nargs: i8,
}

#[derive(PartialEq)]
pub enum PacketMagic {
    UNKNOWN,
    REQ,
    RES,
    TEXT,
}

pub struct Packet {
    pub magic: PacketMagic,
    pub ptype: u32,
    pub psize: u32,
    pub data: Box<Vec<u8>>,
    _field_byte_count: usize,
    _field_count: i8,
}

const READ_BUFFER_INIT_CAPACITY: usize = 2048;

impl Iterator for Packet {
    type Item = (usize, usize);
    fn next(&mut self) -> Option<(usize, usize)> {
        let nargs = PTYPES[self.ptype as usize].nargs;
        if self._field_count > nargs {
            return None
        }
        self._field_count += 1;
        debug!("DEBUG: returning field #{}", self._field_count);
        if self._field_count == nargs {
            return Some((self._field_byte_count, self.data.len()))
        };
        let start = self._field_byte_count;
        for byte in &self.data[start..] {
            self._field_byte_count += 1;
            if *byte == '\0' as u8 {
                self._field_byte_count -= 1; // Drop the null
                break
            }
        };
        Some((start, self._field_byte_count))
    }
}

pub struct ParseError {}

#[derive(Debug)]
pub struct EofError {}

pub type Result<T> = result::Result<T, ParseError>;

impl Packet {
    pub fn new() -> Packet {
        Packet {
            magic: PacketMagic::UNKNOWN,
            ptype: 0,
            psize: 0,
            data: Box::new(Vec::with_capacity(READ_BUFFER_INIT_CAPACITY)),
            _field_byte_count: 0,
            _field_count: 0,
        }
    }

    pub fn new_res(ptype: u32, data: Box<Vec<u8>>) -> Packet {
        Packet {
            magic: PacketMagic::RES,
            ptype: ptype,
            psize: data.len() as u32,
            data: data,
            _field_byte_count: 0,
            _field_count: 0,
        }
    }

    pub fn from_socket(&mut self,
                       socket: &mut TcpStream,
                       worker: &mut Worker,
                       queues: QueueHolder) -> result::Result<Option<Packet>, EofError> {
        let mut magic_buf = [0; 4];
        let mut typ_buf = [0; 4];
        let mut size_buf = [0; 4];
        let psize: u32 = 0;
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut magic_buf) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("No more to read");
                    break
                },
                Ok(Some(0)) => {
                    debug!("Eof (magic)");
                    return Err(EofError {})
                }
                Ok(Some(len)) => {
                    tot_read += len;
                    if tot_read == 4 {
                        // Is this a req/res
                        match magic_buf {
                            REQ => {
                                self.magic = PacketMagic::REQ;
                            },
                            RES => {
                                self.magic = PacketMagic::RES;
                            },
                            // TEXT/ADMIN protocol
                            _ => {
                                debug!("Possible admin protocol usage");
                                self.magic = PacketMagic::TEXT;
                                return Ok(None)
                            },
                        }
                    };
                    break
                },
            }
        }
        // Now get the type
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut typ_buf) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("No more to read (type)");
                    break
                },
                Ok(Some(0)) => {
                    debug!("Eof (typ)");
                    return Err(EofError {})
                }
                Ok(Some(len)) => {
                    tot_read += len;
                    if tot_read == 4 {
                        // validate typ
                        self.ptype = BigEndian::read_u32(&typ_buf);
                        debug!("We got a {}", PTYPES[self.ptype as usize].name);
                    };
                    break
                }
            }
        }
        // Now the length
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut size_buf) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("Need size!");
                    break
                },
                Ok(Some(0)) => {
                    debug!("Eof (size)");
                    return Err(EofError {})
                }
                Ok(Some(len)) => {
                    tot_read += len;
                    if tot_read == 4 {
                        self.psize = BigEndian::read_u32(&size_buf);
                        debug!("Data section is {} bytes", self.psize);
                    };
                    break
                }
            }
        }
        self.data.resize(self.psize as usize, 0);
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut self.data) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("done reading data, tot_read = {}", tot_read);
                    break
                },
                Ok(Some(len)) => {
                    tot_read += len;
                    debug!("got {} out of {} bytes of data", len, tot_read);
                    if tot_read >= psize as usize {
                        debug!("got all data");
                        {
                            match self.process(queues.clone(), worker) {
                                Err(_) => {
                                    error!("Packet parsing error");
                                    return Err(EofError {})
                                },
                                Ok(pr) => {
                                    return Ok(pr)
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }
        Ok(None)
    }

    pub fn process(&mut self, queues: QueueHolder, worker: &mut Worker) -> Result<Option<Packet>> {
        let p = match self.ptype {
            SUBMIT_JOB => self.handle_submit_job(queues)?,
            CAN_DO => self.handle_can_do(worker)?,
            CANT_DO => self.handle_cant_do(worker)?,
            GRAB_JOB_ALL => self.handle_grab_job_all(queues, worker)?,
            _ => {
                debug!("Unimplemented: {:?} processing packet", self);
                None
            },
        };
        Ok(p)
    }

    fn next_field(&mut self) -> Result<Vec<u8>> {
        let (start, finish) = match self.next() {
            None => return Err(ParseError{}),
            Some((start, finish)) => (start, finish),
        };
        let mut r = Vec::with_capacity(finish - start);
        let new_size = r.capacity();
        r.resize(new_size, 0);
        r.clone_from_slice(&self.data[start..finish]);
        Ok(r)
    }

    fn handle_can_do(&mut self, worker: &mut Worker) -> Result<Option<Packet>> {
        let fname = self.next_field()?;
        debug!("CAN_DO fname = {:?}", fname);
        worker.functions.insert(fname);
        Ok(None)
    }

    fn handle_cant_do(&mut self, worker: &mut Worker) -> Result<Option<Packet>> {
        let fname = self.next_field()?;
        worker.functions.remove(&fname);
        Ok(None)
    }

    fn handle_grab_job_all(&mut self, mut queues: QueueHolder, worker: &mut Worker) -> Result<Option<Packet>> {
        if queues.get_job(worker) {
            match worker.job {
                Some(ref j) => {
                    let mut data: Box<Vec<u8>> = Box::new(Vec::with_capacity(4 + j.handle.len() + j.fname.len() + j.unique.len() + j.data.len()));
                    data.extend(&j.handle);
                    data.push(b'\0');
                    data.extend(&j.fname);
                    data.push(b'\0');
                    data.extend(&j.unique);
                    data.push(b'\0');
                    // reducer not implemented
                    data.push(b'\0');
                    data.extend(&j.data);
                    return Ok(Some(Packet::new_res(JOB_ASSIGN_ALL, data)))
                },
                None => {},
            }
        };
        Ok(Some(Packet::new_res(NO_JOB, Box::new(Vec::new()))))
    }

    fn handle_submit_job(&mut self, mut queues: QueueHolder) -> Result<Option<Packet>> {
        let fname = self.next_field()?;
        debug!("fname = {:?}", &fname);
        let unique = self.next_field()?;
        let data = self.next_field()?;
        let j = Job::new(fname, unique, data);
        info!("Created job {:?}", j);
        let p = Packet::new_res(JOB_CREATED, Box::new(j.handle.clone()));
        queues.add_job(j);
        Ok(Some(p))
    }

    pub fn to_byteslice(&self) -> Box<[u8]> {
        let len = 12 + self.psize;
        let mut buf = Vec::with_capacity(len as usize) as Vec<u8>;
        let magic = match self.magic {
            PacketMagic::UNKNOWN => panic!("Unknown packet magic cannot be sent"),
            PacketMagic::REQ => REQ,
            PacketMagic::RES => RES,
            PacketMagic::TEXT => {
                return self.data.clone().into_boxed_slice();
            },
        };
        buf.extend(magic.iter());
        buf.write_u32::<BigEndian>(self.ptype).unwrap();
        buf.write_u32::<BigEndian>(self.psize).unwrap();
        buf.extend(self.data.iter());
        buf.into_boxed_slice()
    }
}

impl fmt::Debug for Packet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Packet {{ magic: {:?}, ptype: {}, size: {} }}",
               match self.magic {
                   PacketMagic::REQ => "REQ",
                   PacketMagic::RES => "RES",
                   PacketMagic::TEXT => "TEXT",
                   _ => "UNKNOWN",
               },
               PTYPES[self.ptype as usize].name,
               self.psize)
    }
}

pub static PTYPES: [PacketType; 43] = [
    PacketType { name: "__UNUSED__", ptype: 0, nargs: -1 },
    PacketType { name: "CAN_DO", ptype: 1, nargs: 0 },
    PacketType { name: "CANT_DO", ptype: 2, nargs: 0 },
    PacketType { name: "RESET_ABILITIES", ptype: 3, nargs: -1 },
    PacketType { name: "PRE_SLEEP", ptype: 4, nargs: -1 },
    PacketType { name: "__UNUSED__", ptype: 5, nargs: -1 },
    PacketType { name: "NOOP", ptype: 6, nargs: -1 },
    PacketType { name: "SUBMIT_JOB", ptype: 7, nargs: 2 },
    PacketType { name: "JOB_CREATED", ptype: 8, nargs: 0 },
    PacketType { name: "GRAB_JOB", ptype: 9, nargs: -1 },
    PacketType { name: "NO_JOB", ptype: 10, nargs: -1 },
    PacketType { name: "JOB_ASSIGN", ptype: 11, nargs: 2 },
    PacketType { name: "WORK_STATUS", ptype: 12, nargs: 2 },
    PacketType { name: "WORK_COMPLETE", ptype: 13, nargs: 1 },
    PacketType { name: "WORK_FAIL", ptype: 14, nargs: 0 },
    PacketType { name: "GET_STATUS", ptype: 15, nargs: 0 },
    PacketType { name: "ECHO_REQ", ptype: 16, nargs: 0 },
    PacketType { name: "ECHO_RES", ptype: 17, nargs: 1 },
    PacketType { name: "SUBMIT_JOB_BG", ptype: 18, nargs: 2 },
    PacketType { name: "ERROR", ptype: 19, nargs: 1 },
    PacketType { name: "STATUS_RES", ptype: 20, nargs: 4 },
    PacketType { name: "SUBMIT_JOB_HIGH", ptype: 21, nargs: 2 },
    PacketType { name: "SET_CLIENT_ID", ptype: 22, nargs: 0 },
    PacketType { name: "CAN_DO_TIMEOUT", ptype: 23, nargs: 1 },
    PacketType { name: "ALL_YOURS", ptype: 24, nargs: -1 },
    PacketType { name: "WORK_EXCEPTION", ptype: 25, nargs: 1 },
    PacketType { name: "OPTION_REQ", ptype: 26, nargs: 0 },
    PacketType { name: "OPTION_RES", ptype: 27, nargs: 0 },
    PacketType { name: "WORK_DATA", ptype: 28, nargs: 1 },
    PacketType { name: "WORK_WARNING", ptype: 29, nargs: 1 },
    PacketType { name: "GRAB_JOB_UNIQ", ptype: 30, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_UNIQ", ptype: 31, nargs: 3 },
    PacketType { name: "SUBMIT_JOB_HIGH_BG", ptype: 32, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW", ptype: 33, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW_BG", ptype: 34, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_SCHED", ptype: 35, nargs: 7 },
    PacketType { name: "SUBMIT_JOB_EPOCH", ptype: 36, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB", ptype: 37, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB_BACKGROUND", ptype: 38, nargs: 3 },
    PacketType { name: "GRAB_JOB_ALL", ptype: 39, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_ALL", ptype: 40, nargs: 4 },
    PacketType { name: "GET_STATUS_UNIQUE", ptype: 41, nargs: 0 },
    PacketType { name: "STATUS_RES_UNIQUE", ptype: 42, nargs: 5 },
];
<commit_msg>Fixing packet field iteration<commit_after>use std::fmt;
use std::result;
use std::str;

use mio::tcp::*;
use mio::deprecated::TryRead;
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};

use constants::*;
use job::*;
use worker::Worker;
use queues::QueueHolder;

#[test]
fn next() {
    let mut data = Box::new(Vec::new());
    data.extend_from_slice(b"funcname\0data");
    let mut p = Packet::new_res(WORK_COMPLETE, data);
    let f = p.next().unwrap();
    assert_eq!(f, (0, 7));
    let f2 = p.next().unwrap();
    assert_eq!(f2, (9, 12));
}

#[test]
fn next_field() {
    let mut data = Box::new(Vec::new());
    data.extend_from_slice(b"funcname\0data\0\x7f");
    let mut p = Packet::new_res(WORK_COMPLETE, data);
    let f = p.next_field().unwrap().into_boxed_slice();
    let f = str::from_utf8(&f).unwrap();
    assert_eq!(f, "funcname");
    let f2 = p.next_field().unwrap().into_boxed_slice();
    assert_eq!(*f2, [b'd', b'a', b't', b'a', b'\0', b'\x7f' ]);
}

pub struct PacketType {
    pub name: &'static str,
    pub ptype: u32,
    pub nargs: i8,
}

#[derive(PartialEq)]
pub enum PacketMagic {
    UNKNOWN,
    REQ,
    RES,
    TEXT,
}

pub struct Packet {
    pub magic: PacketMagic,
    pub ptype: u32,
    pub psize: u32,
    pub data: Box<Vec<u8>>,
    _field_byte_count: usize,
    _field_count: i8,
}

const READ_BUFFER_INIT_CAPACITY: usize = 2048;

impl Iterator for Packet {
    type Item = (usize, usize);
    fn next(&mut self) -> Option<(usize, usize)> {
        let nargs = PTYPES[self.ptype as usize].nargs;
        if self._field_count > nargs {
            return None
        }
        self._field_count += 1;
        debug!("DEBUG: returning field #{}", self._field_count);
        if self._field_count > nargs {
            return Some((self._field_byte_count, self.data.len() - 1))
        };
        let start = self._field_byte_count;
        for byte in &self.data[start..] {
            if *byte == '\0' as u8 {
                self._field_byte_count += 1; // Skip the null
                break
            }
            self._field_byte_count += 1;
        };
        Some((start, self._field_byte_count - 2)) // And don't return it
    }
}

#[derive(Debug)]
pub struct ParseError {}

#[derive(Debug)]
pub struct EofError {}

pub type Result<T> = result::Result<T, ParseError>;

impl Packet {
    pub fn new() -> Packet {
        Packet {
            magic: PacketMagic::UNKNOWN,
            ptype: 0,
            psize: 0,
            data: Box::new(Vec::with_capacity(READ_BUFFER_INIT_CAPACITY)),
            _field_byte_count: 0,
            _field_count: 0,
        }
    }

    pub fn new_res(ptype: u32, data: Box<Vec<u8>>) -> Packet {
        Packet {
            magic: PacketMagic::RES,
            ptype: ptype,
            psize: data.len() as u32,
            data: data,
            _field_byte_count: 0,
            _field_count: 0,
        }
    }

    pub fn from_socket(&mut self,
                       socket: &mut TcpStream,
                       worker: &mut Worker,
                       queues: QueueHolder) -> result::Result<Option<Packet>, EofError> {
        let mut magic_buf = [0; 4];
        let mut typ_buf = [0; 4];
        let mut size_buf = [0; 4];
        let psize: u32 = 0;
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut magic_buf) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("No more to read");
                    break
                },
                Ok(Some(0)) => {
                    debug!("Eof (magic)");
                    return Err(EofError {})
                }
                Ok(Some(len)) => {
                    tot_read += len;
                    if tot_read == 4 {
                        // Is this a req/res
                        match magic_buf {
                            REQ => {
                                self.magic = PacketMagic::REQ;
                            },
                            RES => {
                                self.magic = PacketMagic::RES;
                            },
                            // TEXT/ADMIN protocol
                            _ => {
                                debug!("Possible admin protocol usage");
                                self.magic = PacketMagic::TEXT;
                                return Ok(None)
                            },
                        }
                    };
                    break
                },
            }
        }
        // Now get the type
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut typ_buf) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("No more to read (type)");
                    break
                },
                Ok(Some(0)) => {
                    debug!("Eof (typ)");
                    return Err(EofError {})
                }
                Ok(Some(len)) => {
                    tot_read += len;
                    if tot_read == 4 {
                        // validate typ
                        self.ptype = BigEndian::read_u32(&typ_buf);
                        debug!("We got a {}", PTYPES[self.ptype as usize].name);
                    };
                    break
                }
            }
        }
        // Now the length
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut size_buf) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("Need size!");
                    break
                },
                Ok(Some(0)) => {
                    debug!("Eof (size)");
                    return Err(EofError {})
                }
                Ok(Some(len)) => {
                    tot_read += len;
                    if tot_read == 4 {
                        self.psize = BigEndian::read_u32(&size_buf);
                        debug!("Data section is {} bytes", self.psize);
                    };
                    break
                }
            }
        }
        self.data.resize(self.psize as usize, 0);
        loop {
            let mut tot_read = 0;
            match socket.try_read(&mut self.data) {
                Err(e) => {
                    error!("Error while reading socket: {:?}", e);
                    return Err(EofError {})
                },
                Ok(None) => {
                    debug!("done reading data, tot_read = {}", tot_read);
                    break
                },
                Ok(Some(len)) => {
                    tot_read += len;
                    debug!("got {} out of {} bytes of data", len, tot_read);
                    if tot_read >= psize as usize {
                        debug!("got all data");
                        {
                            match self.process(queues.clone(), worker) {
                                Err(_) => {
                                    error!("Packet parsing error");
                                    return Err(EofError {})
                                },
                                Ok(pr) => {
                                    return Ok(pr)
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }
        Ok(None)
    }

    pub fn process(&mut self, queues: QueueHolder, worker: &mut Worker) -> Result<Option<Packet>> {
        let p = match self.ptype {
            SUBMIT_JOB => self.handle_submit_job(queues)?,
            CAN_DO => self.handle_can_do(worker)?,
            CANT_DO => self.handle_cant_do(worker)?,
            GRAB_JOB_ALL => self.handle_grab_job_all(queues, worker)?,
            WORK_COMPLETE => self.handle_work_complete(worker)?,
            _ => {
                debug!("Unimplemented: {:?} processing packet", self);
                None
            },
        };
        Ok(p)
    }

    fn next_field(&mut self) -> Result<Vec<u8>> {
        let (start, finish) = match self.next() {
            None => return Err(ParseError{}),
            Some((start, finish)) => (start, finish),
        };
        let mut r = Vec::with_capacity(finish - start + 1);
        let new_size = r.capacity();
        r.resize(new_size, 0);
        r.clone_from_slice(&self.data[start..finish + 1]);
        Ok(r)
    }

    fn handle_can_do(&mut self, worker: &mut Worker) -> Result<Option<Packet>> {
        let fname = self.next_field()?;
        debug!("CAN_DO fname = {:?}", fname);
        worker.functions.insert(fname);
        Ok(None)
    }

    fn handle_cant_do(&mut self, worker: &mut Worker) -> Result<Option<Packet>> {
        let fname = self.next_field()?;
        worker.functions.remove(&fname);
        Ok(None)
    }

    fn handle_grab_job_all(&mut self, mut queues: QueueHolder, worker: &mut Worker) -> Result<Option<Packet>> {
        if queues.get_job(worker) {
            match worker.job {
                Some(ref j) => {
                    let mut data: Box<Vec<u8>> = Box::new(Vec::with_capacity(4 + j.handle.len() + j.fname.len() + j.unique.len() + j.data.len()));
                    data.extend(&j.handle);
                    data.push(b'\0');
                    data.extend(&j.fname);
                    data.push(b'\0');
                    data.extend(&j.unique);
                    data.push(b'\0');
                    // reducer not implemented
                    data.push(b'\0');
                    data.extend(&j.data);
                    return Ok(Some(Packet::new_res(JOB_ASSIGN_ALL, data)))
                },
                None => {},
            }
        };
        Ok(Some(Packet::new_res(NO_JOB, Box::new(Vec::new()))))
    }

    fn handle_submit_job(&mut self, mut queues: QueueHolder) -> Result<Option<Packet>> {
        let fname = self.next_field()?;
        debug!("fname = {:?}", &fname);
        let unique = self.next_field()?;
        let data = self.next_field()?;
        let j = Job::new(fname, unique, data);
        info!("Created job {:?}", j);
        let p = Packet::new_res(JOB_CREATED, Box::new(j.handle.clone()));
        queues.add_job(j);
        Ok(Some(p))
    }

    fn handle_work_complete(&mut self, worker: &mut Worker) -> Result<Option<Packet>> {
        let handle = self.next_field()?;
        let data = self.next_field()?;
        info!("Job is complete {:?}", handle);
        match worker.job {
            Some(ref j) => {
                if j.handle != handle {
                    let msg = "WORK_COMPLETE received for inactive job handle";
                    let mut data: Box<Vec<u8>> = Box::new(Vec::with_capacity(msg.len() + 1));
                    data.push(b'\0');
                    data.extend_from_slice(msg.as_bytes());
                    return Ok(Some(Packet::new_res(ERROR, data)))
                }
            },
            None => {
                let msg = "WORK_COMPLETE received but no active jobs";
                let mut data: Box<Vec<u8>> = Box::new(Vec::with_capacity(msg.len() + 1));
                data.push(b'\0');
                data.extend_from_slice(msg.as_bytes());
                return Ok(Some(Packet::new_res(ERROR, data)))
            }
        }
        // TODO: send packet to _client_ if present
        worker.job = None;
        Ok(None)
    }

    pub fn to_byteslice(&self) -> Box<[u8]> {
        let len = 12 + self.psize;
        let mut buf = Vec::with_capacity(len as usize) as Vec<u8>;
        let magic = match self.magic {
            PacketMagic::UNKNOWN => panic!("Unknown packet magic cannot be sent"),
            PacketMagic::REQ => REQ,
            PacketMagic::RES => RES,
            PacketMagic::TEXT => {
                return self.data.clone().into_boxed_slice();
            },
        };
        buf.extend(magic.iter());
        buf.write_u32::<BigEndian>(self.ptype).unwrap();
        buf.write_u32::<BigEndian>(self.psize).unwrap();
        buf.extend(self.data.iter());
        buf.into_boxed_slice()
    }
}

impl fmt::Debug for Packet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Packet {{ magic: {:?}, ptype: {}, size: {} }}",
               match self.magic {
                   PacketMagic::REQ => "REQ",
                   PacketMagic::RES => "RES",
                   PacketMagic::TEXT => "TEXT",
                   _ => "UNKNOWN",
               },
               PTYPES[self.ptype as usize].name,
               self.psize)
    }
}

pub static PTYPES: [PacketType; 43] = [
    PacketType { name: "__UNUSED__", ptype: 0, nargs: -1 },
    PacketType { name: "CAN_DO", ptype: 1, nargs: 0 },
    PacketType { name: "CANT_DO", ptype: 2, nargs: 0 },
    PacketType { name: "RESET_ABILITIES", ptype: 3, nargs: -1 },
    PacketType { name: "PRE_SLEEP", ptype: 4, nargs: -1 },
    PacketType { name: "__UNUSED__", ptype: 5, nargs: -1 },
    PacketType { name: "NOOP", ptype: 6, nargs: -1 },
    PacketType { name: "SUBMIT_JOB", ptype: 7, nargs: 2 },
    PacketType { name: "JOB_CREATED", ptype: 8, nargs: 0 },
    PacketType { name: "GRAB_JOB", ptype: 9, nargs: -1 },
    PacketType { name: "NO_JOB", ptype: 10, nargs: -1 },
    PacketType { name: "JOB_ASSIGN", ptype: 11, nargs: 2 },
    PacketType { name: "WORK_STATUS", ptype: 12, nargs: 2 },
    PacketType { name: "WORK_COMPLETE", ptype: 13, nargs: 1 },
    PacketType { name: "WORK_FAIL", ptype: 14, nargs: 0 },
    PacketType { name: "GET_STATUS", ptype: 15, nargs: 0 },
    PacketType { name: "ECHO_REQ", ptype: 16, nargs: 0 },
    PacketType { name: "ECHO_RES", ptype: 17, nargs: 1 },
    PacketType { name: "SUBMIT_JOB_BG", ptype: 18, nargs: 2 },
    PacketType { name: "ERROR", ptype: 19, nargs: 1 },
    PacketType { name: "STATUS_RES", ptype: 20, nargs: 4 },
    PacketType { name: "SUBMIT_JOB_HIGH", ptype: 21, nargs: 2 },
    PacketType { name: "SET_CLIENT_ID", ptype: 22, nargs: 0 },
    PacketType { name: "CAN_DO_TIMEOUT", ptype: 23, nargs: 1 },
    PacketType { name: "ALL_YOURS", ptype: 24, nargs: -1 },
    PacketType { name: "WORK_EXCEPTION", ptype: 25, nargs: 1 },
    PacketType { name: "OPTION_REQ", ptype: 26, nargs: 0 },
    PacketType { name: "OPTION_RES", ptype: 27, nargs: 0 },
    PacketType { name: "WORK_DATA", ptype: 28, nargs: 1 },
    PacketType { name: "WORK_WARNING", ptype: 29, nargs: 1 },
    PacketType { name: "GRAB_JOB_UNIQ", ptype: 30, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_UNIQ", ptype: 31, nargs: 3 },
    PacketType { name: "SUBMIT_JOB_HIGH_BG", ptype: 32, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW", ptype: 33, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW_BG", ptype: 34, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_SCHED", ptype: 35, nargs: 7 },
    PacketType { name: "SUBMIT_JOB_EPOCH", ptype: 36, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB", ptype: 37, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB_BACKGROUND", ptype: 38, nargs: 3 },
    PacketType { name: "GRAB_JOB_ALL", ptype: 39, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_ALL", ptype: 40, nargs: 4 },
    PacketType { name: "GET_STATUS_UNIQUE", ptype: 41, nargs: 0 },
    PacketType { name: "STATUS_RES_UNIQUE", ptype: 42, nargs: 5 },
];
<|endoftext|>