<commit_before>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use model::ShowReplyItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
    y: usize,
    replier_max_width: usize,
    time_max_width: usize
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
            y: 0,
            replier_max_width: 14,
            time_max_width: 5
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        self.y = 2;

        self.print_header(&format!("{} - {} [{}/{}]",
                                   item.title,
                                   title,
                                   item.page,
                                   item.max_page));
        self.print_body(&item);
    }

    fn print_separator_top(&mut self, reply: &ShowReplyItem) {
        if self.can_print() {
            let (replier_name, time) = make_separator_content(&reply);
            self.rustbox.print(0,
                               self.scrolledY(),
                               rustbox::RB_NORMAL,
                               Color::Green,
                               Color::Black,
                               &self.build_separator_top(&replier_name, &time));
        }
    }

    fn print_separator_bottom(&mut self) {
        if self.can_print() {
            self.rustbox.print(0,
                               self.scrolledY(),
                               rustbox::RB_NORMAL,
                               Color::Green,
                               Color::Black,
                               &self.build_separator_bottom());
        }
    }

    fn print_header(&mut self, text: &str) {
        let title_len = jks_len(text);
        let padding = (if self.rustbox.width() >= title_len {
            self.rustbox.width() - title_len
        } else {
            0
        }) / 2;

        let header_bottom = seq_str_gen(0, self.rustbox.width(), "─", "");

        clearline(&self.rustbox, self.rustbox.width(), 0, 0);
        self.rustbox.print(padding,
                           0,
                           rustbox::RB_BOLD,
                           Color::White,
                           Color::Black,
                           text);
        self.rustbox.print(0,
                           1,
                           rustbox::RB_BOLD,
                           Color::Yellow,
                           Color::Black,
                           &header_bottom);
    }

    pub fn print_body(&mut self, item: &ShowItem) {
        let width = self.body_width();
        let rows = self.body_height();
        let rustbox = self.rustbox;

        for (i, reply) in item.replies.iter().take(rows).enumerate() {

            self.print_reply(&reply.body, 0);

            self.print_separator_top(&reply);
            self.y += 1;

            self.print_separator_bottom();
            self.y += 1;
        }
    }

    fn print_reply(&mut self, vec: &Vec<NodeType>,
                   depth: usize)
                    {

       let rustbox = self.rustbox;

        let padding = seq_str_gen(0, depth, "├─", "");
        let mut line = String::new();
        let mut is_first = true;

        let vec_clean = clean_reply_body(vec);
        for (j, node) in vec_clean.iter().enumerate() {
            if self.can_print() {
                match node.clone() {
                    NodeType::Text(n) => {
                        if n.data != "" {
                            line = format!("{}{}", line, n.data);
                        }
                    }
                    NodeType::Image(n) => {
                        if n.data != "" {
                            line = format!("{}[img {}]", line, n.data);
                        }
                    }
                    NodeType::BlockQuote(n) => {
                        self.print_reply(&n.data, depth + 1);
                        is_first = false;
                    }
                    NodeType::Br(n) => {
                        if !line.is_empty() {
                            print_default(rustbox,
                                          0,
                                           self.scrolledY(),
                                          format!(" {}{}", padding, line));
                            line = String::new();
                            is_first = false;
                        }

                        // prevent first line empty
                        if !is_first {
                             self.y += 1;
                        }

                    }
                }
            }
        }

        if !line.is_empty() {
            // total_y = self.y + m + reursive_offset;
            print_default(rustbox,
                          0,
                           self.scrolledY(),
                          format!(" {}{}  ", padding, line));
            line = String::new();
             self.y += 1;
        }

    }

    fn build_separator_arguments(&mut self) -> (usize, usize, String) {
        let width = self.body_width();
        let rustbox = self.rustbox;

        let separator_width = if rustbox.width() >= 2 {
            rustbox.width() - 2
        } else {
            0
        };
        let separator_padding_width = if rustbox.width() > separator_width {
            rustbox.width() - separator_width
        } else {
            0
        } / 2;

        let separator_padding = seq_str_gen(0, separator_padding_width, " ", "");

        (separator_width, separator_padding_width, separator_padding)
    }

    fn build_separator_top(&mut self, replier_name: &str, time: &str) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_top(separator_width,
                           &separator_padding,
                           self.replier_max_width,
                           &replier_name,
                           self.time_max_width,
                           &time)
    }

    fn build_separator_bottom(&mut self) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_bottom(separator_width, &separator_padding)
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp < 10000 {
            self.scrollY = tmp + value;
            return true;
        }
        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }

    fn can_print(&self) -> bool {
        self.y > self.scrollY + 1
    }

    fn scrolledY(&self) -> usize {
        self.y - self.scrollY
    }
}

fn print_default(rustbox: &rustbox::RustBox, x: usize, y: usize, s: String) {
    rustbox.print(0, y, rustbox::RB_NORMAL, Color::White, Color::Black, &s);
}

fn make_separator_content(reply: &ShowReplyItem) -> (String, String) {
    let now = Local::now();

    let replier_name = reply.username.clone();

    let published_at = reply.published_at.clone();

    let published_at_dt = match Local.datetime_from_str(&published_at, "%d/%m/%Y %H:%M") {
        Ok(v) => v,
        Err(e) => now,
    };
    let time = published_at_format(&(now - published_at_dt));
    (replier_name, time)
}

fn clean_reply_body(vec: &Vec<NodeType>) -> Vec<NodeType>{
    // clean up lines (end)
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter()
                                              .rev()
                                              .take(4)
                                              .enumerate()
                                              .all(|(j, node)| match node.clone() {
                                                  NodeType::Br(n) => j == 1 || j == 2 || j == 3,
                                                  NodeType::Text(n) => j == 0 && n.data.is_empty(),
                                                  _ => false,
                                              });

        let vec_short_length = if vec_length > 4 && is_last4_empty {
            vec_length - 4
        } else {
            vec_length
        };

        vec.iter().take(vec_short_length)
    };

    // clean up lines (start)
    let vec3 = {
        let vec2_cloned = vec2.clone();
        let mut result: Vec<NodeType> = Vec::new();
        for (j, node) in vec2_cloned.enumerate() {
            let node2 = node.clone();
            let node3 = node.clone();
            match node2 {
                NodeType::Br(n) => {
                    if !result.is_empty() {
                        result.push(node3);
                    }
                }
                _ => result.push(node3),
            }
        }
        result.clone()
    };

    vec3
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = seq_str_gen(0, replier_name_left_spacing_width, "─", "");
    let replier_name_right_spacing = seq_str_gen(0, replier_name_right_spacing_width, "─", "");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = seq_str_gen(0, time_left_spacing_width, "─", "");
    let time_right_spacing = seq_str_gen(0, time_right_spacing_width, "─", "");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = seq_str_gen(0, separator_top_middle_width, " ", "");
    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = seq_str_gen(0, separator_bottom_middle_width, "─", "");

    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}

