<commit_before>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

pub trait PrettyPrint {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> ();
    fn pretty_print(&self) -> String {
        let mut pretty_printed = String::new();
        &self.pretty_print_into(&mut pretty_printed);
        pretty_printed
    }
}

impl PrettyPrint for Expr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &Expr::Literal(ref l) => l.pretty_print_into(pretty_printed),
            &Expr::Unary(ref u) => (*u).pretty_print_into(pretty_printed),
            &Expr::Binary(ref b) => (*b).pretty_print_into(pretty_printed),
            &Expr::Grouping(ref g) => (*g).pretty_print_into(pretty_printed),
        }
    }
}

impl PrettyPrint for UnaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &UnaryOperator::Bang => pretty_printed.push_str("!"),
            &UnaryOperator::Minus => pretty_printed.push_str("-"),
        }
    }
}

impl PrettyPrint for BinaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &BinaryOperator::Minus => pretty_printed.push_str("-"),
            &BinaryOperator::Plus => pretty_printed.push_str("+"),
            &BinaryOperator::Slash => pretty_printed.push_str("/"),
            &BinaryOperator::Star => pretty_printed.push_str("*"),
            &BinaryOperator::Equal => pretty_printed.push_str("=="),
            &BinaryOperator::NotEqual => pretty_printed.push_str("!="),
            &BinaryOperator::Less => pretty_printed.push_str("<"),
            &BinaryOperator::LessEqual => pretty_printed.push_str("<="),
            &BinaryOperator::Greater => pretty_printed.push_str(">"),
            &BinaryOperator::GreaterEqual => pretty_printed.push_str(">="),
        }
    }
}

impl PrettyPrint for Literal {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &Literal::NilLiteral => pretty_printed.push_str("null"),
            &Literal::BoolLiteral(ref b) => pretty_printed.push_str(&b.to_string()),
            &Literal::StringLiteral(ref s) => pretty_printed.push_str(s),
            &Literal::NumberLiteral(n) => pretty_printed.push_str(&n.to_string()),
        }
    }
}

impl PrettyPrint for Grouping {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(group ");
        &self.expr.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for UnaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        &self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for BinaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        &self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.left.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!("abc", &expr.pretty_print());
    }

    #[test]
    fn complex_expression() {
        let subexpr1 = UnaryExpr {
            operator: UnaryOperator::Minus,
            right: Expr::Literal(Literal::NumberLiteral(123f64)),
        };
        let subexpr2 = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        let binary_expr = BinaryExpr {
            left: Expr::Unary(Box::new(subexpr1)),
            operator: BinaryOperator::Star,
            right: Expr::Grouping(Box::new(subexpr2)),
        };
        let expr = Expr::Binary(Box::new(binary_expr));
        assert_eq!("(* (- 123) (group 45.67))", &expr.pretty_print());
    }
}
<commit_msg>Removed useless dereferencing<commit_after>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

pub trait PrettyPrint {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> ();
    fn pretty_print(&self) -> String {
        let mut pretty_printed = String::new();
        &self.pretty_print_into(&mut pretty_printed);
        pretty_printed
    }
}

impl PrettyPrint for Expr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &Expr::Literal(ref l) => l.pretty_print_into(pretty_printed),
            &Expr::Unary(ref u) => u.pretty_print_into(pretty_printed),
            &Expr::Binary(ref b) => b.pretty_print_into(pretty_printed),
            &Expr::Grouping(ref g) => g.pretty_print_into(pretty_printed),
        }
    }
}

impl PrettyPrint for UnaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &UnaryOperator::Bang => pretty_printed.push_str("!"),
            &UnaryOperator::Minus => pretty_printed.push_str("-"),
        }
    }
}

impl PrettyPrint for BinaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &BinaryOperator::Minus => pretty_printed.push_str("-"),
            &BinaryOperator::Plus => pretty_printed.push_str("+"),
            &BinaryOperator::Slash => pretty_printed.push_str("/"),
            &BinaryOperator::Star => pretty_printed.push_str("*"),
            &BinaryOperator::Equal => pretty_printed.push_str("=="),
            &BinaryOperator::NotEqual => pretty_printed.push_str("!="),
            &BinaryOperator::Less => pretty_printed.push_str("<"),
            &BinaryOperator::LessEqual => pretty_printed.push_str("<="),
            &BinaryOperator::Greater => pretty_printed.push_str(">"),
            &BinaryOperator::GreaterEqual => pretty_printed.push_str(">="),
        }
    }
}

impl PrettyPrint for Literal {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &Literal::NilLiteral => pretty_printed.push_str("null"),
            &Literal::BoolLiteral(ref b) => pretty_printed.push_str(&b.to_string()),
            &Literal::StringLiteral(ref s) => pretty_printed.push_str(s),
            &Literal::NumberLiteral(n) => pretty_printed.push_str(&n.to_string()),
        }
    }
}

impl PrettyPrint for Grouping {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(group ");
        &self.expr.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for UnaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        &self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for BinaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        &self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.left.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!("abc", &expr.pretty_print());
    }

    #[test]
    fn complex_expression() {
        let subexpr1 = UnaryExpr {
            operator: UnaryOperator::Minus,
            right: Expr::Literal(Literal::NumberLiteral(123f64)),
        };
        let subexpr2 = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        let binary_expr = BinaryExpr {
            left: Expr::Unary(Box::new(subexpr1)),
            operator: BinaryOperator::Star,
            right: Expr::Grouping(Box::new(subexpr2)),
        };
        let expr = Expr::Binary(Box::new(binary_expr));
        assert_eq!("(* (- 123) (group 45.67))", &expr.pretty_print());
    }
}
<|endoftext|>


<commit_before>use serde_json;
use serde_json::Value;

use bot::parse_mode::{get_parse_mode, ParseMode};
use bot::chat_action::{ChatAction, get_chat_action};
use error::Error::{JsonNotFound};
use error::{Result, check_for_error};
use objects::{Update, Message, Markup, Contact};
use bot::Bot;

impl Bot {
    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message(&self,
                        chat_id: &i64,
                        text: &str,
                        parse_mode: Option<&ParseMode>,
                        disable_web_page_preview: Option<&bool>,
                        disable_notification: Option<&bool>,
                        reply_to_message_id: Option<&i64>,
                        reply_markup: Option<&Markup>)
                        -> Result<Message> {
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str = &disable_web_page_preview.unwrap_or(&false)
            .to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string())
            .unwrap_or("None".to_string());
        let reply_markup =
            if reply_markup.is_some() {
                serde_json::to_string(&reply_markup.unwrap())
                    .unwrap_or("None".to_string())
            } else {
                "".to_string()
            };
        let path = ["sendMessage"];
        let params = [("chat_id", chat_id),
                      ("text", text),
                      ("parse_mode", parse_mode),
                      ("disable_web_page_preview", disable_web_page_preview),
                      ("disable_notification", disable_notification),
                      ("reply_to_message_id", reply_to_message_id),
                      ("reply_markup", &reply_markup)];
        self.post_message(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(&chat_id, text, None, None, None, Some(&message_id), None)
    }