fn seq_str_gen(start: usize, end: usize, sym: &str, join_sym: &str) -> String {
    (start..end).map(|_| sym.clone()).collect::<Vec<_>>().join(&join_sym)
}
<commit_msg>show - refactor searator argumetns<commit_after>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use model::ShowReplyItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
    y: usize,
    replier_max_width: usize,
    time_max_width: usize
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
            y: 0,
            replier_max_width: 14,
            time_max_width: 5
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        self.y = 2;

        self.print_header(&format!("{} - {} [{}/{}]",
                                   item.title,
                                   title,
                                   item.page,
                                   item.max_page));
        self.print_body(&item);
    }

    fn print_separator_top(&mut self, reply: &ShowReplyItem) {
        if self.can_print() {
            let (replier_name, time) = make_separator_content(&reply);
            self.rustbox.print(0,
                               self.scrolledY(),
                               rustbox::RB_NORMAL,
                               Color::Green,
                               Color::Black,
                               &self.build_separator_top(&replier_name, &time));
        }
    }

    fn print_separator_bottom(&mut self) {
        if self.can_print() {
            self.rustbox.print(0,
                               self.scrolledY(),
                               rustbox::RB_NORMAL,
                               Color::Green,
                               Color::Black,
                               &self.build_separator_bottom());
        }
    }

    fn print_header(&mut self, text: &str) {
        let title_len = jks_len(text);
        let padding = (if self.rustbox.width() >= title_len {
            self.rustbox.width() - title_len
        } else {
            0
        }) / 2;

        let header_bottom = seq_str_gen(0, self.rustbox.width(), "─", "");

        clearline(&self.rustbox, self.rustbox.width(), 0, 0);
        self.rustbox.print(padding,
                           0,
                           rustbox::RB_BOLD,
                           Color::White,
                           Color::Black,
                           text);
        self.rustbox.print(0,
                           1,
                           rustbox::RB_BOLD,
                           Color::Yellow,
                           Color::Black,
                           &header_bottom);
    }

    pub fn print_body(&mut self, item: &ShowItem) {
        let width = self.body_width();
        let rows = self.body_height();
        let rustbox = self.rustbox;

        for (i, reply) in item.replies.iter().take(rows).enumerate() {

            self.print_reply(&reply.body, 0);

            self.print_separator_top(&reply);
            self.y += 1;

            self.print_separator_bottom();
            self.y += 1;
        }
    }

    fn print_reply(&mut self, vec: &Vec<NodeType>,
                   depth: usize)
                    {

       let rustbox = self.rustbox;

        let padding = seq_str_gen(0, depth, "├─", "");
        let mut line = String::new();
        let mut is_first = true;

        let vec_clean = clean_reply_body(vec);
        for (j, node) in vec_clean.iter().enumerate() {
            if self.can_print() {
                match node.clone() {
                    NodeType::Text(n) => {
                        if n.data != "" {
                            line = format!("{}{}", line, n.data);
                        }
                    }
                    NodeType::Image(n) => {
                        if n.data != "" {
                            line = format!("{}[img {}]", line, n.data);
                        }
                    }
                    NodeType::BlockQuote(n) => {
                        self.print_reply(&n.data, depth + 1);
                        is_first = false;
                    }
                    NodeType::Br(n) => {
                        if !line.is_empty() {
                            print_default(rustbox,
                                          0,
                                           self.scrolledY(),
                                          format!(" {}{}", padding, line));
                            line = String::new();
                            is_first = false;
                        }

                        // prevent first line empty
                        if !is_first {
                             self.y += 1;
                        }

                    }
                }
            }
        }

        if !line.is_empty() {
            // total_y = self.y + m + reursive_offset;
            print_default(rustbox,
                          0,
                           self.scrolledY(),
                          format!(" {}{}  ", padding, line));
            line = String::new();
             self.y += 1;
        }

    }

    fn build_separator_arguments(&mut self) -> (usize, usize, String) {
        let separator_width = self.body_width();
        let separator_padding_width = if  self.rustbox.width() > separator_width {
             self.rustbox.width() - separator_width
        } else {
            0
        } / 2;

        let separator_padding = seq_str_gen(0, separator_padding_width, " ", "");

        (separator_width, separator_padding_width, separator_padding)
    }

    fn build_separator_top(&mut self, replier_name: &str, time: &str) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_top(separator_width,
                           &separator_padding,
                           self.replier_max_width,
                           &replier_name,
                           self.time_max_width,
                           &time)
    }

    fn build_separator_bottom(&mut self) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_bottom(separator_width, &separator_padding)
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp < 10000 {
            self.scrollY = tmp + value;
            return true;
        }
        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }

    fn can_print(&self) -> bool {
        self.y > self.scrollY + 1
    }

    fn scrolledY(&self) -> usize {
        self.y - self.scrollY
    }
}

fn print_default(rustbox: &rustbox::RustBox, x: usize, y: usize, s: String) {
    rustbox.print(0, y, rustbox::RB_NORMAL, Color::White, Color::Black, &s);
}

fn make_separator_content(reply: &ShowReplyItem) -> (String, String) {
    let now = Local::now();

    let replier_name = reply.username.clone();

    let published_at = reply.published_at.clone();

    let published_at_dt = match Local.datetime_from_str(&published_at, "%d/%m/%Y %H:%M") {
        Ok(v) => v,
        Err(e) => now,
    };
    let time = published_at_format(&(now - published_at_dt));
    (replier_name, time)
}

fn clean_reply_body(vec: &Vec<NodeType>) -> Vec<NodeType>{
    // clean up lines (end)
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter()
                                              .rev()
                                              .take(4)
                                              .enumerate()
                                              .all(|(j, node)| match node.clone() {
                                                  NodeType::Br(n) => j == 1 || j == 2 || j == 3,
                                                  NodeType::Text(n) => j == 0 && n.data.is_empty(),
                                                  _ => false,
                                              });

        let vec_short_length = if vec_length > 4 && is_last4_empty {
            vec_length - 4
        } else {
            vec_length
        };

        vec.iter().take(vec_short_length)
    };

    // clean up lines (start)
    let vec3 = {
        let vec2_cloned = vec2.clone();
        let mut result: Vec<NodeType> = Vec::new();
        for (j, node) in vec2_cloned.enumerate() {
            let node2 = node.clone();
            let node3 = node.clone();
            match node2 {
                NodeType::Br(n) => {
                    if !result.is_empty() {
                        result.push(node3);
                    }
                }
                _ => result.push(node3),
            }
        }
        result.clone()
    };

    vec3
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = seq_str_gen(0, replier_name_left_spacing_width, "─", "");
    let replier_name_right_spacing = seq_str_gen(0, replier_name_right_spacing_width, "─", "");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = seq_str_gen(0, time_left_spacing_width, "─", "");
    let time_right_spacing = seq_str_gen(0, time_right_spacing_width, "─", "");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = seq_str_gen(0, separator_top_middle_width, " ", "");
    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = seq_str_gen(0, separator_bottom_middle_width, "─", "");

    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}

fn seq_str_gen(start: usize, end: usize, sym: &str, join_sym: &str) -> String {
    (start..end).map(|_| sym.clone()).collect::<Vec<_>>().join(&join_sym)
}
<|endoftext|>


<commit_before>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]

use std::collections::VecDeque;
use std::sync::Arc;
use std::env;

use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
use libc;

use self::x11::XConnection;
use self::x11::XError;
use self::x11::XNotSupported;
use self::x11::ffi::XVisualInfo;

mod dlopen;
pub mod wayland;
pub mod x11;

/// Environment variable that indicates the X11 backend should be used
/// even if Wayland is available. In this case XWayland will be used.
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_PREFER_UNIX_BACKEND";

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub visual_infos: Option<XVisualInfo>,
    pub screen_id: Option<i32>,
}

pub enum UnixBackend {
    X(Arc<XConnection>),
    Wayland(Arc<wayland::WaylandContext>),
    Error(Option<XNotSupported>, Option<String>),
}

lazy_static!(
    pub static ref UNIX_BACKEND: UnixBackend = {
        #[inline]
        fn x_backend() -> Result<UnixBackend, XNotSupported> {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => Ok(UnixBackend::X(Arc::new(x))),
                Err(e) => Err(e),
            }
        }
        #[inline]
        fn wayland_backend() -> Result<UnixBackend, ()> {
             wayland::WaylandContext::init()
                .map(|ctx| UnixBackend::Wayland(Arc::new(ctx)))
                .ok_or(())
        }
        match env::var(BACKEND_PREFERENCE_ENV_VAR) {
            Ok(s) => match s.as_str() {
                "x11" => x_backend().unwrap_or_else(|e| UnixBackend::Error(Some(e), None)),
                "wayland" => wayland_backend().unwrap_or_else(|_| {
                    UnixBackend::Error(None, Some("Wayland not available".into()))
                }),
                _ => panic!("Unknown environment variable value for {}, try one of `x11`,`wayland`",
                            BACKEND_PREFERENCE_ENV_VAR),
            },
            Err(_) => {
                // Try wayland, fallback to X11
                wayland_backend().unwrap_or_else(|_| {
                    x_backend().unwrap_or_else(|x_err| {
                        UnixBackend::Error(Some(x_err), Some("Wayland not available".into()))
                    })
                })
            },
        }
    };
);

pub enum Window2 {
    #[doc(hidden)]
    X(x11::Window2),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowId {
    #[doc(hidden)]
    X(x11::WindowId),
    #[doc(hidden)]
    Wayland(wayland::WindowId)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DeviceId {
    #[doc(hidden)]
    X(x11::DeviceId),
    #[doc(hidden)]
    Wayland(wayland::DeviceId)
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt)
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        UnixBackend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        UnixBackend::Error(..) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)),
        UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        UnixBackend::Error(..) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

impl Window2 {
    #[inline]
    pub fn new(events_loop: &EventsLoop,
               window: &::WindowAttributes,
               pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Self, CreationError>
    {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                if let EventsLoop::Wayland(ref evlp) = *events_loop {
                    wayland::Window::new(evlp, ctxt.clone(), window).map(Window2::Wayland)
                } else {
                    // It is not possible to instanciate an EventsLoop not matching its backend
                    unreachable!()
                }
            },

            UnixBackend::X(_) => {
                x11::Window2::new(events_loop, window, pl_attribs).map(Window2::X)
            },
            UnixBackend::Error(..) => {
                // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
                // thus this function cannot be called!
                unreachable!()
            }
        }
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        match self {
            &Window2::X(ref w) => WindowId::X(w.id()),
            &Window2::Wayland(ref w) => WindowId::Wayland(w.id())
        }
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window2::X(ref w) => w.set_title(title),
            &Window2::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window2::X(ref w) => w.show(),
            &Window2::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window2::X(ref w) => w.hide(),
            &Window2::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window2::X(ref w) => w.get_position(),
            &Window2::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window2::X(ref w) => w.set_position(x, y),
            &Window2::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_inner_size(),
            &Window2::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_outer_size(),
            &Window2::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window2::X(ref w) => w.set_inner_size(x, y),
            &Window2::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window2::X(ref w) => w.set_cursor(cursor),
            &Window2::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window2::X(ref w) => w.set_cursor_state(state),
            &Window2::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window2::X(ref w) => w.hidpi_factor(),
            &Window2::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window2::X(ref w) => w.set_cursor_position(x, y),
            &Window2::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_display(),
            &Window2::Wayland(ref w) => w.get_display().ptr() as *mut _
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_window(),
            &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let UnixBackend::X(ref x) = *UNIX_BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut libc::c_char, buff.capacity() as i32);
        let description = CStr::from_ptr(buff.as_mut_ptr() as *const libc::c_char).to_string_lossy();

        let error = XError {
            description: description.into_owned(),
            error_code: (*event).error_code,
            request_code: (*event).request_code,
            minor_code: (*event).minor_code,
        };

        *x.latest_error.lock().unwrap() = Some(error);
    }

    0
}

pub enum EventsLoop {
    #[doc(hidden)]
    Wayland(wayland::EventsLoop),
    #[doc(hidden)]
    X(x11::EventsLoop)
}

pub enum EventsLoopProxy {
    X(x11::EventsLoopProxy),
    Wayland(wayland::EventsLoopProxy),
}

impl EventsLoop {
    pub fn new() -> EventsLoop {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                EventsLoop::Wayland(wayland::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::X(ref ctxt) => {
                EventsLoop::X(x11::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::Error(..) => {
                panic!("Attempted to create an EventsLoop while no backend was available.")
            }
        }
    }

    pub fn create_proxy(&self) -> EventsLoopProxy {
        match *self {
            EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()),
            EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()),
        }
    }

    pub fn poll_events<F>(&mut self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback),
            EventsLoop::X(ref mut evlp) => evlp.poll_events(callback)
        }
    }

    pub fn run_forever<F>(&mut self, callback: F)
        where F: FnMut(::Event) -> ControlFlow
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.run_forever(callback),
            EventsLoop::X(ref mut evlp) => evlp.run_forever(callback)
        }
    }
}

impl EventsLoopProxy {
    pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
        match *self {
            EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(),
            EventsLoopProxy::X(ref proxy) => proxy.wakeup(),
        }
    }
}
<commit_msg>Rename unix backend env var<commit_after>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]

use std::collections::VecDeque;
use std::sync::Arc;
use std::env;

use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
use libc;

use self::x11::XConnection;
use self::x11::XError;
use self::x11::XNotSupported;
use self::x11::ffi::XVisualInfo;

mod dlopen;
pub mod wayland;
pub mod x11;

/// Environment variable that indicates a backend preference
/// `WINIT_UNIX_BACKEND=x11` : Will try to use an X11 backend
/// `WINIT_UNIX_BACKEND=wayland` : Will try to use a wayland backend
/// When used is selected backends will not fallback to one another
/// (Current default behaviour is wayland, fallback to X)
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND";

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub visual_infos: Option<XVisualInfo>,
    pub screen_id: Option<i32>,
}

pub enum UnixBackend {
    X(Arc<XConnection>),
    Wayland(Arc<wayland::WaylandContext>),
    Error(Option<XNotSupported>, Option<String>),
}

lazy_static!(
    pub static ref UNIX_BACKEND: UnixBackend = {
        #[inline]
        fn x_backend() -> Result<UnixBackend, XNotSupported> {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => Ok(UnixBackend::X(Arc::new(x))),
                Err(e) => Err(e),
            }
        }
        #[inline]
        fn wayland_backend() -> Result<UnixBackend, ()> {
             wayland::WaylandContext::init()
                .map(|ctx| UnixBackend::Wayland(Arc::new(ctx)))
                .ok_or(())
        }
        match env::var(BACKEND_PREFERENCE_ENV_VAR) {
            Ok(s) => match s.as_str() {
                "x11" => x_backend().unwrap_or_else(|e| UnixBackend::Error(Some(e), None)),
                "wayland" => wayland_backend().unwrap_or_else(|_| {
                    UnixBackend::Error(None, Some("Wayland not available".into()))
                }),
                _ => panic!("Unknown environment variable value for {}, try one of `x11`,`wayland`",
                            BACKEND_PREFERENCE_ENV_VAR),
            },
            Err(_) => {
                // Try wayland, fallback to X11
                wayland_backend().unwrap_or_else(|_| {
                    x_backend().unwrap_or_else(|x_err| {
                        UnixBackend::Error(Some(x_err), Some("Wayland not available".into()))
                    })
                })
            },
        }
    };
);

pub enum Window2 {
    #[doc(hidden)]
    X(x11::Window2),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowId {
    #[doc(hidden)]
    X(x11::WindowId),
    #[doc(hidden)]
    Wayland(wayland::WindowId)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DeviceId {
    #[doc(hidden)]
    X(x11::DeviceId),
    #[doc(hidden)]
    Wayland(wayland::DeviceId)
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt)
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        UnixBackend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        UnixBackend::Error(..) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)),
        UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        UnixBackend::Error(..) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