    /// API call which will forward a message.
    pub fn forward_messge(&self,
                          update: &Update,
                          chat_id: &i32,
                          disable_notification: Option<&bool>)
                          -> Result<Message> {
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [("chat_id", chat_id),
                      ("from_chat_id", from_chat_id),
                      ("disable_notification", disable_notification),
                      ("message_id", message_id)];
        self.post_message(&path, &params)
    }

    /// API call whick will send the requested chat action to your bot.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        let action = get_chat_action(action);
        println!("{:?}", &action);
        let path = ["sendChatAction"];
        let url = ::construct_api_url(&self.bot_url, &path);
        let params = [("chat_id", chat_id.to_string()),
            ("action", action)];
        let mut data = self.client.post(&url).form(&params).send()?;
        println!("{:?}", &data);

        let rjson: Value = check_for_error(data.json()?)?;
        let message_json = rjson.get("result").ok_or(JsonNotFound)?;
        println!("{:?}", message_json);
        if message_json.as_bool().unwrap() {
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// API call which will send the given contact.
    pub fn send_contact(&self,
                        chat_id: &i64,
                        contact: &Contact,
                        disable_notification: Option<&bool>,
                        reply_to_message_id: Option<&i32>,
                        reply_markup: Option<&Markup>) -> Result<bool> {

        let chat_id: &str = &chat_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string())
            .unwrap_or("None".to_string());
        let reply_markup =
            if reply_markup.is_some() {
                serde_json::to_string(&reply_markup.unwrap())
                    .unwrap_or("None".to_string())
            } else {
                "".to_string()
            };

        let path = ["sendContact"];
        let url = ::construct_api_url(&self.bot_url, &path);
        let params = [("chat_id", chat_id),
            ("phone_number", &contact.phone_number),
            ("first_name", &contact.first_name),
            ("last_name", &contact.clone().last_name.unwrap()),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", &reply_markup)];
        //println!("{:?}", params);
        let mut data = self.client.post(&url).form(&params).send()?;
        println!("{:?}", &data);

        let rjson: Value = check_for_error(data.json()?)?;
        println!("{:?}", &rjson);
        let message_json = rjson.get("result").ok_or(JsonNotFound)?;
        //println!("{:?}", message_json);
        if message_json.as_bool().unwrap_or(false) {
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// The actual networking done for sending messages.
    fn post_message(&self, path: &[&str], params: &[(&str, &str)]) -> Result<Message> {
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url).form(&params).send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let message_json = rjson.get("result").ok_or(JsonNotFound)?;
        let message: Message = serde_json::from_value(message_json.clone())?;
        Ok(message)
    }
}
<commit_msg>removed send_contact method and moved it to media.rs<commit_after>use serde_json;
use serde_json::Value;

use bot::parse_mode::{get_parse_mode, ParseMode};
use bot::chat_action::{ChatAction, get_chat_action};
use error::Error::{JsonNotFound};
use error::{Result, check_for_error};
use objects::{Update, Message, InlineKeyboardMarkup};
use bot::Bot;

impl Bot {
    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message(&self,
                        chat_id: &i64,
                        text: &str,
                        parse_mode: Option<&ParseMode>,
                        disable_web_page_preview: Option<&bool>,
                        disable_notification: Option<&bool>,
                        reply_to_message_id: Option<&i64>,
                        reply_markup: Option<&InlineKeyboardMarkup>)
                        -> Result<Message> {
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str = &disable_web_page_preview.unwrap_or(&false)
            .to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string())
            .unwrap_or("None".to_string());

        let reply_markup: &str = &if let Some(r) = reply_markup {
            serde_json::to_string(&reply_markup).unwrap_or("None".to_string())
        } else {
            "".to_string()
        };

        let path = ["sendMessage"];
        let params = [("chat_id", chat_id),
                      ("text", text),
                      ("parse_mode", parse_mode),
                      ("disable_web_page_preview", disable_web_page_preview),
                      ("disable_notification", disable_notification),
                      ("reply_to_message_id", reply_to_message_id),
                      ("reply_markup", reply_markup)];
        self.post_message(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(&chat_id, text, None, None, None, Some(&message_id), None)
    }

    /// API call which will forward a message.
    pub fn forward_messge(&self,
                          update: &Update,
                          chat_id: &i32,
                          disable_notification: Option<&bool>)
                          -> Result<Message> {
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [("chat_id", chat_id),
                      ("from_chat_id", from_chat_id),
                      ("disable_notification", disable_notification),
                      ("message_id", message_id)];
        self.post_message(&path, &params)
    }

    /// API call which will send the requested chat action to your bot.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        let action = get_chat_action(action);
        let path = ["sendChatAction"];
        let url = ::construct_api_url(&self.bot_url, &path);
        let params = [("chat_id", chat_id.to_string()),
            ("action", action)];
        let mut data = self.client.post(&url).form(&params).send()?;

        let rjson: Value = check_for_error(data.json()?)?;
        let success = rjson.get("result").ok_or(JsonNotFound)?;

        Ok(success.as_bool().unwrap())
    }

    /// The actual networking done for sending messages.
    fn post_message(&self, path: &[&str], params: &[(&str, &str)]) -> Result<Message> {
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url).form(&params).send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let message_json = rjson.get("result").ok_or(JsonNotFound)?;
        let message: Message = serde_json::from_value(message_json.clone())?;
        Ok(message)
    }
}
<|endoftext|>


<commit_before>// ignore-test
// compile-flags: --force-warns arithmetic_overflow
// check-pass

#![allow(arithmetic_overflow)]

fn main() {
    1_i32 << 32;
    //~^ WARN this arithmetic operation will overflow
}
<commit_msg>Add final test<commit_after>// compile-flags: --force-warns const_err
// check-pass

#![allow(const_err)]
const C: i32 = 1 / 0;
//~^ WARN any use of this value will cause an error
//~| WARN this was previously accepted by the compiler

fn main() {}
<|endoftext|>


<commit_before>#![feature(generators, generator_trait)]

use std::ops::{GeneratorState, Generator};
use std::pin::Pin;

fn finish<T>(mut amt: usize, mut t: T) -> T::Return
    where T: Generator<Yield = usize>
{
    // We are not moving the `t` around until it gets dropped, so this is okay.
    let mut t = unsafe { Pin::new_unchecked(&mut t) };
    loop {
        match t.as_mut().resume() {
            GeneratorState::Yielded(y) => amt -= y,
            GeneratorState::Complete(ret) => {
                assert_eq!(amt, 0);
                return ret
            }
        }
    }
}

enum Never {}
fn never() -> Never {
    panic!()
}