impl Window2 {
    #[inline]
    pub fn new(events_loop: &EventsLoop,
               window: &::WindowAttributes,
               pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Self, CreationError>
    {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                if let EventsLoop::Wayland(ref evlp) = *events_loop {
                    wayland::Window::new(evlp, ctxt.clone(), window).map(Window2::Wayland)
                } else {
                    // It is not possible to instanciate an EventsLoop not matching its backend
                    unreachable!()
                }
            },

            UnixBackend::X(_) => {
                x11::Window2::new(events_loop, window, pl_attribs).map(Window2::X)
            },
            UnixBackend::Error(..) => {
                // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
                // thus this function cannot be called!
                unreachable!()
            }
        }
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        match self {
            &Window2::X(ref w) => WindowId::X(w.id()),
            &Window2::Wayland(ref w) => WindowId::Wayland(w.id())
        }
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window2::X(ref w) => w.set_title(title),
            &Window2::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window2::X(ref w) => w.show(),
            &Window2::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window2::X(ref w) => w.hide(),
            &Window2::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window2::X(ref w) => w.get_position(),
            &Window2::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window2::X(ref w) => w.set_position(x, y),
            &Window2::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_inner_size(),
            &Window2::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_outer_size(),
            &Window2::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window2::X(ref w) => w.set_inner_size(x, y),
            &Window2::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window2::X(ref w) => w.set_cursor(cursor),
            &Window2::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window2::X(ref w) => w.set_cursor_state(state),
            &Window2::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window2::X(ref w) => w.hidpi_factor(),
            &Window2::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window2::X(ref w) => w.set_cursor_position(x, y),
            &Window2::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_display(),
            &Window2::Wayland(ref w) => w.get_display().ptr() as *mut _
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_window(),
            &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let UnixBackend::X(ref x) = *UNIX_BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut libc::c_char, buff.capacity() as i32);
        let description = CStr::from_ptr(buff.as_mut_ptr() as *const libc::c_char).to_string_lossy();

        let error = XError {
            description: description.into_owned(),
            error_code: (*event).error_code,
            request_code: (*event).request_code,
            minor_code: (*event).minor_code,
        };

        *x.latest_error.lock().unwrap() = Some(error);
    }

    0
}

pub enum EventsLoop {
    #[doc(hidden)]
    Wayland(wayland::EventsLoop),
    #[doc(hidden)]
    X(x11::EventsLoop)
}

pub enum EventsLoopProxy {
    X(x11::EventsLoopProxy),
    Wayland(wayland::EventsLoopProxy),
}

impl EventsLoop {
    pub fn new() -> EventsLoop {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                EventsLoop::Wayland(wayland::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::X(ref ctxt) => {
                EventsLoop::X(x11::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::Error(..) => {
                panic!("Attempted to create an EventsLoop while no backend was available.")
            }
        }
    }

    pub fn create_proxy(&self) -> EventsLoopProxy {
        match *self {
            EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()),
            EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()),
        }
    }

    pub fn poll_events<F>(&mut self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback),
            EventsLoop::X(ref mut evlp) => evlp.poll_events(callback)
        }
    }

    pub fn run_forever<F>(&mut self, callback: F)
        where F: FnMut(::Event) -> ControlFlow
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.run_forever(callback),
            EventsLoop::X(ref mut evlp) => evlp.run_forever(callback)
        }
    }
}

impl EventsLoopProxy {
    pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
        match *self {
            EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(),
            EventsLoopProxy::X(ref proxy) => proxy.wakeup(),
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "split"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Akira Hayakawa <ruby.wktk@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate getopts;
extern crate libc;

use std::io;
use std::num::Int;
use std::char;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "split";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> int {
    let opts = [
        getopts::optopt("a", "suffix-length", "use suffixes of length N (default 2)", "N"),
        getopts::optopt("b", "bytes", "put SIZE bytes per output file", "SIZE"),
        getopts::optopt("C", "line-bytes", "put at most SIZE bytes of lines per output file", "SIZE"),
        getopts::optflag("d", "numeric-suffixes", "use numeric suffixes instead of alphabetic"),
        getopts::optopt("l", "lines", "put NUMBER lines per output file", "NUMBER"),
        getopts::optflag("", "verbose", "print a diagnostic just before each output file is opened"),
        getopts::optflag("h", "help", "display help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("h") {
        println!("{} v{}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [INPUT [PREFIX]]", NAME);
        println!("");
        io::print(getopts::usage("Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is -, read standard input." , &opts).as_slice());
        println!("");
        println!("SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.");
        return 0;
    }

    if matches.opt_present("V") {
        println!("{} v{}", NAME, VERSION);
        return 0;
    }

    let mut settings = Settings {
        prefix: "".to_string(),
        numeric_suffix: false,
        suffix_length: 0,
        input: "".to_string(),
        strategy: "".to_string(),
        strategy_param: "".to_string(),
        verbose: false,
    };

    settings.numeric_suffix = if matches.opt_present("d") { true } else { false };

    settings.suffix_length = match matches.opt_str("a") {
        Some(n) => match n.as_slice().parse() {
            Some(m) => m,
            None => crash!(1, "cannot parse num")
        },
        None => 2
    };

    settings.verbose = if matches.opt_present("verbose") { true } else { false };

    settings.strategy = "l".to_string();
    settings.strategy_param = "1000".to_string();
    let strategies = vec!["b", "C", "l"];
    for e in strategies.iter() {
        match matches.opt_str(*e) {
            Some(a) => {
                if settings.strategy.as_slice() == "l" {
                    settings.strategy = e.to_string();
                    settings.strategy_param = a;
                } else {
                    crash!(1, "{}: cannot split in more than one way", NAME)
                }
            },
            None => {}
        }
    }

    let mut v = matches.free.iter();
    let (input, prefix) = match (v.next(), v.next()) {
        (Some(a), None) => (a.to_string(), "x".to_string()),
        (Some(a), Some(b)) => (a.to_string(), b.to_string()),
        (None, _) => ("-".to_string(), "x".to_string()),
    };
    settings.input = input;
    settings.prefix = prefix;

    split(&settings)
}

struct Settings {
    prefix: String,
    numeric_suffix: bool,
    suffix_length: uint,
    input: String,
    strategy: String,
    strategy_param: String,
    verbose: bool,
}

struct SplitControl {
    current_line: String, // Don't touch
    request_new_file: bool, // Splitter implementation requests new file
}

trait Splitter {
    // Factory pattern
    fn new(_hint: Option<Self>, &Settings) -> Box<Splitter>;

    // Consume the current_line and return the consumed string
    fn consume(&mut self, &mut SplitControl) -> String;
}

struct LineSplitter {
    saved_lines_to_write: uint,
    lines_to_write: uint,
}

impl Splitter for LineSplitter {
    fn new(_: Option<LineSplitter>, settings: &Settings) -> Box<Splitter> {
        let n = match settings.strategy_param.as_slice().parse() {
            Some(a) => a,
            _ => crash!(1, "invalid number of lines")
        };
        box LineSplitter {
            saved_lines_to_write: n,
            lines_to_write: n,
        } as Box<Splitter>
    }

    fn consume(&mut self, control: &mut SplitControl) -> String {
        self.lines_to_write -= 1;
        if self.lines_to_write == 0 {
            self.lines_to_write = self.saved_lines_to_write;
            control.request_new_file = true;
        }
        control.current_line.clone()
    }
}

struct ByteSplitter {
    saved_bytes_to_write: uint,
    bytes_to_write: uint,
}

impl Splitter for ByteSplitter {
    fn new(_: Option<ByteSplitter>, settings: &Settings) -> Box<Splitter> {
        let mut strategy_param : Vec<char> = settings.strategy_param.chars().collect();
        let suffix = strategy_param.pop().unwrap();
        let multiplier = match suffix {
            '0'...'9' => 1u,
            'b' => 512u,
            'k' => 1024u,
            'm' => 1024u * 1024u,
            _ => crash!(1, "invalid number of bytes")
        };
        let n = if suffix.is_alphabetic() {
            match String::from_chars(strategy_param.as_slice()).as_slice().parse::<uint>() {
                Some(a) => a,
                _ => crash!(1, "invalid number of bytes")
            }
        } else {
            match settings.strategy_param.as_slice().parse::<uint>() {
                Some(a) => a,
                _ => crash!(1, "invalid number of bytes")
            }
        };
        box ByteSplitter {
            saved_bytes_to_write: n * multiplier,
            bytes_to_write: n * multiplier,
        } as Box<Splitter>
    }

    fn consume(&mut self, control: &mut SplitControl) -> String {
        let line = control.current_line.clone();
        let n = std::cmp::min(line.as_slice().chars().count(), self.bytes_to_write);
        self.bytes_to_write -= n;
        if n == 0 {
            self.bytes_to_write = self.saved_bytes_to_write;
            control.request_new_file = true;
        }
        line.as_slice().slice(0, n).to_string()
    }
}

// (1, 3) -> "aab"
fn str_prefix(i: uint, width: uint) -> String {
    let mut c = "".to_string();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = Int::pow(26 as uint, w);
        let r = n / div;
        n -= r * div;
        c.push(char::from_u32((r as u32) + 97).unwrap());
    }
    c
}

// (1, 3) -> "001"
fn num_prefix(i: uint, width: uint) -> String {
    let mut c = "".to_string();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = Int::pow(10 as uint, w);
        let r = n / div;
        n -= r * div;
        c.push(char::from_digit(r, 10).unwrap());
    }
    c
}

fn split(settings: &Settings) -> int {
    let mut reader = io::BufferedReader::new(
        if settings.input.as_slice() == "-" {
            box io::stdio::stdin_raw() as Box<Reader>
        } else {
            let r = match io::File::open(&Path::new(settings.input.clone())) {
                Ok(a) => a,
                Err(_) => crash!(1, "cannot open '{}' for reading: No such file or directory", settings.input)
            };
            box r as Box<Reader>
        }
    );

    let mut splitter: Box<Splitter> =
        match settings.strategy.as_slice() {
            "l" => Splitter::new(None::<LineSplitter>, settings),
            "b" => Splitter::new(None::<ByteSplitter>, settings),
            a @ _ => crash!(1, "strategy {} not supported", a)
        };

    let mut control = SplitControl {
        current_line: "".to_string(), // Request new line
        request_new_file: true, // Request new file
    };

    let mut writer = io::BufferedWriter::new(box io::stdio::stdout_raw() as Box<Writer>);
    let mut fileno = 0;
    loop {
        if control.current_line.as_slice().chars().count() == 0 {
            match reader.read_line() {
                Ok(a) => { control.current_line = a; }
                Err(_) =>  { break; }
            }
        }

        if control.request_new_file {
            let mut filename = settings.prefix.to_string();
            filename.push_str(if settings.numeric_suffix {
                num_prefix(fileno, settings.suffix_length)
            } else {
                str_prefix(fileno, settings.suffix_length)
            }.as_slice());

            if fileno != 0 {
                crash_if_err!(1, writer.flush());
            }
            fileno += 1;
            writer = io::BufferedWriter::new(box io::File::open_mode(&Path::new(filename.as_slice()), io::Open, io::Write) as Box<Writer>);
            control.request_new_file = false;
        }

        let consumed = splitter.consume(&mut control);
        crash_if_err!(1, writer.write_str(consumed.as_slice()));

        let advance = consumed.as_slice().chars().count();
        let clone = control.current_line.clone();
        let sl = clone.as_slice();
        control.current_line = sl.slice(advance, sl.chars().count()).to_string();
    }
    0
}
<commit_msg>C flag for split<commit_after>#![crate_name = "split"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Akira Hayakawa <ruby.wktk@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate getopts;
extern crate libc;

use std::io;
use std::num::Int;
use std::char;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "split";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> int {
    let opts = [
        getopts::optopt("a", "suffix-length", "use suffixes of length N (default 2)", "N"),
        getopts::optopt("b", "bytes", "put SIZE bytes per output file", "SIZE"),
        getopts::optopt("C", "line-bytes", "put at most SIZE bytes of lines per output file", "SIZE"),
        getopts::optflag("d", "numeric-suffixes", "use numeric suffixes instead of alphabetic"),
        getopts::optopt("l", "lines", "put NUMBER lines per output file", "NUMBER"),
        getopts::optflag("", "verbose", "print a diagnostic just before each output file is opened"),
        getopts::optflag("h", "help", "display help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("h") {
        println!("{} v{}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [INPUT [PREFIX]]", NAME);
        println!("");
        io::print(getopts::usage("Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is -, read standard input." , &opts).as_slice());
        println!("");
        println!("SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.");
        return 0;
    }

    if matches.opt_present("V") {
        println!("{} v{}", NAME, VERSION);
        return 0;
    }

    let mut settings = Settings {
        prefix: "".to_string(),
        numeric_suffix: false,
        suffix_length: 0,
        input: "".to_string(),
        strategy: "".to_string(),
        strategy_param: "".to_string(),
        verbose: false,
    };

    settings.numeric_suffix = if matches.opt_present("d") { true } else { false };

    settings.suffix_length = match matches.opt_str("a") {
        Some(n) => match n.as_slice().parse() {
            Some(m) => m,
            None => crash!(1, "cannot parse num")
        },
        None => 2
    };

    settings.verbose = if matches.opt_present("verbose") { true } else { false };

    settings.strategy = "l".to_string();
    settings.strategy_param = "1000".to_string();
    let strategies = vec!["b", "C", "l"];
    for e in strategies.iter() {
        match matches.opt_str(*e) {
            Some(a) => {
                if settings.strategy.as_slice() == "l" {
                    settings.strategy = e.to_string();
                    settings.strategy_param = a;
                } else {
                    crash!(1, "{}: cannot split in more than one way", NAME)
                }
            },
            None => {}
        }
    }

    let mut v = matches.free.iter();
    let (input, prefix) = match (v.next(), v.next()) {
        (Some(a), None) => (a.to_string(), "x".to_string()),
        (Some(a), Some(b)) => (a.to_string(), b.to_string()),
        (None, _) => ("-".to_string(), "x".to_string()),
    };
    settings.input = input;
    settings.prefix = prefix;

    split(&settings)
}

struct Settings {
    prefix: String,
    numeric_suffix: bool,
    suffix_length: uint,
    input: String,
    strategy: String,
    strategy_param: String,
    verbose: bool,
}

struct SplitControl {
    current_line: String, // Don't touch
    request_new_file: bool, // Splitter implementation requests new file
}

trait Splitter {
    // Factory pattern
    fn new(_hint: Option<Self>, &Settings) -> Box<Splitter>;

    // Consume the current_line and return the consumed string
    fn consume(&mut self, &mut SplitControl) -> String;
}

struct LineSplitter {
    saved_lines_to_write: uint,
    lines_to_write: uint,
}

impl Splitter for LineSplitter {
    fn new(_: Option<LineSplitter>, settings: &Settings) -> Box<Splitter> {
        let n = match settings.strategy_param.as_slice().parse() {
            Some(a) => a,
            _ => crash!(1, "invalid number of lines")
        };
        box LineSplitter {
            saved_lines_to_write: n,
            lines_to_write: n,
        } as Box<Splitter>
    }

    fn consume(&mut self, control: &mut SplitControl) -> String {
        self.lines_to_write -= 1;
        if self.lines_to_write == 0 {
            self.lines_to_write = self.saved_lines_to_write;
            control.request_new_file = true;
        }
        control.current_line.clone()
    }
}

struct ByteSplitter {
    saved_bytes_to_write: uint,
    bytes_to_write: uint,
    break_on_line_end: bool,
    require_whole_line: bool,
}

impl Splitter for ByteSplitter {
    fn new(_: Option<ByteSplitter>, settings: &Settings) -> Box<Splitter> {
        let mut strategy_param : Vec<char> = settings.strategy_param.chars().collect();
        let suffix = strategy_param.pop().unwrap();
        let multiplier = match suffix {
            '0'...'9' => 1u,
            'b' => 512u,
            'k' => 1024u,
            'm' => 1024u * 1024u,
            _ => crash!(1, "invalid number of bytes")
        };
        let n = if suffix.is_alphabetic() {
            match String::from_chars(strategy_param.as_slice()).as_slice().parse::<uint>() {
                Some(a) => a,
                _ => crash!(1, "invalid number of bytes")
            }
        } else {
            match settings.strategy_param.as_slice().parse::<uint>() {
                Some(a) => a,
                _ => crash!(1, "invalid number of bytes")
            }
        };
        box ByteSplitter {
            saved_bytes_to_write: n * multiplier,
            bytes_to_write: n * multiplier,
            break_on_line_end: if settings.strategy == "b" { false } else { true },
            require_whole_line: false,
        } as Box<Splitter>
    }

    fn consume(&mut self, control: &mut SplitControl) -> String {
        let line = control.current_line.clone();
        let n = std::cmp::min(line.as_slice().chars().count(), self.bytes_to_write);
        if self.require_whole_line && n < line.as_slice().chars().count() {
            self.bytes_to_write = self.saved_bytes_to_write;
            control.request_new_file = true;
            self.require_whole_line = false;
            return line.as_slice().slice(0, 0).to_string();
        }
        self.bytes_to_write -= n;
        if n == 0 {
            self.bytes_to_write = self.saved_bytes_to_write;
            control.request_new_file = true;
        }
        if self.break_on_line_end && n == line.as_slice().chars().count() {
            self.require_whole_line = self.break_on_line_end;
        }
        line.as_slice().slice(0, n).to_string()
    }
}

// (1, 3) -> "aab"
fn str_prefix(i: uint, width: uint) -> String {
    let mut c = "".to_string();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = Int::pow(26 as uint, w);
        let r = n / div;
        n -= r * div;
        c.push(char::from_u32((r as u32) + 97).unwrap());
    }
    c
}

// (1, 3) -> "001"
fn num_prefix(i: uint, width: uint) -> String {
    let mut c = "".to_string();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = Int::pow(10 as uint, w);
        let r = n / div;
        n -= r * div;
        c.push(char::from_digit(r, 10).unwrap());
    }
    c
}