fn main() {
    finish(1, || yield 1);
    finish(3, || {
        let mut x = 0;
        yield 1;
        x += 1;
        yield 1;
        x += 1;
        yield 1;
        assert_eq!(x, 2);
    });
    finish(7*8/2, || {
        for i in 0..8 {
            yield i;
        }
    });
    finish(1, || {
        if true {
            yield 1;
        } else {
        }
    });
    finish(1, || {
        if false {
        } else {
            yield 1;
        }
    });
    finish(2, || {
        if { yield 1; false } {
            yield 1;
            panic!()
        }
        yield 1;
    });
    // also test a self-referential generator
    assert_eq!(
        finish(5, || {
            let mut x = Box::new(5);
            let y = &mut *x;
            *y = 5;
            yield *y;
            *y = 10;
            *x
        }),
        10
    );
    let b = true;
    finish(1, || {
        yield 1;
        if b { return; }
        #[allow(unused)]
        let x = never();
        yield 2;
        drop(x);
    });
}
<commit_msg>test generator that yields during initialization of struct with uninhabited field<commit_after>#![feature(generators, generator_trait, never_type)]

use std::ops::{GeneratorState, Generator};
use std::pin::Pin;

fn finish<T>(mut amt: usize, mut t: T) -> T::Return
    where T: Generator<Yield = usize>
{
    // We are not moving the `t` around until it gets dropped, so this is okay.
    let mut t = unsafe { Pin::new_unchecked(&mut t) };
    loop {
        match t.as_mut().resume() {
            GeneratorState::Yielded(y) => amt -= y,
            GeneratorState::Complete(ret) => {
                assert_eq!(amt, 0);
                return ret
            }
        }
    }
}

enum Never {}
fn never() -> Never {
    panic!()
}

fn main() {
    finish(1, || yield 1);

    finish(3, || {
        let mut x = 0;
        yield 1;
        x += 1;
        yield 1;
        x += 1;
        yield 1;
        assert_eq!(x, 2);
    });

    finish(7*8/2, || {
        for i in 0..8 {
            yield i;
        }
    });

    finish(1, || {
        if true {
            yield 1;
        } else {
        }
    });

    finish(1, || {
        if false {
        } else {
            yield 1;
        }
    });

    finish(2, || {
        if { yield 1; false } {
            yield 1;
            panic!()
        }
        yield 1;
    });

    // also test a self-referential generator
    assert_eq!(
        finish(5, || {
            let mut x = Box::new(5);
            let y = &mut *x;
            *y = 5;
            yield *y;
            *y = 10;
            *x
        }),
        10
    );

    let b = true;
    finish(1, || {
        yield 1;
        if b { return; }
        #[allow(unused)]
        let x = never();
        yield 2;
        drop(x);
    });

    finish(3, || {
        yield 1;
        #[allow(unreachable_code)]
        let _x: (String, !) = (String::new(), { yield 2; return });
    });
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_imports)]

extern crate fitsio_sys as sys;
extern crate libc;

use std::ptr;
use std::ffi;

mod stringutils;

/// Error type
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    status: i32,
    message: String,
}

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

/// Hdu description type
///
/// Any way of describing a HDU - number or string which either
/// changes the hdu by absolute number, or by name.
pub trait DescribesHdu {
    fn change_hdu(&self, fptr: &FitsFile) -> Result<()>;
}

impl DescribesHdu for usize {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        unsafe {
            sys::ffmahd(f.fptr, (*self + 1) as i32, &mut _hdu_type, &mut status);
        }
        match status {
            0 => Ok(()),
            _ => Err(FitsError {
                status: status,
                message: stringutils::status_to_string(status).unwrap(),
            }),
        }
    }
}

impl<'a> DescribesHdu for &'a str {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        let c_hdu_name = ffi::CString::new(*self).unwrap();

        unsafe {
            sys::ffmnhd(f.fptr,
                   sys::HduType::ANY_HDU as libc::c_int,
                   c_hdu_name.into_raw(),
                   0,
                   &mut status);
        }

        match status {
            0 => Ok(()),
            _ => Err(FitsError {
                status: status,
                message: stringutils::status_to_string(status).unwrap(),
            }),
        }
    }
}

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: std::marker::Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                match status {
                    0 => Ok(value),
                    s => {
                        Err(FitsError {
                            status: s,
                            message: stringutils::status_to_string(s).unwrap(),
                        })
                    }
                }
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                   c_name.into_raw(),
                   value.as_mut_ptr(),
                   ptr::null_mut(),
                   &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                Ok(String::from_utf8(value).unwrap())
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }
}

pub struct FitsFile {
    fptr: *mut sys::fitsfile,
    pub filename: String,
}

impl FitsFile {
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            sys::ffopen(&mut fptr as *mut *mut sys::fitsfile,
                   c_filename.as_ptr(),
                   sys::FileOpenMode::READONLY as libc::c_int,
                   &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: filename.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }

    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            sys::ffinit(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: path.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }

    pub fn hdu<T: DescribesHdu>(&self, hdu_description: T) -> Result<FitsHdu> {
        try!(hdu_description.change_hdu(self));
        let hdu_number = self.hdu_number();

        Ok(FitsHdu {
            fits_file: self,
            hdunum: hdu_number,
        })
    }

    fn hdu_number(&self) -> usize {
        let mut hdu_num = 0;
        unsafe {
            sys::ffghdn(self.fptr, &mut hdu_num);
        }
        (hdu_num - 1) as usize
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        let mut status = 0;
        unsafe {
            sys::ffclos(self.fptr, &mut status);
        }
    }
}

pub struct FitsHdu<'a> {
    fits_file: &'a FitsFile,
    hdunum: usize,
}

impl<'a> FitsHdu<'a> {
    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self.fits_file, name)
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::FitsFile;

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("../testdata/full_example.fits") {
            Ok(_) => {}
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(_) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn fetching_a_hdu() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        for i in 0..2 {
            assert_eq!(f.hdu(i).unwrap().hdunum, i);
        }
        match f.hdu(2) {
            Err(e) => assert_eq!(e.status, 107),
            _ => panic!("Error checking for failure"),
        }

        let tbl_hdu = f.hdu("TESTEXT").unwrap();
        assert_eq!(tbl_hdu.hdunum, 1);
    }

    #[test]
    fn reading_header_keys() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        match f.hdu(0).unwrap().read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }
}
<commit_msg>Add extra tests for header key reading<commit_after>#![allow(dead_code, unused_imports)]

extern crate fitsio_sys as sys;
extern crate libc;

use std::ptr;
use std::ffi;

mod stringutils;

/// Error type
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    status: i32,
    message: String,
}

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

/// Hdu description type
///
/// Any way of describing a HDU - number or string which either
/// changes the hdu by absolute number, or by name.
pub trait DescribesHdu {
    fn change_hdu(&self, fptr: &FitsFile) -> Result<()>;
}