fn split(settings: &Settings) -> int {
    let mut reader = io::BufferedReader::new(
        if settings.input.as_slice() == "-" {
            box io::stdio::stdin_raw() as Box<Reader>
        } else {
            let r = match io::File::open(&Path::new(settings.input.clone())) {
                Ok(a) => a,
                Err(_) => crash!(1, "cannot open '{}' for reading: No such file or directory", settings.input)
            };
            box r as Box<Reader>
        }
    );

    let mut splitter: Box<Splitter> =
        match settings.strategy.as_slice() {
            "l" => Splitter::new(None::<LineSplitter>, settings),
            "b" | "C" => Splitter::new(None::<ByteSplitter>, settings),
            a @ _ => crash!(1, "strategy {} not supported", a)
        };

    let mut control = SplitControl {
        current_line: "".to_string(), // Request new line
        request_new_file: true, // Request new file
    };

    let mut writer = io::BufferedWriter::new(box io::stdio::stdout_raw() as Box<Writer>);
    let mut fileno = 0;
    loop {
        if control.current_line.as_slice().chars().count() == 0 {
            match reader.read_line() {
                Ok(a) => { control.current_line = a; }
                Err(_) =>  { break; }
            }
        }

        if control.request_new_file {
            let mut filename = settings.prefix.to_string();
            filename.push_str(if settings.numeric_suffix {
                num_prefix(fileno, settings.suffix_length)
            } else {
                str_prefix(fileno, settings.suffix_length)
            }.as_slice());

            if fileno != 0 {
                crash_if_err!(1, writer.flush());
            }
            fileno += 1;
            writer = io::BufferedWriter::new(box io::File::open_mode(&Path::new(filename.as_slice()), io::Open, io::Write) as Box<Writer>);
            control.request_new_file = false;
        }

        let consumed = splitter.consume(&mut control);
        crash_if_err!(1, writer.write_str(consumed.as_slice()));

        let advance = consumed.as_slice().chars().count();
        let clone = control.current_line.clone();
        let sl = clone.as_slice();
        control.current_line = sl.slice(advance, sl.chars().count()).to_string();
    }
    0
}
<|endoftext|>


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

use std::error;

impl error::Error for ::BytesError {
    fn description(&self) -> &str {
        "invalid number of uuid bytes"
    }
}
<commit_msg>implement Error for uuid::Error<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::error;

impl error::Error for super::BytesError {
    fn description(&self) -> &str {
        "invalid number of uuid bytes"
    }
}

impl error::Error for super::Error {
    fn description(&self) -> &str {
        match *self {
            super::Error::Bytes(err) => error::Error::description(&err),
            super::Error::Parse(err) => error::Error::description(&err),
        }
    }
}

<|endoftext|>


<commit_before>pub mod tables;
pub mod initials;
pub mod enter_vars;
pub mod leave_vars;
pub mod pivots;

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::cell::RefCell;
    use math::variables::{new_var, new_const};
    use math::relationships::Relationship;
    use math::expressions::Expression;
    use objective::problems::ProblemType;
    use objective::functions::Function;
    use objective::constraints::{Constraint, SystemOfConstraints};
    use objective::solvers::transform_leq_rels;
    use tableau::tables::Table;
    use tableau::initials::get_initial_table_from;
    use tableau::enter_vars::get_enter_var_column_index;
    use tableau::leave_vars::get_leave_var_row_index;
    use tableau::pivots::pivot_around;

    #[test]
    fn can_create_tables() {
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x".to_string(), 0);
        column_names.insert("y".to_string(), 1);
        let rows = vec![vec![1.0, 2.0], vec![3.0, 4.0], vec![5.0, 6.0]];
        let table = Table::new(column_names, rows);
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert!(table_header.contains_key("x"));
        assert!(table_header.contains_key("y"));
        assert_eq!(2, table_header.len());
        assert_eq!(0, *table_header.get("x").unwrap());
        assert_eq!(1, *table_header.get("y").unwrap());
        assert_eq!(1.0, table_rows[0][0]);
        assert_eq!(2.0, table_rows[0][1]);
        assert_eq!(3.0, table_rows[1][0]);
        assert_eq!(4.0, table_rows[1][1]);
        assert_eq!(5.0, table_rows[2][0]);
        assert_eq!(6.0, table_rows[2][1]);
    }

    #[test]
    fn can_create_initial_tableau() {
        let e = Expression::new(vec![new_var("Z", 1.0)],
                                Relationship::EQ,
                                vec![new_var("x1", 6.0), new_var("x2", 14.0), new_var("x3", 13.0)]);
        let f = Function::new(e, ProblemType::MAX);
        let e1 = Expression::new(vec![new_var("x1", 0.5), new_var("x2", 2.0), new_var("x3", 1.0)],
                                 Relationship::LEQ,
                                 vec![new_const("Metalworking (days)", 24.0)]);
        let e2 = Expression::new(vec![new_var("x1", 1.0), new_var("x2", 2.0), new_var("x3", 4.0)],
                                 Relationship::LEQ,
                                 vec![new_const("Woodworking (days)", 60.0)]);
        let c1 = Constraint::Regular(RefCell::new(e1));
        let c2 = Constraint::Regular(RefCell::new(e2));
        let c3 = Constraint::NonNegative(new_var("x1", 1.0));
        let c4 = Constraint::NonNegative(new_var("x2", 1.0));
        let c5 = Constraint::NonNegative(new_var("x3", 1.0));
        let system = SystemOfConstraints::new(vec![c1, c2, c3, c4, c5]);
        transform_leq_rels(&system);
        let table = get_initial_table_from(&f, &system);
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(6, table_header.len());
        assert_eq!(3, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("x3"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("RHS"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("x3").unwrap());
        assert_eq!(3, *table_header.get("s1").unwrap());
        assert_eq!(4, *table_header.get("s2").unwrap());
        assert_eq!(5, *table_header.get("RHS").unwrap());
        assert_eq!(vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0], table_rows[0]);
        assert_eq!(vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0], table_rows[1]);
        assert_eq!(vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0], table_rows[2]);
    }

    #[test]
    fn can_get_enter_var_column_index() {
        let table_rows: Vec<Vec<f64>> = vec![vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0],
                                             vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0],
                                             vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0]];
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x1".to_string(), 0);
        column_names.insert("x2".to_string(), 1);
        column_names.insert("x3".to_string(), 2);
        column_names.insert("s1".to_string(), 3);
        column_names.insert("s2".to_string(), 4);
        column_names.insert("RHS".to_string(), 5);
        let table = Table::new(column_names, table_rows);
        assert_eq!(1, get_enter_var_column_index(&table));
        // Make sure no table modification
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(6, table_header.len());
        assert_eq!(3, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("x3"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("RHS"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("x3").unwrap());
        assert_eq!(3, *table_header.get("s1").unwrap());
        assert_eq!(4, *table_header.get("s2").unwrap());
        assert_eq!(5, *table_header.get("RHS").unwrap());
        assert_eq!(vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0], table_rows[0]);
        assert_eq!(vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0], table_rows[1]);
        assert_eq!(vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0], table_rows[2]);
    }

    #[test]
    fn can_get_enter_var_row_index() {
        let table_rows: Vec<Vec<f64>> = vec![vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0],
                                             vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0],
                                             vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0]];
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x1".to_string(), 0);
        column_names.insert("x2".to_string(), 1);
        column_names.insert("x3".to_string(), 2);
        column_names.insert("s1".to_string(), 3);
        column_names.insert("s2".to_string(), 4);
        column_names.insert("RHS".to_string(), 5);
        let table = Table::new(column_names, table_rows);
        let enter_var_index = get_enter_var_column_index(&table);
        assert_eq!(0, get_leave_var_row_index(enter_var_index, &table));
        // Make sure no table modification
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(6, table_header.len());
        assert_eq!(3, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("x3"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("RHS"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("x3").unwrap());
        assert_eq!(3, *table_header.get("s1").unwrap());
        assert_eq!(4, *table_header.get("s2").unwrap());
        assert_eq!(5, *table_header.get("RHS").unwrap());
        assert_eq!(vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0], table_rows[0]);
        assert_eq!(vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0], table_rows[1]);
        assert_eq!(vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0], table_rows[2]);
    }

    #[test]
    fn can_pivot_around() {
        let table_rows: Vec<Vec<f64>> = vec![vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0],
                                             vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0],
                                             vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0]];
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x1".to_string(), 0);
        column_names.insert("x2".to_string(), 1);
        column_names.insert("x3".to_string(), 2);
        column_names.insert("s1".to_string(), 3);
        column_names.insert("s2".to_string(), 4);
        column_names.insert("RHS".to_string(), 5);
        let mut table = Table::new(column_names, table_rows);
        pivot_around(1, 0, &mut table);
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(vec![0.25, 1.0, 0.5, 0.5, 0.0, 12.0], table_rows[0]);
        assert_eq!(vec![0.5, 0.0, 3.0, -1.0, 1.0, 36.0], table_rows[1]);
        assert_eq!(vec![2.5, 0.0, 6.0, -7.0, 0.0, -168.0], table_rows[2]);
        // Make sure no table modification
        assert_eq!(6, table_header.len());
        assert_eq!(3, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("x3"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("RHS"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("x3").unwrap());
        assert_eq!(3, *table_header.get("s1").unwrap());
        assert_eq!(4, *table_header.get("s2").unwrap());
        assert_eq!(5, *table_header.get("RHS").unwrap());
    }
}
<commit_msg>Create better test for pivoting.<commit_after>pub mod tables;
pub mod initials;
pub mod enter_vars;
pub mod leave_vars;
pub mod pivots;

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::cell::RefCell;
    use math::variables::{new_var, new_const};
    use math::relationships::Relationship;
    use math::expressions::Expression;
    use objective::problems::ProblemType;
    use objective::functions::Function;
    use objective::constraints::{Constraint, SystemOfConstraints};
    use objective::solvers::transform_leq_rels;
    use tableau::tables::Table;
    use tableau::initials::get_initial_table_from;
    use tableau::enter_vars::get_enter_var_column_index;
    use tableau::leave_vars::get_leave_var_row_index;
    use tableau::pivots::pivot_around;

    #[test]
    fn can_create_tables() {
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x".to_string(), 0);
        column_names.insert("y".to_string(), 1);
        let rows = vec![vec![1.0, 2.0], vec![3.0, 4.0], vec![5.0, 6.0]];
        let table = Table::new(column_names, rows);
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert!(table_header.contains_key("x"));
        assert!(table_header.contains_key("y"));
        assert_eq!(2, table_header.len());
        assert_eq!(0, *table_header.get("x").unwrap());
        assert_eq!(1, *table_header.get("y").unwrap());
        assert_eq!(1.0, table_rows[0][0]);
        assert_eq!(2.0, table_rows[0][1]);
        assert_eq!(3.0, table_rows[1][0]);
        assert_eq!(4.0, table_rows[1][1]);
        assert_eq!(5.0, table_rows[2][0]);
        assert_eq!(6.0, table_rows[2][1]);
    }

    #[test]
    fn can_create_initial_tableau() {
        let e = Expression::new(vec![new_var("Z", 1.0)],
                                Relationship::EQ,
                                vec![new_var("x1", 6.0), new_var("x2", 14.0), new_var("x3", 13.0)]);
        let f = Function::new(e, ProblemType::MAX);
        let e1 = Expression::new(vec![new_var("x1", 0.5), new_var("x2", 2.0), new_var("x3", 1.0)],
                                 Relationship::LEQ,
                                 vec![new_const("Metalworking (days)", 24.0)]);
        let e2 = Expression::new(vec![new_var("x1", 1.0), new_var("x2", 2.0), new_var("x3", 4.0)],
                                 Relationship::LEQ,
                                 vec![new_const("Woodworking (days)", 60.0)]);
        let c1 = Constraint::Regular(RefCell::new(e1));
        let c2 = Constraint::Regular(RefCell::new(e2));
        let c3 = Constraint::NonNegative(new_var("x1", 1.0));
        let c4 = Constraint::NonNegative(new_var("x2", 1.0));
        let c5 = Constraint::NonNegative(new_var("x3", 1.0));
        let system = SystemOfConstraints::new(vec![c1, c2, c3, c4, c5]);
        transform_leq_rels(&system);
        let table = get_initial_table_from(&f, &system);
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(6, table_header.len());
        assert_eq!(3, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("x3"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("RHS"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("x3").unwrap());
        assert_eq!(3, *table_header.get("s1").unwrap());
        assert_eq!(4, *table_header.get("s2").unwrap());
        assert_eq!(5, *table_header.get("RHS").unwrap());
        assert_eq!(vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0], table_rows[0]);
        assert_eq!(vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0], table_rows[1]);
        assert_eq!(vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0], table_rows[2]);
    }

    #[test]
    fn can_get_enter_var_column_index() {
        let table_rows: Vec<Vec<f64>> = vec![vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0],
                                             vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0],
                                             vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0]];
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x1".to_string(), 0);
        column_names.insert("x2".to_string(), 1);
        column_names.insert("x3".to_string(), 2);
        column_names.insert("s1".to_string(), 3);
        column_names.insert("s2".to_string(), 4);
        column_names.insert("RHS".to_string(), 5);
        let table = Table::new(column_names, table_rows);
        assert_eq!(1, get_enter_var_column_index(&table));
        // Make sure no table modification
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(6, table_header.len());
        assert_eq!(3, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("x3"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("RHS"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("x3").unwrap());
        assert_eq!(3, *table_header.get("s1").unwrap());
        assert_eq!(4, *table_header.get("s2").unwrap());
        assert_eq!(5, *table_header.get("RHS").unwrap());
        assert_eq!(vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0], table_rows[0]);
        assert_eq!(vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0], table_rows[1]);
        assert_eq!(vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0], table_rows[2]);
    }

    #[test]
    fn can_get_enter_var_row_index() {
        let table_rows: Vec<Vec<f64>> = vec![vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0],
                                             vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0],
                                             vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0]];
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x1".to_string(), 0);
        column_names.insert("x2".to_string(), 1);
        column_names.insert("x3".to_string(), 2);
        column_names.insert("s1".to_string(), 3);
        column_names.insert("s2".to_string(), 4);
        column_names.insert("RHS".to_string(), 5);
        let table = Table::new(column_names, table_rows);
        let enter_var_index = get_enter_var_column_index(&table);
        assert_eq!(0, get_leave_var_row_index(enter_var_index, &table));
        // Make sure no table modification
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(6, table_header.len());
        assert_eq!(3, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("x3"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("RHS"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("x3").unwrap());
        assert_eq!(3, *table_header.get("s1").unwrap());
        assert_eq!(4, *table_header.get("s2").unwrap());
        assert_eq!(5, *table_header.get("RHS").unwrap());
        assert_eq!(vec![0.5, 2.0, 1.0, 1.0, 0.0, 24.0], table_rows[0]);
        assert_eq!(vec![1.0, 2.0, 4.0, 0.0, 1.0, 60.0], table_rows[1]);
        assert_eq!(vec![6.0, 14.0, 13.0, 0.0, 0.0, 0.0], table_rows[2]);
    }

    #[test]
    fn can_pivot_around() {
        let table_rows: Vec<Vec<f64>> = vec![vec![3.0, 6.0, 1.0, 0.0, 0.0, 90.0],
                                             vec![2.0, 1.0, 0.0, 1.0, 0.0, 35.0],
                                             vec![1.0, 1.0, 0.0, 0.0, 1.0, 20.0],
                                             vec![-2.5, -3.0, 0.0, 0.0, 0.0, 0.0]];
        let mut column_names: HashMap<String, usize> = HashMap::new();
        column_names.insert("x1".to_string(), 0);
        column_names.insert("x2".to_string(), 1);
        column_names.insert("s1".to_string(), 2);
        column_names.insert("s2".to_string(), 3);
        column_names.insert("s3".to_string(), 4);
        column_names.insert("Value".to_string(), 5);
        let mut table = Table::new(column_names, table_rows);
        pivot_around(1, 0, &mut table);
        let table_header = table.get_column_names();
        let table_rows = table.get_rows();
        assert_eq!(vec![0.5, 1.0, (1.0 / 6.0), 0.0, 0.0, 15.0], table_rows[0]);
        assert_eq!(vec![1.5, 0.0, -(1.0 / 6.0), 1.0, 0.0, 20.0], table_rows[1]);
        assert_eq!(vec![0.5, 0.0, -(1.0 / 6.0), 0.0, 1.0, 5.0], table_rows[2]);
        assert_eq!(vec![-1.0, 0.0, 0.5, 0.0, 0.0, 45.0], table_rows[3]);
        // Make sure no table modification
        assert_eq!(6, table_header.len());
        assert_eq!(4, table_rows.len());
        assert!(table_header.contains_key("x1"));
        assert!(table_header.contains_key("x2"));
        assert!(table_header.contains_key("s1"));
        assert!(table_header.contains_key("s2"));
        assert!(table_header.contains_key("s3"));
        assert!(table_header.contains_key("Value"));
        assert_eq!(0, *table_header.get("x1").unwrap());
        assert_eq!(1, *table_header.get("x2").unwrap());
        assert_eq!(2, *table_header.get("s1").unwrap());
        assert_eq!(3, *table_header.get("s2").unwrap());
        assert_eq!(4, *table_header.get("s3").unwrap());
        assert_eq!(5, *table_header.get("Value").unwrap());
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use runtime::actiondispatch::dispatchable::Dispatchable;
use structure::xflow::{XFlowNode, XFlowNodeType};
use xfstate::XFState;

type Receivers<'a> = HashMap<XFlowNodeType, Box<Dispatchable + 'a>>;

#[derive(Debug)]
pub struct Dispatcher<'a> {
    receivers: Receivers<'a>,
}

impl<'a> Dispatcher<'a> {
    pub fn register_receiver<T: Dispatchable + 'a>(
        &mut self,
        xflow_node_type: XFlowNodeType,
        receiver: T,
    ) -> () {
        let receiver_box = Box::new(receiver);
        self.receivers.insert(
            xflow_node_type.to_owned(),
            receiver_box,
        );
    }

    pub fn dispatch(&self, xfnode: &XFlowNode, xfstate: &mut XFState) -> Result<(), String> {
        debug!("Nodetype {:?}, action {}", xfnode.nodetype, xfnode.action);

        if let Some(receiver) = self.receivers.get(&xfnode.nodetype) {
            match receiver.dispatch(xfnode, xfstate) {
                Ok(()) => Ok(()),
                Err(()) => {
                    let msg = "An error has occurred dispatching, but this is currently not handled".to_owned();
                    error!("{}", msg);
                    Err(msg)
                }
            }
        } else {
            let msg = format!(
                "No dispatcher found for {:?}/{}!",
                xfnode.nodetype,
                xfnode.action
            );
            error!("{}", msg);
            Err(msg)
        }

    }
}