impl DescribesHdu for usize {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        unsafe {
            sys::ffmahd(f.fptr, (*self + 1) as i32, &mut _hdu_type, &mut status);
        }
        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

impl<'a> DescribesHdu for &'a str {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        let c_hdu_name = ffi::CString::new(*self).unwrap();

        unsafe {
            sys::ffmnhd(f.fptr,
                        sys::HduType::ANY_HDU as libc::c_int,
                        c_hdu_name.into_raw(),
                        0,
                        &mut status);
        }

        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: std::marker::Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                match status {
                    0 => Ok(value),
                    s => {
                        Err(FitsError {
                            status: s,
                            message: stringutils::status_to_string(s).unwrap(),
                        })
                    }
                }
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                        c_name.into_raw(),
                        value.as_mut_ptr(),
                        ptr::null_mut(),
                        &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                Ok(String::from_utf8(value).unwrap())
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }
}

pub struct FitsFile {
    fptr: *mut sys::fitsfile,
    pub filename: String,
}

impl FitsFile {
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            sys::ffopen(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        sys::FileOpenMode::READONLY as libc::c_int,
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: filename.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }

    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            sys::ffinit(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: path.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }

    pub fn hdu<T: DescribesHdu>(&self, hdu_description: T) -> Result<FitsHdu> {
        try!(hdu_description.change_hdu(self));
        let hdu_number = self.hdu_number();

        Ok(FitsHdu {
            fits_file: self,
            hdunum: hdu_number,
        })
    }

    fn hdu_number(&self) -> usize {
        let mut hdu_num = 0;
        unsafe {
            sys::ffghdn(self.fptr, &mut hdu_num);
        }
        (hdu_num - 1) as usize
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        let mut status = 0;
        unsafe {
            sys::ffclos(self.fptr, &mut status);
        }
    }
}

pub struct FitsHdu<'a> {
    fits_file: &'a FitsFile,
    hdunum: usize,
}

impl<'a> FitsHdu<'a> {
    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self.fits_file, name)
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::FitsFile;

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("../testdata/full_example.fits") {
            Ok(_) => {}
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(_) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn fetching_a_hdu() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        for i in 0..2 {
            assert_eq!(f.hdu(i).unwrap().hdunum, i);
        }
        match f.hdu(2) {
            Err(e) => assert_eq!(e.status, 107),
            _ => panic!("Error checking for failure"),
        }

        let tbl_hdu = f.hdu("TESTEXT").unwrap();
        assert_eq!(tbl_hdu.hdunum, 1);
    }

    #[test]
    fn reading_header_keys() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        match f.hdu(0).unwrap().read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.hdu(0).unwrap().read_key::<f64>("DBLTEST") {
            Ok(value) => assert_eq!(value, 0.09375),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.hdu(0).unwrap().read_key::<String>("TEST") {
            Ok(value) => assert_eq!(value, "value"),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>use analysis::namespaces;
use case::CaseExt;
use codegen::general::{self, version_condition, version_condition_string};
use config::gobjects::GObject;
use env::Env;
use file_saver;
use library::*;
use std::collections::HashSet;
use std::io::prelude::*;
use std::io::Result;
use std::path::Path;
use traits::*;
use version::Version;

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    let configs: Vec<&GObject> = env.config
        .objects
        .values()
        .filter(|c| {
            c.status.need_generate() && c.type_id.map_or(false, |tid| tid.ns_id == namespaces::MAIN)
        })
        .collect();
    let mut has_get_quark = false;
    let mut has_any = false;
    for config in &configs {
        if let Type::Enumeration(ref enum_) = *env.library.type_(config.type_id.unwrap()) {
            has_any = true;
            if get_error_quark_name(enum_).is_some() {
                has_get_quark = true;
                break;
            }
        }
    }

    let path = root_path.join("enums.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        try!(general::start_comments(w, &env.config));
        try!(writeln!(w, ""));
        try!(writeln!(w, "use ffi;"));
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            if has_get_quark {
                try!(writeln!(w, "use ffi as glib_ffi;"));
                try!(writeln!(w, "use error::ErrorDomain;"));
            }
            try!(writeln!(w, "use translate::*;"));
        } else {
            if has_get_quark {
                try!(writeln!(w, "use glib_ffi;"));
                try!(writeln!(w, "use glib::error::ErrorDomain;"));
            }
            try!(writeln!(w, "use glib::translate::*;"));
        }
        try!(writeln!(w, ""));

        if has_any {
            mod_rs.push("\nmod enums;".into());
        }
        for config in &configs {
            if let Type::Enumeration(ref enum_) = *env.library.type_(config.type_id.unwrap()) {
                if let Some(cfg) = version_condition_string(env, enum_.version, false, 0) {
                    mod_rs.push(cfg);
                }
                mod_rs.push(format!("pub use self::enums::{};", enum_.name));
                try!(generate_enum(env, w, enum_, config));
            }
        }

        Ok(())
    });
}