impl<'a> Default for Dispatcher<'a> {
    fn default() -> Dispatcher<'a> {
        let receivers: Receivers = HashMap::new();

        Dispatcher { receivers: receivers }
    }
}
<commit_msg>wip: Remove Debug from Dispatchable<commit_after>use std::collections::HashMap;

use runtime::actiondispatch::dispatchable::Dispatchable;
use structure::xflow::{XFlowNode, XFlowNodeType};
use xfstate::XFState;

type Receivers<'a> = HashMap<XFlowNodeType, Box<Dispatchable + 'a>>;

pub struct Dispatcher<'a> {
    receivers: Receivers<'a>,
}

impl<'a> Dispatcher<'a> {
    pub fn register_receiver<T: Dispatchable + 'a>(
        &mut self,
        xflow_node_type: XFlowNodeType,
        receiver: T,
    ) -> () {
        let receiver_box = Box::new(receiver);
        self.receivers.insert(
            xflow_node_type.to_owned(),
            receiver_box,
        );
    }

    pub fn dispatch(&self, xfnode: &XFlowNode, xfstate: &mut XFState) -> Result<(), String> {
        debug!("Nodetype {:?}, action {}", xfnode.nodetype, xfnode.action);

        if let Some(receiver) = self.receivers.get(&xfnode.nodetype) {
            match receiver.dispatch(xfnode, xfstate) {
                Ok(()) => Ok(()),
                Err(()) => {
                    let msg = "An error has occurred dispatching, but this is currently not handled".to_owned();
                    error!("{}", msg);
                    Err(msg)
                }
            }
        } else {
            let msg = format!(
                "No dispatcher found for {:?}/{}!",
                xfnode.nodetype,
                xfnode.action
            );
            error!("{}", msg);
            Err(msg)
        }

    }
}

impl<'a> Default for Dispatcher<'a> {
    fn default() -> Dispatcher<'a> {
        let receivers: Receivers = HashMap::new();

        Dispatcher { receivers: receivers }
    }
}
<|endoftext|>