fn generate_enum(env: &Env, w: &mut Write, enum_: &Enumeration, config: &GObject) -> Result<()> {
    struct Member {
        name: String,
        c_name: String,
        version: Option<Version>,
    }

    let mut members: Vec<Member> = Vec::new();
    let mut vals: HashSet<String> = HashSet::new();

    for member in &enum_.members {
        let member_config = config.members.matched(&member.name);
        let is_alias = member_config.iter().any(|m| m.alias);
        if is_alias || vals.contains(&member.value) {
            continue;
        }
        vals.insert(member.value.clone());
        let version = member_config.iter().filter_map(|m| m.version).next();
        members.push(Member {
            name: member.name.to_camel(),
            c_name: member.c_identifier.clone(),
            version: version,
        });
    }

    try!(version_condition(w, env, enum_.version, false, 0));
    try!(writeln!(
        w,
        "#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]"
    ));
    try!(writeln!(w, "pub enum {} {{", enum_.name));
    for member in &members {
        try!(version_condition(w, env, member.version, false, 1));
        try!(writeln!(w, "\t{},", member.name));
    }
    try!(writeln!(
        w,
        "{}",
        "    #[doc(hidden)]
    __Nonexhaustive(()),
}
"
    ));

    try!(version_condition(w, env, enum_.version, false, 0));
    try!(writeln!(
        w,
        "#[doc(hidden)]
impl ToGlib for {name} {{
    type GlibType = ffi::{ffi_name};

    fn to_glib(&self) -> ffi::{ffi_name} {{
        match *self {{",
        name = enum_.name,
        ffi_name = enum_.c_type
    ));
    for member in &members {
        try!(version_condition(w, env, member.version, false, 3));
        try!(writeln!(
            w,
            "\t\t\t{}::{} => ffi::{},",
            enum_.name,
            member.name,
            member.c_name
        ));
    }
    try!(writeln!(
        w,
        "\t\t\t{}::__Nonexhaustive(_) => panic!(),",
        enum_.name
    ));
    try!(writeln!(
        w,
        "{}",
        "        }
    }
}
"
    ));

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    try!(version_condition(w, env, enum_.version, false, 0));
    try!(writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<ffi::{ffi_name}> for {name} {{
    fn from_glib(value: ffi::{ffi_name}) -> Self {{
        {assert}match value {{",
        name = enum_.name,
        ffi_name = enum_.c_type,
        assert = assert
    ));
    for member in &members {
        try!(version_condition(w, env, member.version, false, 3));
        try!(writeln!(
            w,
            "\t\t\tffi::{} => {}::{},",
            member.c_name,
            enum_.name,
            member.name
        ));
    }
    if members.len() == 1 {
        try!(writeln!(
            w,
            "\t\t\t_ => {}::__Nonexhaustive(()),",
            enum_.name
        ));
    }
    try!(writeln!(
        w,
        "{}",
        "        }
    }
}
"
    ));
    if let Some(ref get_quark) = get_error_quark_name(enum_) {
        let get_quark = get_quark.replace("-", "_");
        let has_failed_member = members.iter().any(|m| m.name == "Failed");

        try!(version_condition(w, env, enum_.version, false, 0));
        try!(writeln!(
            w,
            "impl ErrorDomain for {name} {{
    fn domain() -> glib_ffi::GQuark {{
        {assert}unsafe {{ ffi::{get_quark}() }}
    }}

    fn code(self) -> i32 {{
        self.to_glib() as i32
    }}

    fn from(code: i32) -> Option<Self> {{
        {assert}match code {{",
            name = enum_.name,
            get_quark = get_quark,
            assert = assert
        ));

        for member in &members {
            try!(version_condition(w, env, member.version, false, 3));
            try!(writeln!(
                w,
                "\t\t\tx if x == ffi::{} as i32 => Some({}::{}),",
                member.c_name,
                enum_.name,
                member.name
            ));
        }
        if has_failed_member {
            try!(writeln!(w, "\t\t\t_ => Some({}::Failed),", enum_.name));
        } else {
            try!(writeln!(
                w,
                "\t\t\t_ => Some({}::__Nonexhaustive(())),",
                enum_.name
            ));
        }

        try!(writeln!(
            w,
            "{}",
            "        }
    }
}
"
        ));
    }

    Ok(())
}

fn get_error_quark_name(enum_: &Enumeration) -> Option<String> {
    enum_
        .functions
        .iter()
        .find(|f| f.name == "quark")
        .and_then(|f| f.c_identifier.clone())
        .or_else(|| enum_.error_domain.clone())
}
<commit_msg>Fix enums from_glib unsafety, store unknown value<commit_after>use analysis::namespaces;
use case::CaseExt;
use codegen::general::{self, version_condition, version_condition_string};
use config::gobjects::GObject;
use env::Env;
use file_saver;
use library::*;
use std::collections::HashSet;
use std::io::prelude::*;
use std::io::Result;
use std::path::Path;
use traits::*;
use version::Version;

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    let configs: Vec<&GObject> = env.config
        .objects
        .values()
        .filter(|c| {
            c.status.need_generate() && c.type_id.map_or(false, |tid| tid.ns_id == namespaces::MAIN)
        })
        .collect();
    let mut has_get_quark = false;
    let mut has_any = false;
    for config in &configs {
        if let Type::Enumeration(ref enum_) = *env.library.type_(config.type_id.unwrap()) {
            has_any = true;
            if get_error_quark_name(enum_).is_some() {
                has_get_quark = true;
                break;
            }
        }
    }

    let path = root_path.join("enums.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        try!(general::start_comments(w, &env.config));
        try!(writeln!(w, ""));
        try!(writeln!(w, "use ffi;"));
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            if has_get_quark {
                try!(writeln!(w, "use ffi as glib_ffi;"));
                try!(writeln!(w, "use error::ErrorDomain;"));
            }
            try!(writeln!(w, "use translate::*;"));
        } else {
            if has_get_quark {
                try!(writeln!(w, "use glib_ffi;"));
                try!(writeln!(w, "use glib::error::ErrorDomain;"));
            }
            try!(writeln!(w, "use glib::translate::*;"));
        }
        try!(writeln!(w, "use std;"));
        try!(writeln!(w, ""));

        if has_any {
            mod_rs.push("\nmod enums;".into());
        }
        for config in &configs {
            if let Type::Enumeration(ref enum_) = *env.library.type_(config.type_id.unwrap()) {
                if let Some(cfg) = version_condition_string(env, enum_.version, false, 0) {
                    mod_rs.push(cfg);
                }
                mod_rs.push(format!("pub use self::enums::{};", enum_.name));
                try!(generate_enum(env, w, enum_, config));
            }
        }

        Ok(())
    });
}

fn generate_enum(env: &Env, w: &mut Write, enum_: &Enumeration, config: &GObject) -> Result<()> {
    struct Member {
        name: String,
        c_name: String,
        value: String,
        version: Option<Version>,
    }

    let mut members: Vec<Member> = Vec::new();
    let mut vals: HashSet<String> = HashSet::new();

    for member in &enum_.members {
        let member_config = config.members.matched(&member.name);
        let is_alias = member_config.iter().any(|m| m.alias);
        if is_alias || vals.contains(&member.value) {
            continue;
        }
        vals.insert(member.value.clone());
        let version = member_config.iter().filter_map(|m| m.version).next();
        members.push(Member {
            name: member.name.to_camel(),
            c_name: member.c_identifier.clone(),
            value: member.value.clone(),
            version: version,
        });
    }

    try!(version_condition(w, env, enum_.version, false, 0));
    try!(writeln!(
        w,
        "#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]"
    ));
    try!(writeln!(w, "pub enum {} {{", enum_.name));
    for member in &members {
        try!(version_condition(w, env, member.version, false, 1));
        try!(writeln!(w, "\t{},", member.name));
    }
    try!(writeln!(
        w,
        "{}",
        "    #[doc(hidden)]
    __Unknown(i32),
}
"
    ));

    try!(version_condition(w, env, enum_.version, false, 0));
    try!(writeln!(
        w,
        "#[doc(hidden)]
impl ToGlib for {name} {{
    type GlibType = ffi::{ffi_name};

    fn to_glib(&self) -> ffi::{ffi_name} {{
        match *self {{",
        name = enum_.name,
        ffi_name = enum_.c_type
    ));
    for member in &members {
        try!(version_condition(w, env, member.version, false, 3));
        try!(writeln!(
            w,
            "\t\t\t{}::{} => ffi::{},",
            enum_.name,
            member.name,
            member.c_name
        ));
    }
    try!(writeln!(
        w,
        "\t\t\t{}::__Unknown(value) => unsafe{{std::mem::transmute(value)}}",
        enum_.name
    ));
    try!(writeln!(
        w,
        "{}",
        "        }
    }
}
"
    ));

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    try!(version_condition(w, env, enum_.version, false, 0));
    try!(writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<ffi::{ffi_name}> for {name} {{
    fn from_glib(value: ffi::{ffi_name}) -> Self {{
        {assert}match value as i32 {{",
        name = enum_.name,
        ffi_name = enum_.c_type,
        assert = assert
    ));
    for member in &members {
        try!(version_condition(w, env, member.version, false, 3));
        try!(writeln!(
            w,
            "\t\t\t{} => {}::{},",
            member.value,
            enum_.name,
            member.name
        ));
    }
    try!(writeln!(
        w,
        "\t\t\tvalue => {}::__Unknown(value),",
        enum_.name
    ));
    try!(writeln!(
        w,
        "{}",
        "        }
    }
}
"
    ));
    if let Some(ref get_quark) = get_error_quark_name(enum_) {
        let get_quark = get_quark.replace("-", "_");
        let has_failed_member = members.iter().any(|m| m.name == "Failed");

        try!(version_condition(w, env, enum_.version, false, 0));
        try!(writeln!(
            w,
            "impl ErrorDomain for {name} {{
    fn domain() -> glib_ffi::GQuark {{
        {assert}unsafe {{ ffi::{get_quark}() }}
    }}

    fn code(self) -> i32 {{
        self.to_glib() as i32
    }}

    fn from(code: i32) -> Option<Self> {{
        {assert}match code {{",
            name = enum_.name,
            get_quark = get_quark,
            assert = assert
        ));

        for member in &members {
            try!(version_condition(w, env, member.version, false, 3));
            try!(writeln!(
                w,
                "\t\t\t{} => Some({}::{}),",
                member.value,
                enum_.name,
                member.name
            ));
        }
        if has_failed_member {
            try!(writeln!(w, "\t\t\t_ => Some({}::Failed),", enum_.name));
        } else {
            try!(writeln!(
                w,
                "\t\t\tvalue => Some({}::__Unknown(value)),",
                enum_.name
            ));
        }

        try!(writeln!(
            w,
            "{}",
            "        }
    }
}
"
        ));
    }

    Ok(())
}

fn get_error_quark_name(enum_: &Enumeration) -> Option<String> {
    enum_
        .functions
        .iter()
        .find(|f| f.name == "quark")
        .and_then(|f| f.c_identifier.clone())
        .or_else(|| enum_.error_domain.clone())
}
<|endoftext|>


<commit_before>
extern crate ndarray;
extern crate ndarray_linalg;
extern crate ndarray_rand;
extern crate rand;

use ndarray::prelude::*;
use ndarray_linalg::prelude::*;
use rand::distributions::*;
use ndarray_rand::RandomExt;

fn all_close(a: Array<f64, (Ix, Ix)>, b: Array<f64, (Ix, Ix)>) {
    if !a.all_close(&b, 1.0e-7) {
        panic!("\nTwo matrices are not equal:\na = \n{:?}\nb = \n{:?}\n",
               a,
               b);
    }
}

macro_rules! test_permutate {
    ($testname:ident, $permutate:expr, $input:expr, $answer:expr) => {
#[test]
fn $testname() {
    let a = arr2($input);
    println!("a= \n{:?}", &a);
    let p = $permutate; // replace 1-2
    let pa = a.permutated(&p);
    println!("permutated = \n{:?}", &pa);
    all_close(pa, arr2($answer))
}
    }
}

macro_rules! test_permutate_t {
    ($testname:ident, $permutate:expr, $input:expr, $answer:expr) => {
#[test]
fn $testname() {
    let a = arr2($input).reversed_axes();
    println!("a= \n{:?}", &a);
    let p = $permutate; // replace 1-2
    let pa = a.permutated(&p);
    println!("permutated = \n{:?}", &pa);
    all_close(pa, arr2($answer))
}
    }
}

test_permutate!(permutate,
                vec![2, 2, 3],
                &[[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]],
                &[[4., 5., 6.], [1., 2., 3.], [7., 8., 9.]]);
test_permutate_t!(permutate_t,
                  vec![2, 2, 3],
                  &[[1., 4., 7.], [2., 5., 8.], [3., 6., 9.]],
                  &[[4., 5., 6.], [1., 2., 3.], [7., 8., 9.]]);
test_permutate!(permutate_3x4,
                vec![1, 3, 3],
                &[[1., 4., 7., 10.], [2., 5., 8., 11.], [3., 6., 9., 12.]],
                &[[1., 4., 7., 10.], [3., 6., 9., 12.], [2., 5., 8., 11.]]);
test_permutate_t!(permutate_3x4_t,
                  vec![1, 3, 3],
                  &[[1., 5., 9.], [2., 6., 10.], [3., 7., 11.], [4., 8., 12.]],
                  &[[1., 2., 3., 4.], [9., 10., 11., 12.], [5., 6., 7., 8.]]);
test_permutate!(permutate_4x3,
                vec![4, 2, 3, 4],
                &[[1., 5., 9.], [2., 6., 10.], [3., 7., 11.], [4., 8., 12.]],
                &[[4., 8., 12.], [2., 6., 10.], [3., 7., 11.], [1., 5., 9.]]);
test_permutate_t!(permutate_4x3_t,
                  vec![4, 2, 3, 4],
                  &[[1., 4., 7., 10.], [2., 5., 8., 11.], [3., 6., 9., 12.]],
                  &[[10., 11., 12.], [4., 5., 6.], [7., 8., 9.], [1., 2., 3.]]);

#[test]
fn lu_square_upper() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random((3, 3), r_dist);
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = 0.0;
        }
    }
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    all_close(l.dot(&u).permutated(&p), a);
}

#[test]
fn lu_square_upper_t() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random((3, 3), r_dist).reversed_axes();
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = 0.0;
        }
    }
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    all_close(l.dot(&u).permutated(&p), a);
}

#[test]
fn lu_square_lower() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random((3, 3), r_dist);
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = 0.0;
        }
    }
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    println!("LU = \n{:?}", l.dot(&u));
    all_close(l.dot(&u).permutated(&p), a);
}

#[test]
fn lu_square_lower_t() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random((3, 3), r_dist).reversed_axes();
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = 0.0;
        }
    }
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    println!("LU = \n{:?}", l.dot(&u));
    all_close(l.dot(&u).permutated(&p), a);
}

#[test]
fn lu_square() {
    let r_dist = Range::new(0., 1.);
    let a = Array::<f64, _>::random((3, 3), r_dist);
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    println!("LU = \n{:?}", l.dot(&u));
    all_close(l.dot(&u).permutated(&p), a);
}

#[test]
fn lu_square_t() {
    let r_dist = Range::new(0., 1.);
    let a = Array::<f64, _>::random((3, 3), r_dist).reversed_axes();
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    all_close(l.dot(&u).permutated(&p), a);
}

// #[test]
// fn lu_3x4() {
//     let r_dist = Range::new(0., 1.);
//     let a = Array::<f64, _>::random((3, 4), r_dist);
//     println!("a = \n{:?}", &a);
//     let (p, l, u) = a.clone().lu().unwrap();
//     println!("P = \n{:?}", &p);
//     println!("L = \n{:?}", &l);
//     println!("U = \n{:?}", &u);
//     println!("LU = \n{:?}", l.dot(&u));
//     all_close(l.dot(&u).permutated(&p), a);
// }
//
// #[test]
// fn lu_3x4_t() {
//     let r_dist = Range::new(0., 1.);
//     let a = Array::<f64, _>::random((4, 3), r_dist).reversed_axes();
//     println!("a = \n{:?}", &a);
//     let (p, l, u) = a.clone().lu().unwrap();
//     println!("P = \n{:?}", &p);
//     println!("L = \n{:?}", &l);
//     println!("U = \n{:?}", &u);
//     all_close(l.dot(&u).permutated(&p), a);
// }

// #[test]
// fn lu_4x3_upper() {
//     let r_dist = Range::new(0., 1.);
//     let mut a = Array::<f64, _>::random((4, 3), r_dist);
//     for ((i, j), val) in a.indexed_iter_mut() {
//         if i > j {
//             *val = 0.0;
//         }
//     }
//     println!("a = \n{:?}", &a);
//     let (p, l, u) = a.clone().lu().unwrap();
//     println!("P = \n{:?}", &p);
//     println!("L = \n{:?}", &l);
//     println!("U = \n{:?}", &u);
//     println!("LU = \n{:?}", l.dot(&u));
//     all_close(l.dot(&u).permutated(&p), a);
// }
//
// #[test]
// fn lu_4x3_lower() {
//     let r_dist = Range::new(0., 1.);
//     let mut a = Array::<f64, _>::random((4, 3), r_dist);
//     for ((i, j), val) in a.indexed_iter_mut() {
//         if i < j {
//             *val = 0.0;
//         }
//     }
//     println!("a = \n{:?}", &a);
//     let (p, l, u) = a.clone().lu().unwrap();
//     println!("P = \n{:?}", &p);
//     println!("L = \n{:?}", &l);
//     println!("U = \n{:?}", &u);
//     println!("LU = \n{:?}", l.dot(&u));
//     all_close(l.dot(&u).permutated(&p), a);
// }

#[test]
fn lu_4x3_upper_t() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random((3, 4), r_dist).reversed_axes();
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = 0.0;
        }
    }
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    println!("LU = \n{:?}", l.dot(&u));
    all_close(l.dot(&u).permutated(&p), a);
}

// #[test]
// fn lu_4x3() {
//     let r_dist = Range::new(0., 1.);
//     let a = Array::<f64, _>::random((4, 3), r_dist);
//     println!("a = \n{:?}", &a);
//     let (p, l, u) = a.clone().lu().unwrap();
//     println!("P = \n{:?}", &p);
//     println!("L = \n{:?}", &l);
//     println!("U = \n{:?}", &u);
//     println!("LU = \n{:?}", l.dot(&u));
//     all_close(l.dot(&u).permutated(&p), a);
// }
//
// #[test]
// fn lu_4x3_t() {
//     let r_dist = Range::new(0., 1.);
//     let a = Array::<f64, _>::random((3, 4), r_dist).reversed_axes();
//     println!("a = \n{:?}", &a);
//     let (p, l, u) = a.clone().lu().unwrap();
//     println!("P = \n{:?}", &p);
//     println!("L = \n{:?}", &l);
//     println!("U = \n{:?}", &u);
//     all_close(l.dot(&u).permutated(&p), a);
// }
<commit_msg>Compress duplicated codes for testing LU<commit_after>
extern crate ndarray;
extern crate ndarray_linalg;
extern crate ndarray_rand;
extern crate rand;

use ndarray::prelude::*;
use ndarray_linalg::prelude::*;
use rand::distributions::*;
use ndarray_rand::RandomExt;

fn all_close(a: Array<f64, (Ix, Ix)>, b: Array<f64, (Ix, Ix)>) {
    if !a.all_close(&b, 1.0e-7) {
        panic!("\nTwo matrices are not equal:\na = \n{:?}\nb = \n{:?}\n",
               a,
               b);
    }
}

macro_rules! test_permutate {
    ($testname:ident, $permutate:expr, $input:expr, $answer:expr) => {
#[test]
fn $testname() {
    let a = arr2($input);
    println!("a= \n{:?}", &a);
    let p = $permutate; // replace 1-2
    let pa = a.permutated(&p);
    println!("permutated = \n{:?}", &pa);
    all_close(pa, arr2($answer))
}
}} // end test_permutate

macro_rules! test_permutate_t {
    ($testname:ident, $permutate:expr, $input:expr, $answer:expr) => {
#[test]
fn $testname() {
    let a = arr2($input).reversed_axes();
    println!("a= \n{:?}", &a);
    let p = $permutate; // replace 1-2
    let pa = a.permutated(&p);
    println!("permutated = \n{:?}", &pa);
    all_close(pa, arr2($answer))
}
}} // end test_permutate_t

test_permutate!(permutate,
                vec![2, 2, 3],
                &[[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]],
                &[[4., 5., 6.], [1., 2., 3.], [7., 8., 9.]]);
test_permutate_t!(permutate_t,
                  vec![2, 2, 3],
                  &[[1., 4., 7.], [2., 5., 8.], [3., 6., 9.]],
                  &[[4., 5., 6.], [1., 2., 3.], [7., 8., 9.]]);
test_permutate!(permutate_3x4,
                vec![1, 3, 3],
                &[[1., 4., 7., 10.], [2., 5., 8., 11.], [3., 6., 9., 12.]],
                &[[1., 4., 7., 10.], [3., 6., 9., 12.], [2., 5., 8., 11.]]);
test_permutate_t!(permutate_3x4_t,
                  vec![1, 3, 3],
                  &[[1., 5., 9.], [2., 6., 10.], [3., 7., 11.], [4., 8., 12.]],
                  &[[1., 2., 3., 4.], [9., 10., 11., 12.], [5., 6., 7., 8.]]);
test_permutate!(permutate_4x3,
                vec![4, 2, 3, 4],
                &[[1., 5., 9.], [2., 6., 10.], [3., 7., 11.], [4., 8., 12.]],
                &[[4., 8., 12.], [2., 6., 10.], [3., 7., 11.], [1., 5., 9.]]);
test_permutate_t!(permutate_4x3_t,
                  vec![4, 2, 3, 4],
                  &[[1., 4., 7., 10.], [2., 5., 8., 11.], [3., 6., 9., 12.]],
                  &[[10., 11., 12.], [4., 5., 6.], [7., 8., 9.], [1., 2., 3.]]);

fn test_lu(a: Array<f64, (Ix, Ix)>) {
    println!("a = \n{:?}", &a);
    let (p, l, u) = a.clone().lu().unwrap();
    println!("P = \n{:?}", &p);
    println!("L = \n{:?}", &l);
    println!("U = \n{:?}", &u);
    println!("LU = \n{:?}", l.dot(&u));
    all_close(l.dot(&u).permutated(&p), a);
}

macro_rules! test_lu_upper {
    ($testname:ident, $testname_t:ident, $n:expr, $m:expr) => {
#[test]
fn $testname() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random(($n, $m), r_dist);
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = 0.0;
        }
    }
    test_lu(a);
}
#[test]
fn $testname_t() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random(($m, $n), r_dist).reversed_axes();
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = 0.0;
        }
    }
    test_lu(a);
}
}} // end test_lu_upper
test_lu_upper!(lu_square_upper, lu_square_upper_t, 3, 3);
test_lu_upper!(lu_3x4_upper, lu_3x4_upper_t, 3, 4);
test_lu_upper!(lu_4x3_upper, lu_4x3_upper_t, 4, 3);

macro_rules! test_lu_lower {
    ($testname:ident, $testname_t:ident, $n:expr, $m:expr) => {
#[test]
fn $testname() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random(($n, $m), r_dist);
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = 0.0;
        }
    }
    test_lu(a);
}
#[test]
fn $testname_t() {
    let r_dist = Range::new(0., 1.);
    let mut a = Array::<f64, _>::random(($m, $n), r_dist).reversed_axes();
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = 0.0;
        }
    }
    test_lu(a);
}
}} // end test_lu_lower
test_lu_lower!(lu_square_lower, lu_square_lower_t, 3, 3);
test_lu_lower!(lu_3x4_lower, lu_3x4_lower_t, 3, 4);
test_lu_lower!(lu_4x3_lower, lu_4x3_lower_t, 4, 3);

macro_rules! test_lu {
    ($testname:ident, $testname_t:ident, $n:expr, $m:expr) => {
#[test]
fn $testname() {
    let r_dist = Range::new(0., 1.);
    let a = Array::<f64, _>::random(($n, $m), r_dist);
    test_lu(a);
}
#[test]
fn $testname_t() {
    let r_dist = Range::new(0., 1.);
    let a = Array::<f64, _>::random(($m, $n), r_dist).reversed_axes();
    test_lu(a);
}
}} // end test_lu
test_lu!(lu_square, lu_square_t, 3, 3);
test_lu!(lu_3x4, lu_3x4_t, 3, 4);
test_lu!(lu_4x3, lu_4x3_t, 4, 3);
<|endoftext|>


<commit_before>#![cfg(windows)]

extern crate winapi;
extern crate kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    input: Receiver<u16>,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let rx = Screen::spawn_input_thread(conin as usize);
        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            input: rx,
            conout: conout,
        }
    }

    // We have to take the conin handle as a usize instead of a *mut c_void in order to avoid a
    // lecture from the compiler about how the latter type cannot be safely sent between threads.
    // I'm not sure if a better solution exists at this time.
    fn spawn_input_thread(conin: usize) -> Receiver<u16> {
        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            loop {
                let conin = conin as *mut c_void;
                let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
                let mut chars_read: DWORD = 0;
                win32!(ReadFile(conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));
                for i in 0..chars_read as usize {
                    tx.send(buf[i]).unwrap();
                }
            }
        });

        rx
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in 0..self.height {
            self.write(&blank_line);
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteConsoleA(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const WHITE_ON_RED: WORD = BACKGROUND_RED as WORD;
        self.set_colors(WHITE_ON_RED);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_red(&mut self, s: &str) {
        let orig = self.original_colors;
        const RED_ON_BLACK: WORD = FOREGROUND_RED as WORD;
        self.set_colors(RED_ON_BLACK);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.input.try_recv() {
            ret.push(Screen::translate_byte(byte));
        }
        if ret.is_empty() {
            let byte = self.input.recv().unwrap();
            ret.push(Screen::translate_byte(byte));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 9 {
            Tab
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conout: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conout, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    // AppVeyor builds run without a console, making this test impossible.
    if option_env!("APPVEYOR").is_some() {
        // TODO: It should be made obvious from the output that this test was skipped
        return;
    }
    let conout = unsafe { kernel32::GetStdHandle(0xFFFFFFF5) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<commit_msg>Call WriteConsoleW on Windows<commit_after>#![cfg(windows)]

extern crate winapi;
extern crate kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    input: Receiver<u16>,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let rx = Screen::spawn_input_thread(conin as usize);
        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            input: rx,
            conout: conout,
        }
    }

    // We have to take the conin handle as a usize instead of a *mut c_void in order to avoid a
    // lecture from the compiler about how the latter type cannot be safely sent between threads.
    // I'm not sure if a better solution exists at this time.
    fn spawn_input_thread(conin: usize) -> Receiver<u16> {
        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            loop {
                let conin = conin as *mut c_void;
                let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
                let mut chars_read: DWORD = 0;
                win32!(ReadFile(conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));
                for i in 0..chars_read as usize {
                    tx.send(buf[i]).unwrap();
                }
            }
        });

        rx
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in 0..self.height {
            self.write(&blank_line);
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut chars_written: DWORD = 0;
        let chars_to_write = s.chars().count() as DWORD;
        win32!(WriteConsoleW(self.conout, Screen::to_wide_char(s), chars_to_write, &mut chars_written as LPDWORD, ptr::null_mut()));
    }

    fn to_wide_char(s: &str) -> PVOID {
        let mut ret = Vec::with_capacity(5001);
        unsafe {
            let buf = ret.as_mut_ptr();
            let _ = MultiByteToWideChar(CP_UTF8, 0, s.as_ptr() as *const i8, s.len() as i32, buf, 2500);
        }
        ret.as_ptr() as PVOID
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const WHITE_ON_RED: WORD = BACKGROUND_RED as WORD;
        self.set_colors(WHITE_ON_RED);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_red(&mut self, s: &str) {
        let orig = self.original_colors;
        const RED_ON_BLACK: WORD = FOREGROUND_RED as WORD;
        self.set_colors(RED_ON_BLACK);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.input.try_recv() {
            ret.push(Screen::translate_byte(byte));
        }
        if ret.is_empty() {
            let byte = self.input.recv().unwrap();
            ret.push(Screen::translate_byte(byte));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 9 {
            Tab
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conout: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conout, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    // AppVeyor builds run without a console, making this test impossible.
    if option_env!("APPVEYOR").is_some() {
        // TODO: It should be made obvious from the output that this test was skipped
        return;
    }
    let conout = unsafe { kernel32::GetStdHandle(0xFFFFFFF5) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<|endoftext|>