<commit_before>use color::PuyoColor;
use field::{self, BitField, FieldHeight};

pub struct CoreField {
    field: BitField,
    height: [i16; 8],
}

impl CoreField {
    pub fn new() -> CoreField {
        CoreField {
            field: BitField::new(),
            height: [0; 8],
        }
    }

    pub fn from_str(s: &str) -> CoreField {
        let mut cf = CoreField {
            field: BitField::from_str(s),
            height: [0; 8],
        };

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. 15 {
                if cf.is_empty(x, y) {
                    cf.height[x] = (y - 1) as i16;
                    break
                }
            }
        }

        cf
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        self.field.color(x, y)
    }

    pub fn height(&self, x: usize) -> usize {
        self.height[x] as usize
    }

    pub fn is_color(&self, x: usize, y: usize, c: PuyoColor) -> bool {
        self.field.is_color(x, y, c)
    }

    pub fn is_normal_color(&self, x: usize, y: usize) -> bool {
        self.field.is_normal_color(x, y)
    }

    pub fn is_empty(&self, x: usize, y: usize) -> bool {
        self.field.is_empty(x, y)
    }

    pub fn field(&self) -> &BitField {
        &self.field
    }

    pub fn is_connected(&self, x: usize, y: usize) -> bool {
        self.field.is_connected(x, y)
    }

    pub fn count_connected_max4(&self, x: usize, y: usize) -> usize {
        self.field.count_connected_max4(x, y)
    }

    pub fn count_connected_max4_with_color(&self, x: usize, y: usize, c: PuyoColor) -> usize {
        self.field.count_connected_max4_with_color(x, y, c)
    }
}

impl FieldHeight for CoreField {
    fn height(&self, x: usize) -> usize {
        CoreField::height(self, x)
    }
}

#[cfg(test)]
mod tests {
    use super::CoreField;
    use color::PuyoColor;
    use field;

    #[test]
    fn test_constructor() {
        let cf = CoreField::new();

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. field::HEIGHT + 1 {
                assert!(cf.is_empty(x, y));
                assert!(cf.is_color(x, y, PuyoColor::EMPTY));
                assert_eq!(PuyoColor::EMPTY, cf.color(x, y));
            }
        }

        for x in 1 .. field::WIDTH + 1 {
            assert_eq!(0, cf.height(x));
        }
    }

    #[test]
    fn test_from_str() {
        let cf = CoreField::from_str(concat!(
            "R.....",
            "RRRB.."));

        assert_eq!(PuyoColor::WALL, cf.color(0, 1));
        assert_eq!(PuyoColor::RED, cf.color(1, 1));
        assert_eq!(PuyoColor::RED, cf.color(2, 1));
        assert_eq!(PuyoColor::RED, cf.color(3, 1));
        assert_eq!(PuyoColor::BLUE, cf.color(4, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(5, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(6, 1));
        assert_eq!(PuyoColor::WALL, cf.color(7, 1));

        assert_eq!(2, cf.height(1));
        assert_eq!(1, cf.height(2));
        assert_eq!(1, cf.height(3));
        assert_eq!(1, cf.height(4));
        assert_eq!(0, cf.height(5));
        assert_eq!(0, cf.height(6));
    }
}
<commit_msg>Add CoreField::drop_column_puyo_list<commit_after>use color::PuyoColor;
use column_puyo_list::ColumnPuyoList;
use field::{self, BitField, FieldHeight};
use std;

#[derive(Clone, Debug, PartialEq)]
pub struct CoreField {
    field: BitField,
    height: [i16; 8],
}

impl CoreField {
    pub fn new() -> CoreField {
        CoreField {
            field: BitField::new(),
            height: [0; 8],
        }
    }

    pub fn from_str(s: &str) -> CoreField {
        let mut cf = CoreField {
            field: BitField::from_str(s),
            height: [0; 8],
        };

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. 15 {
                if cf.is_empty(x, y) {
                    cf.height[x] = (y - 1) as i16;
                    break
                }
            }
        }

        cf
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        self.field.color(x, y)
    }

    pub fn height(&self, x: usize) -> usize {
        self.height[x] as usize
    }

    pub fn is_color(&self, x: usize, y: usize, c: PuyoColor) -> bool {
        self.field.is_color(x, y, c)
    }

    pub fn is_normal_color(&self, x: usize, y: usize) -> bool {
        self.field.is_normal_color(x, y)
    }

    pub fn is_empty(&self, x: usize, y: usize) -> bool {
        self.field.is_empty(x, y)
    }

    pub fn field(&self) -> &BitField {
        &self.field
    }

    pub fn is_connected(&self, x: usize, y: usize) -> bool {
        self.field.is_connected(x, y)
    }

    pub fn count_connected_max4(&self, x: usize, y: usize) -> usize {
        self.field.count_connected_max4(x, y)
    }

    pub fn count_connected_max4_with_color(&self, x: usize, y: usize, c: PuyoColor) -> usize {
        self.field.count_connected_max4_with_color(x, y, c)
    }

    pub fn drop_puyo_on_with_max_height(&mut self, x: usize, c: PuyoColor, max_height: usize) -> bool {
        debug_assert!(c != PuyoColor::EMPTY);
        debug_assert!(max_height <= 14);

        if self.height(x) >= std::cmp::min(13, max_height) {
            return false;
        }

        debug_assert!(self.color(x, self.height(x) + 1) == PuyoColor::EMPTY,
                      "x={} max_height={}", x, max_height);

        self.height[x] += 1;
        self.field.set_color(x, self.height[x] as usize, c);

        true
    }

    pub fn drop_column_puyo_list(&mut self, cpl: &ColumnPuyoList) -> bool {
        self.drop_column_puyo_list_with_max_height(cpl, 13)
    }

    pub fn drop_column_puyo_list_with_max_height(&mut self, cpl: &ColumnPuyoList, max_height: usize) -> bool {
        // check size
        for x in 1..7 {
            if self.height(x) + cpl.size_on(x) > max_height {
                return false;
            }
        }

        for x in 1..7 {
            let s = cpl.size_on(x);
            for i in 0..s {
                self.height[x] += 1;
                let c = cpl.get(x, i);
                let h = self.height(x);
                self.field.set_color(x, h, c);
            }
        }

        true
    }
}

impl FieldHeight for CoreField {
    fn height(&self, x: usize) -> usize {
        CoreField::height(self, x)
    }
}

#[cfg(test)]
mod tests {
    use super::CoreField;
    use color::PuyoColor;
    use column_puyo_list::ColumnPuyoList;
    use field;

    #[test]
    fn test_constructor() {
        let cf = CoreField::new();

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. field::HEIGHT + 1 {
                assert!(cf.is_empty(x, y));
                assert!(cf.is_color(x, y, PuyoColor::EMPTY));
                assert_eq!(PuyoColor::EMPTY, cf.color(x, y));
            }
        }

        for x in 1 .. field::WIDTH + 1 {
            assert_eq!(0, cf.height(x));
        }
    }

    #[test]
    fn test_from_str() {
        let cf = CoreField::from_str(concat!(
            "R.....",
            "RRRB.."));

        assert_eq!(PuyoColor::WALL, cf.color(0, 1));
        assert_eq!(PuyoColor::RED, cf.color(1, 1));
        assert_eq!(PuyoColor::RED, cf.color(2, 1));
        assert_eq!(PuyoColor::RED, cf.color(3, 1));
        assert_eq!(PuyoColor::BLUE, cf.color(4, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(5, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(6, 1));
        assert_eq!(PuyoColor::WALL, cf.color(7, 1));

        assert_eq!(2, cf.height(1));
        assert_eq!(1, cf.height(2));
        assert_eq!(1, cf.height(3));
        assert_eq!(1, cf.height(4));
        assert_eq!(0, cf.height(5));
        assert_eq!(0, cf.height(6));
    }

    #[test]
    fn test_drop_puyo_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert!(cf.drop_puyo_on_with_max_height(3, PuyoColor::BLUE, 13));
        assert!(cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(6, PuyoColor::BLUE, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_drop_column_puyo_list_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        let mut cpl = ColumnPuyoList::new();
        assert!(cpl.add(3, PuyoColor::BLUE));
        assert!(cpl.add(4, PuyoColor::BLUE));
        assert!(cf.drop_column_puyo_list_with_max_height(&cpl, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }
}
<|endoftext|>


<commit_before>extern crate postgres;
extern crate chrono;

#[cfg(test)]
mod tests;

use postgres::{Connection, SslMode, types};
use std::io::{self, Read};

#[derive(PartialEq, Debug)]
pub enum Align {
    Left,
    Right,
    Center,
}

#[allow(dead_code)]
#[derive(PartialEq, Debug)]
pub enum Color {
    White,
    BoldWhite,
    BoldRed,
    BoldGreen,
    BoldBlue,
}

struct TableDesc {
    names:  Vec<String>,
    types:  Vec<types::Type>,
    widths: Vec<usize>,
    data:   Vec<Vec<String>>,
}

impl TableDesc {
    fn new() -> TableDesc {
        TableDesc {
            names:  Vec::new(),
            types:  Vec::new(),
            widths: Vec::new(),
            data:   Vec::new(),
        }
    }

    fn parse_result(&self, column: &postgres::rows::Row, colpos: usize) -> String {
        let val: String = match self.types[colpos] {
            types::Type::Text | types::Type::Varchar => column.get(colpos),
            types::Type::Bool => {
                let tmpbool: bool = column.get(colpos);
                match tmpbool {
                    true  => String::from("true"),
                    false => String::from("false"),
                }
            },
            types::Type::Int2 | types::Type::Int4 => {
                let tmpint: i32 = column.get(colpos);
                tmpint.to_string()
            },
            types::Type::Int8 => {
                let tmpint: i64 = column.get(colpos);
                tmpint.to_string()
            },
            types::Type::Float4 => {
                let tmpflt: f32 = column.get(colpos);
                tmpflt.to_string()
            },
            types::Type::Float8 => {
                let tmpflt: f64 = column.get(colpos);
                tmpflt.to_string()
            },
            types::Type::Timestamp => {
                let tmpdate: chrono::NaiveDateTime = column.get(colpos);
                tmpdate.format("%Y-%m-%d %H:%M:%s").to_string()
            },
            types::Type::TimestampTZ => {
                let tmpdate: chrono::DateTime<chrono::UTC> = column.get(colpos);
                tmpdate.format("%Y-%m-%d %H:%M:%s").to_string()
            },
            types::Type::Date => {
                let tmpdate: chrono::NaiveDate = column.get(colpos);
                tmpdate.format("%Y-%m-%d").to_string()
            },
            _ => String::from(""),
        };

        val
    }

    fn append(&mut self, row: &postgres::rows::Row) {
        let mut colvals: Vec<String> = Vec::new();

        for i in 0..row.len() {
            let ret = row.get_bytes(i);
            let col = match ret.is_some() {
                true    => self.parse_result(&row, i),
                false   => String::from(""),
            };

            self.widths[i] = match col.len() > self.widths[i] {
                true    => col.len(),
                false   => self.widths[i]
            };

            colvals.push(col);
        }

        self.data.push(colvals);
    }

    fn print_row(&self, rowdata: &Vec<String>, is_header: bool) {
        for (i, col) in rowdata.iter().enumerate() {
            if i > 0 {
                print!("{}", TableDesc::color_text("|", Color::BoldWhite));
            }

            match is_header {
                false   => print!(" {} ", TableDesc::format_field(&col,
                                                            self.widths[i],
                                                            TableDesc::get_alignment(&self.types[i]))),
                true    => print!(" {} ", TableDesc::color_text(&TableDesc::format_field(&col,
                                                                             self.widths[i],
                                                                             Align::Center),
                                                          Color::BoldWhite)),
            };
        }

        println!("");

        match is_header {
            false   => {},
            true    => {
                for (i, col) in self.widths.iter().enumerate() {
                    if i > 0 {
                        print!("{}", TableDesc::color_text("+", Color::BoldWhite));
                    }

                    print!("{}", TableDesc::color_text(&TableDesc::pad_gen(col+2, "-"), Color::BoldWhite));
                }

                println!("");
            },
        };

    }

    fn print(&self) {
        self.print_row(&self.names, true);
        for rowdata in &self.data {
            self.print_row(&rowdata, false);
        }
    }
}

/* public functions, for string formatting, etc. */
impl TableDesc {
    pub fn get_alignment(coltype: &types::Type) -> Align {
        match coltype {
            &types::Type::Int2          => Align::Right,
            &types::Type::Int4          => Align::Right,
            &types::Type::Int8          => Align::Right,
            &types::Type::Float4        => Align::Right,
            &types::Type::Float8        => Align::Right,
            &types::Type::Date          => Align::Right,
            &types::Type::Timestamp     => Align::Right,
            &types::Type::TimestampTZ   => Align::Right,
            _                           => Align::Left,
        }
    }

    pub fn pad_gen(len: usize, pad: &str) -> String {
        let mut padstr = String::from("");

        for _ in 0..len {
            padstr = padstr + pad;
        }

        padstr
    }

    pub fn format_field(column: &str, width: usize, align: Align) -> String {
        let padlen: usize = width - column.len();
        let extra: usize = padlen % 2;

        let ret: String = match align {
            Align::Right    => { format!("{}{}", TableDesc::pad_gen(padlen, " "), column) },
            Align::Left     => { format!("{}{}", column, TableDesc::pad_gen(padlen, " ")) },
            Align::Center   => { format!("{}{}{}", TableDesc::pad_gen(padlen/2, " "), column,
                                                   TableDesc::pad_gen((padlen/2)+extra, " ")) },
        };

        ret
    }

    pub fn color_text(text: &str, color: Color) -> String {
        let clrstr = match color {
            Color::White       => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[37m", text)        },
            Color::BoldWhite   => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[37m", text) },
            Color::BoldRed     => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[31m", text) },
            Color::BoldGreen   => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[32m", text) },
            Color::BoldBlue    => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[34m", text) },
        };

        clrstr
    }
}

fn main() {
    let mut buf = String::new();
    let mut tdesc = TableDesc::new();
    let mut args = std::env::args();

    if args.len() == 1 {
        println!("{} {}", TableDesc::color_text("error:", Color::BoldRed),
                          TableDesc::color_text("a DBURI is required!", Color::BoldWhite));
        println!("{} cat file.sql | first [DBURI]", TableDesc::color_text("usage:", Color::BoldBlue));
        std::process::exit(1);
    }

    let connstr: String = args.nth(1).unwrap();
    io::stdin().read_to_string(&mut buf);

    let conn = Connection::connect(&connstr as &str, SslMode::None).unwrap();
    let res = &conn.query(&mut buf, &[]).unwrap();

    for col in res.columns() {
        let colname = String::from(col.name());
        tdesc.widths.push(colname.len());
        tdesc.names.push(colname);
        tdesc.types.push(col.type_().clone());
    }

    for row in res.iter() {
        tdesc.append(&row);
    }

    tdesc.print();
}
<commit_msg>move the adding of a column into the class, too<commit_after>extern crate postgres;
extern crate chrono;

#[cfg(test)]
mod tests;

use postgres::{Connection, SslMode, types};
use std::io::{self, Read};

#[derive(PartialEq, Debug)]
pub enum Align {
    Left,
    Right,
    Center,
}

#[allow(dead_code)]
#[derive(PartialEq, Debug)]
pub enum Color {
    White,
    BoldWhite,
    BoldRed,
    BoldGreen,
    BoldBlue,
}

struct TableDesc {
    names:  Vec<String>,
    types:  Vec<types::Type>,
    widths: Vec<usize>,
    data:   Vec<Vec<String>>,
}

impl TableDesc {
    fn new() -> TableDesc {
        TableDesc {
            names:  Vec::new(),
            types:  Vec::new(),
            widths: Vec::new(),
            data:   Vec::new(),
        }
    }

    fn register_column(&mut self, column: &postgres::stmt::Column) {
        let colname = String::from(column.name());

        self.widths.push(colname.len());
        self.names.push(colname);
        self.types.push(column.type_().clone());
    }

    fn parse_result(&self, column: &postgres::rows::Row, colpos: usize) -> String {
        let val: String = match self.types[colpos] {
            types::Type::Text | types::Type::Varchar => column.get(colpos),
            types::Type::Bool => {
                let tmpbool: bool = column.get(colpos);
                match tmpbool {
                    true  => String::from("true"),
                    false => String::from("false"),
                }
            },
            types::Type::Int2 | types::Type::Int4 => {
                let tmpint: i32 = column.get(colpos);
                tmpint.to_string()
            },
            types::Type::Int8 => {
                let tmpint: i64 = column.get(colpos);
                tmpint.to_string()
            },
            types::Type::Float4 => {
                let tmpflt: f32 = column.get(colpos);
                tmpflt.to_string()
            },
            types::Type::Float8 => {
                let tmpflt: f64 = column.get(colpos);
                tmpflt.to_string()
            },
            types::Type::Timestamp => {
                let tmpdate: chrono::NaiveDateTime = column.get(colpos);
                tmpdate.format("%Y-%m-%d %H:%M:%s").to_string()
            },
            types::Type::TimestampTZ => {
                let tmpdate: chrono::DateTime<chrono::UTC> = column.get(colpos);
                tmpdate.format("%Y-%m-%d %H:%M:%s").to_string()
            },
            types::Type::Date => {
                let tmpdate: chrono::NaiveDate = column.get(colpos);
                tmpdate.format("%Y-%m-%d").to_string()
            },
            _ => String::from(""),
        };

        val
    }

    fn append(&mut self, row: &postgres::rows::Row) {
        let mut colvals: Vec<String> = Vec::new();

        for i in 0..row.len() {
            let ret = row.get_bytes(i);
            let col = match ret.is_some() {
                true    => self.parse_result(&row, i),
                false   => String::from(""),
            };

            self.widths[i] = match col.len() > self.widths[i] {
                true    => col.len(),
                false   => self.widths[i]
            };

            colvals.push(col);
        }

        self.data.push(colvals);
    }

    fn print_row(&self, rowdata: &Vec<String>, is_header: bool) {
        for (i, col) in rowdata.iter().enumerate() {
            if i > 0 {
                print!("{}", TableDesc::color_text("|", Color::BoldWhite));
            }

            match is_header {
                false   => print!(" {} ", TableDesc::format_field(&col,
                                                            self.widths[i],
                                                            TableDesc::get_alignment(&self.types[i]))),
                true    => print!(" {} ", TableDesc::color_text(&TableDesc::format_field(&col,
                                                                             self.widths[i],
                                                                             Align::Center),
                                                          Color::BoldWhite)),
            };
        }

        println!("");

        match is_header {
            false   => {},
            true    => {
                for (i, col) in self.widths.iter().enumerate() {
                    if i > 0 {
                        print!("{}", TableDesc::color_text("+", Color::BoldWhite));
                    }

                    print!("{}", TableDesc::color_text(&TableDesc::pad_gen(col+2, "-"), Color::BoldWhite));
                }

                println!("");
            },
        };

    }

    fn print(&self) {
        self.print_row(&self.names, true);
        for rowdata in &self.data {
            self.print_row(&rowdata, false);
        }
    }
}

/* public functions, for string formatting, etc. */
impl TableDesc {
    pub fn get_alignment(coltype: &types::Type) -> Align {
        match coltype {
            &types::Type::Int2          => Align::Right,
            &types::Type::Int4          => Align::Right,
            &types::Type::Int8          => Align::Right,
            &types::Type::Float4        => Align::Right,
            &types::Type::Float8        => Align::Right,
            &types::Type::Date          => Align::Right,
            &types::Type::Timestamp     => Align::Right,
            &types::Type::TimestampTZ   => Align::Right,
            _                           => Align::Left,
        }
    }

    pub fn pad_gen(len: usize, pad: &str) -> String {
        let mut padstr = String::from("");

        for _ in 0..len {
            padstr = padstr + pad;
        }

        padstr
    }

    pub fn format_field(column: &str, width: usize, align: Align) -> String {
        let padlen: usize = width - column.len();
        let extra: usize = padlen % 2;

        let ret: String = match align {
            Align::Right    => { format!("{}{}", TableDesc::pad_gen(padlen, " "), column) },
            Align::Left     => { format!("{}{}", column, TableDesc::pad_gen(padlen, " ")) },
            Align::Center   => { format!("{}{}{}", TableDesc::pad_gen(padlen/2, " "), column,
                                                   TableDesc::pad_gen((padlen/2)+extra, " ")) },
        };

        ret
    }

    pub fn color_text(text: &str, color: Color) -> String {
        let clrstr = match color {
            Color::White       => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[37m", text)        },
            Color::BoldWhite   => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[37m", text) },
            Color::BoldRed     => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[31m", text) },
            Color::BoldGreen   => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[32m", text) },
            Color::BoldBlue    => { format!("{}{}\x1B[33m\x1B[0m", "\x1B[33m\x1B[1m\x1B[33m\x1B[34m", text) },
        };

        clrstr
    }
}

fn main() {
    let mut buf = String::new();
    let mut tdesc = TableDesc::new();
    let mut args = std::env::args();

    if args.len() == 1 {
        println!("{} {}", TableDesc::color_text("error:", Color::BoldRed),
                          TableDesc::color_text("a DBURI is required!", Color::BoldWhite));
        println!("{} cat file.sql | first [DBURI]", TableDesc::color_text("usage:", Color::BoldBlue));
        std::process::exit(1);
    }

    let connstr: String = args.nth(1).unwrap();
    io::stdin().read_to_string(&mut buf);

    let conn = Connection::connect(&connstr as &str, SslMode::None).unwrap();
    let res = &conn.query(&mut buf, &[]).unwrap();

    for col in res.columns() {
        tdesc.register_column(&col);
    }

    for row in res.iter() {
        tdesc.append(&row);
    }

    tdesc.print();
}
<|endoftext|>


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

use cmp;
use mem;
use ptr;

/// Rotation is much faster if it has access to a little bit of memory. This
/// union provides a RawVec-like interface, but to a fixed-size stack buffer.
#[allow(unions_with_drop_fields)]
union RawArray<T> {
    /// Ensure this is appropriately aligned for T, and is big
    /// enough for two elements even if T is enormous.
    typed: [T; 2],
    /// For normally-sized types, especially things like u8, having more
    /// than 2 in the buffer is necessary for usefulness, so pad it out
    /// enough to be helpful, but not so big as to risk overflow.
    _extra: [usize; 32],
}

impl<T> RawArray<T> {
    fn new() -> Self {
        unsafe { mem::uninitialized() }
    }
    fn ptr(&self) -> *mut T {
        unsafe { &self.typed as *const T as *mut T }
    }
    fn cap() -> usize {
        if mem::size_of::<T>() == 0 {
            usize::max_value()
        } else {
            mem::size_of::<Self>() / mem::size_of::<T>()
        }
    }
}

/// Rotates the range `[mid-left, mid+right)` such that the element at `mid`
/// becomes the first element.  Equivalently, rotates the range `left`
/// elements to the left or `right` elements to the right.
///
/// # Safety
///
/// The specified range must be valid for reading and writing.
///
/// # Algorithm
///
/// For longer rotations, swap the left-most `delta = min(left, right)`
/// elements with the right-most `delta` elements.  LLVM vectorizes this,
/// which is profitable as we only reach this step for a "large enough"
/// rotation.  Doing this puts `delta` elements on the larger side into the
/// correct position, leaving a smaller rotate problem.  Demonstration:
///
/// ```text
/// [ 6 7 8 9 10 11 12 13 . 1 2 3 4 5 ]
/// 1 2 3 4 5 [ 11 12 13 . 6 7 8 9 10 ]
/// 1 2 3 4 5 [ 8 9 10 . 6 7 ] 11 12 13
/// 1 2 3 4 5 6 7 [ 10 . 8 9 ] 11 12 13
/// 1 2 3 4 5 6 7 [ 9 . 8 ] 10 11 12 13
/// 1 2 3 4 5 6 7 8 [ . ] 9 10 11 12 13
/// ```
///
/// Once the rotation is small enough, copy some elements into a stack
/// buffer, `memmove` the others, and move the ones back from the buffer.
pub unsafe fn ptr_rotate<T>(mut left: usize, mid: *mut T, mut right: usize) {
    loop {
        let delta = cmp::min(left, right);
        if delta <= RawArray::<T>::cap() {
            // We will always hit this immediately for ZST.
            break;
        }

        ptr::swap_nonoverlapping(
            mid.sub(left),
            mid.add(right - delta),
            delta);

        if left <= right {
            right -= delta;
        } else {
            left -= delta;
        }
    }

    let rawarray = RawArray::new();
    let buf = rawarray.ptr();

    let dim = mid.sub(left).add(right);
    if left <= right {
        ptr::copy_nonoverlapping(mid.sub(left), buf, left);
        ptr::copy(mid, mid.sub(left), right);
        ptr::copy_nonoverlapping(buf, dim, left);
    }
    else {
        ptr::copy_nonoverlapping(mid, buf, right);
        ptr::copy(mid.sub(left), dim, left);
        ptr::copy_nonoverlapping(buf, mid.sub(left), right);
    }
}
<commit_msg>use MaybeUninit in core::slice::rotate<commit_after>// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use cmp;
use mem::{self, MaybeUninit};
use ptr;

/// Rotation is much faster if it has access to a little bit of memory. This
/// union provides a RawVec-like interface, but to a fixed-size stack buffer.
#[allow(unions_with_drop_fields)]
union RawArray<T> {
    /// Ensure this is appropriately aligned for T, and is big
    /// enough for two elements even if T is enormous.
    typed: [T; 2],
    /// For normally-sized types, especially things like u8, having more
    /// than 2 in the buffer is necessary for usefulness, so pad it out
    /// enough to be helpful, but not so big as to risk overflow.
    _extra: [usize; 32],
}

impl<T> RawArray<T> {
    fn cap() -> usize {
        if mem::size_of::<T>() == 0 {
            usize::max_value()
        } else {
            mem::size_of::<Self>() / mem::size_of::<T>()
        }
    }
}

/// Rotates the range `[mid-left, mid+right)` such that the element at `mid`
/// becomes the first element.  Equivalently, rotates the range `left`
/// elements to the left or `right` elements to the right.
///
/// # Safety
///
/// The specified range must be valid for reading and writing.
///
/// # Algorithm
///
/// For longer rotations, swap the left-most `delta = min(left, right)`
/// elements with the right-most `delta` elements.  LLVM vectorizes this,
/// which is profitable as we only reach this step for a "large enough"
/// rotation.  Doing this puts `delta` elements on the larger side into the
/// correct position, leaving a smaller rotate problem.  Demonstration:
///
/// ```text
/// [ 6 7 8 9 10 11 12 13 . 1 2 3 4 5 ]
/// 1 2 3 4 5 [ 11 12 13 . 6 7 8 9 10 ]
/// 1 2 3 4 5 [ 8 9 10 . 6 7 ] 11 12 13
/// 1 2 3 4 5 6 7 [ 10 . 8 9 ] 11 12 13
/// 1 2 3 4 5 6 7 [ 9 . 8 ] 10 11 12 13
/// 1 2 3 4 5 6 7 8 [ . ] 9 10 11 12 13
/// ```
///
/// Once the rotation is small enough, copy some elements into a stack
/// buffer, `memmove` the others, and move the ones back from the buffer.
pub unsafe fn ptr_rotate<T>(mut left: usize, mid: *mut T, mut right: usize) {
    loop {
        let delta = cmp::min(left, right);
        if delta <= RawArray::<T>::cap() {
            // We will always hit this immediately for ZST.
            break;
        }

        ptr::swap_nonoverlapping(
            mid.sub(left),
            mid.add(right - delta),
            delta);

        if left <= right {
            right -= delta;
        } else {
            left -= delta;
        }
    }

    let mut rawarray = MaybeUninit::<RawArray<T>>::uninitialized();
    let buf = &mut (*rawarray.as_mut_ptr()).typed as *mut [T; 2] as *mut T;

    let dim = mid.sub(left).add(right);
    if left <= right {
        ptr::copy_nonoverlapping(mid.sub(left), buf, left);
        ptr::copy(mid, mid.sub(left), right);
        ptr::copy_nonoverlapping(buf, dim, left);
    }
    else {
        ptr::copy_nonoverlapping(mid, buf, right);
        ptr::copy(mid.sub(left), dim, left);
        ptr::copy_nonoverlapping(buf, mid.sub(left), right);
    }
}
<|endoftext|>


<commit_before>#![feature(no_std,lang_items,core)]
#![no_std]

#![crate_type = "staticlib"]
#![crate_name = "rustcode"]

// use libcore
#[macro_use]
extern crate core;
extern crate rlibc;

// kernel module imports
use window::{Window, Color};

use heap::{init};

// kernel module declarations
#[macro_use]
mod debug; // debug must be first, since it defines macros the others need
mod bare_bones;

mod machine;

mod vga;
mod window;

mod heap;
mod rust_alloc;

// This is the entry point to the kernel. It is the first rust code that runs.
#[no_mangle]
pub fn kernel_main() {
    // print new line after "x"
    printf! ("\n");

    // clear the screen
    Window::clear_screen();

    // draw a test window to let the world know we're alive
    draw_window();

    // initialize the heap
    printf! ("Going to init heap\n");
    heap::init();
    printf! ("Heap inited\n");
}

fn draw_window() {
    let mut w0 = Window::new(40, 10, (4, 10));

    w0.set_bg_color(Color::LightBlue);
    w0.paint();

    w0.set_cursor((0, 0));
    w0.set_bg_color(Color::LightGreen);
    w0.set_fg_color(Color::Red);
    w0.put_str("Hello World!");
}
<commit_msg>Minor comment<commit_after>#![feature(no_std,lang_items,core)]
#![no_std]

#![crate_type = "staticlib"]
#![crate_name = "rustcode"]

// use libcore
#[macro_use]
extern crate core;
extern crate rlibc;

// kernel module imports
use window::{Window, Color};

use heap::{init};

// kernel module declarations
#[macro_use]
mod debug; // debug must be first, since it defines macros the others need
mod bare_bones;

mod machine;

mod vga;
mod window;

mod heap;
mod rust_alloc;

// This is the entry point to the kernel. It is the first rust code that runs.
#[no_mangle]
pub fn kernel_main() {
    // print new line after "x"
    printf! ("\n");

    // clear the screen
    Window::clear_screen();

    // draw a test window to let the world know we're alive
    draw_window();

    // initialize the heap
    printf! ("Going to init heap\n");
    heap::init();
    printf! ("Heap inited\n");
}

// Draw a test window
fn draw_window() {
    let mut w0 = Window::new(40, 10, (4, 10));

    w0.set_bg_color(Color::LightBlue);
    w0.paint();

    w0.set_cursor((0, 0));
    w0.set_bg_color(Color::LightGreen);
    w0.set_fg_color(Color::Red);
    w0.put_str("Hello World!");
}
<|endoftext|>


<commit_before>#![crate_name = "kernel"]
#![crate_type = "staticlib"]
#![no_std]
#![feature(asm, lang_items)]
#![feature(core)]

extern crate core;
extern crate rlibc;

#[path = "arch/x86/"]
pub mod platform {
	pub mod vga;
	pub mod cpu;
	pub mod mmu;
	mod io;
	pub mod keyboard;
}

pub mod kernel {
	pub mod main;
	pub mod interrupts;
	mod stdio;
	mod keyboard;
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
<commit_msg>Fix compilation<commit_after>#![crate_name = "kernel"]
#![crate_type = "staticlib"]
#![no_std]
#![feature(asm, lang_items)]
#![feature(core)]

extern crate core;
extern crate rlibc;

#[path = "arch/x86/"]
pub mod platform {
	pub mod vga;
	pub mod cpu;
	pub mod mmu;
	mod io;
	pub mod keyboard;
}

pub mod kernel {
	pub mod main;
	pub mod interrupts;
	mod stdio;
	mod keyboard;
}

// Remove this when https://github.com/rust-lang/rust/issues/21827 is solved
mod std {
    pub mod option {
        pub use core::option::*;
    }
    pub mod iter {
        pub use core::iter::*;
    }
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
<|endoftext|>


<commit_before><commit_msg>Handle --system-libs with MSVC.<commit_after><|endoftext|>


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

use mio::{Event, Evented, Events, Poll, PollOpt, Ready, Token};
use std::io;
use std::rc::Rc;
use std::time::Duration;
use slab::Slab;

const TAG: &'static str = "Selector";

pub trait EventHandler {
    fn on_ready(&self, selector: &mut Selector, event: Event);
}

impl<F> EventHandler for F
where
    F: Fn(&mut Selector, Event),
{
    fn on_ready(&self, selector: &mut Selector, event: Event) {
        self(selector, event);
    }
}

pub struct Selector {
    poll: Poll,
    handlers: Slab<Rc<EventHandler>>,
    // tokens to be removed after all the current poll events are executed
    tokens_to_remove: Vec<Token>,
}

impl Selector {
    pub fn new() -> io::Result<Self> {
        Ok(Self {
            poll: Poll::new()?,
            handlers: Slab::with_capacity(1024),
            tokens_to_remove: Vec::new(),
        })
    }

    pub fn register<E, H>(
        &mut self,
        handle: &E,
        handler: H,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<Token>
    where
        E: Evented + ?Sized,
        H: EventHandler + 'static,
    {
        let token = Token(self.handlers.insert(Rc::new(handler)));
        self.poll.register(handle, token, interest, opts)?;
        Ok(token)
    }

    pub fn reregister<E>(
        &mut self,
        handle: &E,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()>
    where
        E: Evented + ?Sized,
    {
        self.poll.reregister(handle, token, interest, opts)
    }

    pub fn deregister<E>(&mut self, handle: &E, token: Token) -> io::Result<()>
    where
        E: Evented + ?Sized,
    {
        self.poll.deregister(handle)?;
        // remove them before next poll()
        self.tokens_to_remove.push(token);
        Ok(())
    }

    fn clean_removed_tokens(&mut self) {
        for &token in &self.tokens_to_remove {
            self.handlers.remove(token.0);
        }
        self.tokens_to_remove.clear();
    }

    pub fn poll(&mut self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(events, timeout)
    }

    pub fn run_handlers(&mut self, events: &Events) {
        for event in events {
            debug!(target: TAG, "event={:?}", event);
            let handler = self.handlers
                .get_mut(event.token().0)
                .expect("Token not found")
                .clone();
            handler.on_ready(self, event);
        }

        // remove the tokens marked as removed
        self.clean_removed_tokens();
    }
}
<commit_msg>Do not leak EventHandler if Poll::register() fails<commit_after>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use mio::{Event, Evented, Events, Poll, PollOpt, Ready, Token};
use std::io;
use std::rc::Rc;
use std::time::Duration;
use slab::Slab;

const TAG: &'static str = "Selector";

pub trait EventHandler {
    fn on_ready(&self, selector: &mut Selector, event: Event);
}

impl<F> EventHandler for F
where
    F: Fn(&mut Selector, Event),
{
    fn on_ready(&self, selector: &mut Selector, event: Event) {
        self(selector, event);
    }
}

pub struct Selector {
    poll: Poll,
    handlers: Slab<Rc<EventHandler>>,
    // tokens to be removed after all the current poll events are executed
    tokens_to_remove: Vec<Token>,
}

impl Selector {
    pub fn new() -> io::Result<Self> {
        Ok(Self {
            poll: Poll::new()?,
            handlers: Slab::with_capacity(1024),
            tokens_to_remove: Vec::new(),
        })
    }

    pub fn register<E, H>(
        &mut self,
        handle: &E,
        handler: H,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<Token>
    where
        E: Evented + ?Sized,
        H: EventHandler + 'static,
    {
        let token = Token(self.handlers.insert(Rc::new(handler)));
        if let Err(err) = self.poll.register(handle, token, interest, opts) {
            // remove the token we just added
            self.handlers.remove(token.0);
            Err(err)
        } else {
            Ok(token)
        }
    }

    pub fn reregister<E>(
        &mut self,
        handle: &E,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()>
    where
        E: Evented + ?Sized,
    {
        self.poll.reregister(handle, token, interest, opts)
    }

    pub fn deregister<E>(&mut self, handle: &E, token: Token) -> io::Result<()>
    where
        E: Evented + ?Sized,
    {
        self.poll.deregister(handle)?;
        // remove them before next poll()
        self.tokens_to_remove.push(token);
        Ok(())
    }

    fn clean_removed_tokens(&mut self) {
        for &token in &self.tokens_to_remove {
            self.handlers.remove(token.0);
        }
        self.tokens_to_remove.clear();
    }

    pub fn poll(&mut self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(events, timeout)
    }

    pub fn run_handlers(&mut self, events: &Events) {
        for event in events {
            debug!(target: TAG, "event={:?}", event);
            let handler = self.handlers
                .get_mut(event.token().0)
                .expect("Token not found")
                .clone();
            handler.on_ready(self, event);
        }

        // remove the tokens marked as removed
        self.clean_removed_tokens();
    }
}
<|endoftext|>


<commit_before>use core::marker;
use core::pin::Pin;
use futures_core::future::{FusedFuture, Future};
use futures_core::task::{Context, Poll};

/// Future for the [`pending()`] function.
#[derive(Debug, Clone)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Pending<T> {
    _data: marker::PhantomData<T>,
}

impl<T> FusedFuture for Pending<T> {
    fn is_terminated(&self) -> bool {
        true
    }
}

/// Creates a future which never resolves, representing a computation that never
/// finishes.
///
/// The returned future will forever return [`Poll::Pending`].
///
/// # Examples
///
/// ```ignore
/// # futures::executor::block_on(async {
/// use futures::future;
///
/// let future = future::pending();
/// let () = future.await;
/// unreachable!();
/// # });
/// ```
pub fn pending<T>() -> Pending<T> {
    Pending {
        _data: marker::PhantomData,
    }
}

impl<T> Future for Pending<T> {
    type Output = T;

    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
        Poll::Pending
    }
}

impl<T> Unpin for Pending<T> {
}
<commit_msg>Make Pending<T>'s Clone impl unconditional.<commit_after>use core::marker;
use core::pin::Pin;
use futures_core::future::{FusedFuture, Future};
use futures_core::task::{Context, Poll};

/// Future for the [`pending()`] function.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Pending<T> {
    _data: marker::PhantomData<T>,
}

impl<T> FusedFuture for Pending<T> {
    fn is_terminated(&self) -> bool {
        true
    }
}

/// Creates a future which never resolves, representing a computation that never
/// finishes.
///
/// The returned future will forever return [`Poll::Pending`].
///
/// # Examples
///
/// ```ignore
/// # futures::executor::block_on(async {
/// use futures::future;
///
/// let future = future::pending();
/// let () = future.await;
/// unreachable!();
/// # });
/// ```
pub fn pending<T>() -> Pending<T> {
    Pending {
        _data: marker::PhantomData,
    }
}

impl<T> Future for Pending<T> {
    type Output = T;

    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
        Poll::Pending
    }
}

impl<T> Unpin for Pending<T> {
}

impl<T> Clone for Pending<T> {
    fn clone(&self) -> Self {
        pending()
    }
}
<|endoftext|>


<commit_before>use num::{PrimInt, Signed};
use num::traits::CheckedShr;
use std::mem;
use std::cmp::{min};

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn right_shift_nicely_rounded <T: PrimInt> (input: T, shift: usize)->T {
  let divisor = T::one() << shift;
  let mask = divisor - T::one();
  if (input & mask) << 1 == divisor {
    let shifted = input >> shift;
    shifted + (shifted & T::one())
  } else {
    (input + (divisor >> 1)) >> shift
  }
}

/// Approximately evaluate an integer polynomial at an input in the range [-0.5, 0.5].
///
/// The input is represented as an integer combined with a right-shift size.
/// Each coefficient, except the constant one, must obey coefficient.abs() <= T::max_value() >> shift.
/// The constant coefficient must obey coefficient.abs() <= T::max_value() - (T::max_value() >> shift),
/// i.e. be small enough that you can add one of the other coefficients to it without overflowing.
/// Given these conditions, the result is guaranteed to be strictly within 1 of the ideal result.
/// For instance, if the ideal result was 2.125, this function could return 2 or 3,
/// but if it was 2, this function can only return exactly 2.
pub fn evaluate_polynomial_at_small_input <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->T {
  let half = (T::one() << shift) >> 1;
  assert!(-half <= input && input <= half, "inputs to evaluate_polynomial_at_small_input must be in the range [-0.5, 0.5]");

  if coefficients.len () == 0 {return T::zero()}

  let mut result = T::zero();
  for coefficient in coefficients.iter().skip(1).rev() {
    result = right_shift_nicely_rounded ((result + (*coefficient).into())*input, shift);
  }
  result + coefficients [0].into()
}

/// Translate a polynomial horizontally, letting it take inputs relative to a given input instead of relative to 0.
///
/// This is equivalent to replacing its coefficients with its Taylor coefficients at the given input.
/// This is equivalent to translating the graph *left* by the given input amount.
///
/// For constant polynomials, this is a no-op.
///
/// To avoid overflow, each term, when evaluating at the given input,
/// must obey term.abs() <= T::max_value() >> (coefficients.len() - 1).
/// If this condition is broken, translate_polynomial() returns Err and makes no changes.
pub fn translate_polynomial <T: PrimInt + Signed + CheckedShr> (coefficients: &mut [T], input: T)->Result <(),()> {
  if !safe_to_translate_polynomial_to (coefficients, input, |_| T::max_value()) {return Err (())}
  translate_polynomial_unchecked (coefficients, input) ;
  Ok (())
}

/// Same as translate_polynomial(), but assume no overflow will occur.
///
/// Useful in performance-critical code when you already know there won't be overflow,
/// such as in the range returned by conservative_safe_polynomial_translation_range.
pub fn translate_polynomial_unchecked <T: PrimInt + Signed> (coefficients: &mut [T], input: T) {
  coefficients.reverse();
  for index in 0..coefficients.len() {
    let coefficient = mem::replace (&mut coefficients [index], T::zero());
    for derivative in (1..(index + 1)).rev() {
      coefficients [derivative] = coefficients [derivative]*input + coefficients [derivative - 1]
    }
    coefficients [0] = coefficients [0]*input + coefficient
  }
}

pub fn safe_to_translate_polynomial_to <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], input: T, maximum: MaximumFn)->bool {
  if coefficients.len() == 0 {return true;}
  let mut factor = T::one();
  let input = input.abs();
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  for (power, coefficient) in coefficients.iter().enumerate() {
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    if coefficient == &T::min_value() {return false;}
    let magnitude = coefficient.abs();
    if magnitude > running_maximum {return false;}
    match magnitude.checked_mul (&factor) {
      None => return false,
      Some (term) => if term > running_maximum {return false;},
    }
    if power + 1 < coefficients.len() { match factor.checked_mul (&input) {
      None => return false,
      Some (next_factor) => factor = next_factor,
    }}
  }
  true
}

/// Find the range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to; magnitudes > result aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
pub fn exact_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], maximum: MaximumFn)->T {
  if !safe_to_translate_polynomial_to (coefficients, T::zero(), & maximum) {return -T::one();}
  // pick a min that's definitely legal and a max where max + 1 is definitely illegal
  let mut min = T::zero();
  let mut max = T::max_value();
  while min < max {
    let mid = (min >> 1u32) + (max >> 1u32) + ((min | max) & T::one());
    if safe_to_translate_polynomial_to (coefficients, mid, & maximum) {
      min = mid;
    } else {
      max = mid - T::one();
    }
  }
  min
}

/// Find a range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to.
/// Magnitudes >= result*2 aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
///
/// This function is much faster than exact_safe_polynomial_translation_range, at the cost of being less precise.
pub fn conservative_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: &[T], maximum: MaximumFn)->T {
  if coefficients.len() == 0 {return T::max_value()}
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  let mut result_shift = mem::size_of::<T>()*8 - 2;
  for (power, coefficient) in coefficients.iter().enumerate() {
    let magnitude = coefficient.abs();
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    while magnitude > running_maximum.checked_shr((result_shift*power) as u32).unwrap_or (T::zero()) {
      if result_shift == 0 {return -T::one();}
      result_shift -= 1;
    }
  }
  T::one() << result_shift
}

#[cfg (test)]
mod tests {
  use super::*;
  use num::{Zero, One, FromPrimitive};
  use num::bigint::BigInt;
  use num::rational::{Ratio, BigRational};
  use rand::distributions::Distribution;
  use rand::distributions::range::{Range};
  use rand::{Rng, SeedableRng};

  fn evaluate_polynomial_exactly <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->BigRational
    where BigInt: From <Coefficient> + From <T> {
    let mut result: BigRational = Ratio::zero();
    let input = Ratio::new(BigInt::from (input), BigInt::one() << shift);
    for coefficient in coefficients.iter().rev() {
      result = result*&input + BigInt::from(*coefficient);
    }
    result
  }

  #[test]
  fn test_right_shift_nicely_rounded() {
    let inputs: Vec<(i64, usize, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(right_shift_nicely_rounded (input, shift), result);
      assert_eq!(right_shift_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_evaluate_polynomial_at_small_input() {
    let mut generator =::rand::chacha::ChaChaRng::from_seed ([33; 32]) ;
    for shift in 0..5 {
      let shift = 1 << shift;
      let half = 1i64 << (shift - 1);
      let maximum = i64::max_value() >> shift;
      let constant_maximum = i64::max_value() - maximum;
      let range = Range::new_inclusive (- maximum, maximum) ;
      let constant_range = Range::new_inclusive (- constant_maximum, constant_maximum);
      let mut test_inputs = vec![- half, - half + 1, - 1, 0, 1, half - 1, half];
      if half > 2 {for _ in 0..6 {test_inputs.push (generator.gen_range (- half + 2, half - 1));}}
      for _ in 0..40 {
        let mut coefficients = vec![constant_range.sample (&mut generator)];
        while generator.gen() {coefficients.push (range.sample (&mut generator));}
        for input in test_inputs.iter() {
          let result = evaluate_polynomial_at_small_input (& coefficients,*input, shift);

          let perfect_result = evaluate_polynomial_exactly (& coefficients,*input, shift);
          let difference = Ratio::from_integer (FromPrimitive::from_i64 (result).unwrap()) - perfect_result;
          assert!(difference < Ratio::from_integer (FromPrimitive::from_i64 (1).unwrap()));
        }
      }
    }
  }

  quickcheck! {
    fn quickcheck_safe_translation_is_safe (coefficients_and_maxima: Vec<(i64, i64)>, input: i64)->bool {
      let mut coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let safe = safe_to_translate_polynomial_to(& coefficients, input, maxima);
      if !safe {return true}
      translate_polynomial_unchecked (&mut coefficients, input);
      println!( "{:?}", coefficients);
      safe_to_translate_polynomial_to(& coefficients, 0, maxima)
    }

    fn quickcheck_safe_translation_reverses_correctly (coefficients: Vec<i64>, input: i64)->bool {
      let mut coefficients = coefficients;
      let maxima = |_: usize | i64::max_value();
      if input == i64::min_value () {return true}
      let original_coefficients = coefficients.clone ();
      if !safe_to_translate_polynomial_to(& coefficients, input, maxima) {return true}
      translate_polynomial_unchecked (&mut coefficients, input);
      if !safe_to_translate_polynomial_to(& coefficients, -input, maxima) {return true}
      println!( "{:?}", coefficients);
      translate_polynomial_unchecked (&mut coefficients, -input);
      coefficients == original_coefficients
    }

    fn quickcheck_exact_safe_translation_range_is_safe (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range < 0 || safe_to_translate_polynomial_to (& coefficients, range, maxima)
    }

    fn quickcheck_exact_safe_translation_range_is_maximal (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range == i64::max_value() || !safe_to_translate_polynomial_to (& coefficients, range + 1, maxima)
    }

    fn quickcheck_conservative_safe_translation_range_is_safe (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let exact_range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      let conservative_range = conservative_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", (exact_range, conservative_range));
      conservative_range <= exact_range
    }

    fn quickcheck_conservative_safe_translation_range_is_within_half_maximal (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let exact_range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      let conservative_range = conservative_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", (exact_range, conservative_range));
      conservative_range == exact_range || conservative_range > exact_range >> 1
    }
  }
}
<commit_msg>Fixed some more special cases detected by quickcheck<commit_after>use num::{PrimInt, Signed};
use num::traits::CheckedShr;
use std::mem;
use std::cmp::{min};

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn right_shift_nicely_rounded <T: PrimInt> (input: T, shift: usize)->T {
  let divisor = T::one() << shift;
  let mask = divisor - T::one();
  if (input & mask) << 1 == divisor {
    let shifted = input >> shift;
    shifted + (shifted & T::one())
  } else {
    (input + (divisor >> 1)) >> shift
  }
}

/// Approximately evaluate an integer polynomial at an input in the range [-0.5, 0.5].
///
/// The input is represented as an integer combined with a right-shift size.
/// Each coefficient, except the constant one, must obey coefficient.abs() <= T::max_value() >> shift.
/// The constant coefficient must obey coefficient.abs() <= T::max_value() - (T::max_value() >> shift),
/// i.e. be small enough that you can add one of the other coefficients to it without overflowing.
/// Given these conditions, the result is guaranteed to be strictly within 1 of the ideal result.
/// For instance, if the ideal result was 2.125, this function could return 2 or 3,
/// but if it was 2, this function can only return exactly 2.
pub fn evaluate_polynomial_at_small_input <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->T {
  let half = (T::one() << shift) >> 1;
  assert!(-half <= input && input <= half, "inputs to evaluate_polynomial_at_small_input must be in the range [-0.5, 0.5]");

  if coefficients.len () == 0 {return T::zero()}

  let mut result = T::zero();
  for coefficient in coefficients.iter().skip(1).rev() {
    result = right_shift_nicely_rounded ((result + (*coefficient).into())*input, shift);
  }
  result + coefficients [0].into()
}

/// Translate a polynomial horizontally, letting it take inputs relative to a given input instead of relative to 0.
///
/// This is equivalent to replacing its coefficients with its Taylor coefficients at the given input.
/// This is equivalent to translating the graph *left* by the given input amount.
///
/// For constant polynomials, this is a no-op.
///
/// To avoid overflow, each term, when evaluating at the given input,
/// must obey term.abs() <= T::max_value() >> (coefficients.len() - 1).
/// If this condition is broken, translate_polynomial() returns Err and makes no changes.
pub fn translate_polynomial <T: PrimInt + Signed + CheckedShr> (coefficients: &mut [T], input: T)->Result <(),()> {
  if !safe_to_translate_polynomial_to (coefficients, input, |_| T::max_value()) {return Err (())}
  translate_polynomial_unchecked (coefficients, input) ;
  Ok (())
}

/// Same as translate_polynomial(), but assume no overflow will occur.
///
/// Useful in performance-critical code when you already know there won't be overflow,
/// such as in the range returned by conservative_safe_polynomial_translation_range.
pub fn translate_polynomial_unchecked <T: PrimInt + Signed> (coefficients: &mut [T], input: T) {
  coefficients.reverse();
  for index in 0..coefficients.len() {
    let coefficient = mem::replace (&mut coefficients [index], T::zero());
    for derivative in (1..(index + 1)).rev() {
      coefficients [derivative] = coefficients [derivative]*input + coefficients [derivative - 1]
    }
    coefficients [0] = coefficients [0]*input + coefficient
  }
}

pub fn polynomial_is_within_bounds <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], maximum: MaximumFn)->bool {
  for (power, coefficient) in coefficients.iter().enumerate() {
    if coefficient == &T::min_value() {return false;}
    let magnitude = coefficient.abs();
    if magnitude > maximum (power) {return false;}
  }
  true
}

pub fn safe_to_translate_polynomial_to <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], input: T, maximum: MaximumFn)->bool {
  if coefficients.len() == 0 {return true;}
  if input == T::zero() {return polynomial_is_within_bounds (coefficients, maximum);}
  let mut factor = T::one();
  let input = input.abs();
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  for (power, coefficient) in coefficients.iter().enumerate() {
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    if coefficient == &T::min_value() {return false;}
    let magnitude = coefficient.abs();
    match magnitude.checked_mul (&factor) {
      None => return false,
      Some (term) => if term > running_maximum {return false;},
    }
    if power + 1 < coefficients.len() { match factor.checked_mul (&input) {
      None => return false,
      Some (next_factor) => factor = next_factor,
    }}
  }
  true
}

/// Find the range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to; magnitudes > result aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
pub fn exact_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], maximum: MaximumFn)->T {
  if !polynomial_is_within_bounds (coefficients, & maximum) {return -T::one();}
  // pick a min that's definitely legal and a max where max + 1 is definitely illegal
  let mut min = T::zero();
  let mut max = T::max_value();
  while min < max {
    let mid = (min >> 1u32) + (max >> 1u32) + ((min | max) & T::one());
    if safe_to_translate_polynomial_to (coefficients, mid, & maximum) {
      min = mid;
    } else {
      max = mid - T::one();
    }
  }
  min
}

/// Find a range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to.
/// Magnitudes >= result*2 aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
///
/// This function is much faster than exact_safe_polynomial_translation_range, at the cost of being less precise.
pub fn conservative_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: &[T], maximum: MaximumFn)->T {
  if coefficients.len() == 0 {return T::max_value()}
  if !polynomial_is_within_bounds (coefficients, & maximum) {return -T::one();}
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  let mut result_shift = mem::size_of::<T>()*8 - 2;
  for (power, coefficient) in coefficients.iter().enumerate() {
    let magnitude = coefficient.abs();
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    while magnitude > running_maximum.checked_shr((result_shift*power) as u32).unwrap_or (T::zero()) {
      if result_shift == 0 {return T::zero();}
      result_shift -= 1;
    }
  }
  T::one() << result_shift
}

#[cfg (test)]
mod tests {
  use super::*;
  use num::{Zero, One, FromPrimitive};
  use num::bigint::BigInt;
  use num::rational::{Ratio, BigRational};
  use rand::distributions::Distribution;
  use rand::distributions::range::{Range};
  use rand::{Rng, SeedableRng};

  fn evaluate_polynomial_exactly <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->BigRational
    where BigInt: From <Coefficient> + From <T> {
    let mut result: BigRational = Ratio::zero();
    let input = Ratio::new(BigInt::from (input), BigInt::one() << shift);
    for coefficient in coefficients.iter().rev() {
      result = result*&input + BigInt::from(*coefficient);
    }
    result
  }

  #[test]
  fn test_right_shift_nicely_rounded() {
    let inputs: Vec<(i64, usize, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(right_shift_nicely_rounded (input, shift), result);
      assert_eq!(right_shift_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_evaluate_polynomial_at_small_input() {
    let mut generator =::rand::chacha::ChaChaRng::from_seed ([33; 32]) ;
    for shift in 0..5 {
      let shift = 1 << shift;
      let half = 1i64 << (shift - 1);
      let maximum = i64::max_value() >> shift;
      let constant_maximum = i64::max_value() - maximum;
      let range = Range::new_inclusive (- maximum, maximum) ;
      let constant_range = Range::new_inclusive (- constant_maximum, constant_maximum);
      let mut test_inputs = vec![- half, - half + 1, - 1, 0, 1, half - 1, half];
      if half > 2 {for _ in 0..6 {test_inputs.push (generator.gen_range (- half + 2, half - 1));}}
      for _ in 0..40 {
        let mut coefficients = vec![constant_range.sample (&mut generator)];
        while generator.gen() {coefficients.push (range.sample (&mut generator));}
        for input in test_inputs.iter() {
          let result = evaluate_polynomial_at_small_input (& coefficients,*input, shift);

          let perfect_result = evaluate_polynomial_exactly (& coefficients,*input, shift);
          let difference = Ratio::from_integer (FromPrimitive::from_i64 (result).unwrap()) - perfect_result;
          assert!(difference < Ratio::from_integer (FromPrimitive::from_i64 (1).unwrap()));
        }
      }
    }
  }

  quickcheck! {
    fn quickcheck_safe_translation_is_safe (coefficients_and_maxima: Vec<(i64, i64)>, input: i64)->bool {
      let mut coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let safe = safe_to_translate_polynomial_to(& coefficients, input, maxima);
      if !safe {return true}
      translate_polynomial_unchecked (&mut coefficients, input);
      println!( "{:?}", coefficients);
      polynomial_is_within_bounds (& coefficients, maxima)
    }

    fn quickcheck_safe_translation_reverses_correctly (coefficients: Vec<i64>, input: i64)->bool {
      let mut coefficients = coefficients;
      let maxima = |_: usize | i64::max_value();
      if input == i64::min_value () {return true}
      let original_coefficients = coefficients.clone ();
      if !safe_to_translate_polynomial_to(& coefficients, input, maxima) {return true}
      translate_polynomial_unchecked (&mut coefficients, input);
      if !safe_to_translate_polynomial_to(& coefficients, -input, maxima) {return true}
      println!( "{:?}", coefficients);
      translate_polynomial_unchecked (&mut coefficients, -input);
      coefficients == original_coefficients
    }

    fn quickcheck_exact_safe_translation_range_is_safe (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range < 0 || safe_to_translate_polynomial_to (& coefficients, range, maxima)
    }

    fn quickcheck_exact_safe_translation_range_is_maximal (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range == i64::max_value() || !safe_to_translate_polynomial_to (& coefficients, range + 1, maxima)
    }

    fn quickcheck_conservative_safe_translation_range_is_safe (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let exact_range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      let conservative_range = conservative_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", (exact_range, conservative_range));
      conservative_range <= exact_range
    }

    fn quickcheck_conservative_safe_translation_range_is_within_half_maximal (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1.checked_abs().unwrap_or (0);
      let exact_range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      let conservative_range = conservative_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", (exact_range, conservative_range));
      conservative_range == exact_range || conservative_range > exact_range >> 1
    }
  }
}
<|endoftext|>


<commit_before>mod r5rs {
    #[deriving(Eq)]
    enum LDatum {
        LIdent(~str),
        LString(~str),
    }

    struct Parser {
        priv reader: @io::Reader,
        priv buf: char,
        priv has_buf: bool,
        line: uint,
        col: uint,
    }

    pub fn Parser(reader: @io::Reader) -> Parser {
        Parser {
            reader: reader,
            has_buf: false,
            buf: 0 as char,
            line: 1,
            col: 1,
        }
    }

    priv fn id_init(c: char) -> bool {
        match(c) {
            '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
            _ => false,
        }
    }

    pub impl Parser {
        fn parse(&mut self) -> Result<LDatum, ~str> {
            do result::chain(self.parse_datum()) |v| {
                self.consume_whitespace();

                if(self.eof()) {
                    Ok(v)
                } else {
                    Err(~"trailing input")
                }
            }
        }
    }

    priv impl Parser {
        fn eof(&mut self) -> bool {
            !self.has_buf && self.reader.eof()
        }

        fn consume(&mut self) -> char {
            if(self.has_buf) {
                self.has_buf = false;
            } else {
                self.buf = self.reader.read_char();
            }

            if(self.buf == '\n') {
                self.line += 1;
                self.col = 1;
            } else {
                self.col += 1;
            }

            self.buf
        }

        fn lookahead(&mut self) -> char {
            if(!self.has_buf) {
                self.has_buf = true;
                self.buf = self.reader.read_char();
            }
            self.buf
        }

        fn consume_whitespace(&mut self) {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' '| '\t' | '\r' | '\n' => { self.consume(); },
                    _ => break
                }
            }
        }

        fn parse_datum(&mut self) -> Result<LDatum, ~str> {
            self.consume_whitespace();

            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.lookahead();
            match(c) {
                _ if id_init(c) =>
                    Ok(LIdent(self.parse_ident())),
                '"' => {
                        self.consume();
                        match(self.parse_string()) {
                            Ok(s) => Ok(LString(s)),
                            Err(e) => Err(e),
                        }
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_ident(&mut self) -> ~str {
            do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.lookahead();

                    match(c) {
                        '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                        _ if id_init(c) => wr.write_char(c),
                        _ => break,
                    }

                    self.consume();
                }
            }
        }

        fn parse_string(&mut self) -> Result<~str, ~str> {
            let mut escape_fail = false;

            let val = do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.consume();
                    match(c) {
                        '\\' => if self.eof() {
                                    escape_fail = true;
                                } else {
                                    wr.write_char(self.consume());
                                },
                        '"' => break,
                        _ => wr.write_char(c),
                    }
                }
            };

            if(escape_fail) {
                Err(~"unexpected EOF")
            } else {
                Ok(val)
            }
        }
    }

    #[test]
    fn test_parse_ident() {
        let test_src = ~"a3!";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LIdent(~"a3!")), val);
        }
    }

    #[test]
    fn test_parse_string() {
        let test_src = ~"\"ab\\\"c\"";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LString(~"ab\"c")), val);
        }
    }
}
<commit_msg>basic character parser<commit_after>mod r5rs {
    #[deriving(Eq)]
    enum LDatum {
        LIdent(~str),
        LString(~str),
        LChar(char),
    }

    struct Parser {
        priv reader: @io::Reader,
        priv buf: char,
        priv has_buf: bool,
        line: uint,
        col: uint,
    }

    pub fn Parser(reader: @io::Reader) -> Parser {
        Parser {
            reader: reader,
            has_buf: false,
            buf: 0 as char,
            line: 1,
            col: 1,
        }
    }

    priv fn id_init(c: char) -> bool {
        match(c) {
            '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
            _ => false,
        }
    }

    pub impl Parser {
        fn parse(&mut self) -> Result<LDatum, ~str> {
            do result::chain(self.parse_datum()) |v| {
                self.consume_whitespace();

                if(self.eof()) {
                    Ok(v)
                } else {
                    Err(~"trailing input")
                }
            }
        }
    }

    priv impl Parser {
        fn eof(&mut self) -> bool {
            !self.has_buf && self.reader.eof()
        }

        fn consume(&mut self) -> char {
            if(self.has_buf) {
                self.has_buf = false;
            } else {
                self.buf = self.reader.read_char();
            }

            if(self.buf == '\n') {
                self.line += 1;
                self.col = 1;
            } else {
                self.col += 1;
            }

            self.buf
        }

        fn lookahead(&mut self) -> char {
            if(!self.has_buf) {
                self.has_buf = true;
                self.buf = self.reader.read_char();
            }
            self.buf
        }

        fn consume_whitespace(&mut self) {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' '| '\t' | '\r' | '\n' => { self.consume(); },
                    _ => break
                }
            }
        }

        fn parse_datum(&mut self) -> Result<LDatum, ~str> {
            self.consume_whitespace();

            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.consume();
            match(c) {
                _ if id_init(c) =>
                    Ok(LIdent(self.parse_ident(c))),
                '"' => {
                        match(self.parse_string()) {
                            Ok(s) => Ok(LString(s)),
                            Err(e) => Err(e),
                        }
                    },
                '#' => {
                        self.parse_sharp()
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_sharp(&mut self) -> Result<LDatum, ~str> {
            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.consume();
            match(c) {
                '\\' =>
                    do result::map(&self.parse_char()) |&c| {
                        LChar(c)
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_char(&mut self) -> Result<char, ~str> {
            if(self.eof()) {
                Err(~"unexpected EOF")
            } else {
                Ok(self.consume())
            }
        }

        fn parse_ident(&mut self, init: char) -> ~str {
            do io::with_str_writer |wr| {
                wr.write_char(init);

                while(!self.eof()) {
                    let c = self.lookahead();

                    match(c) {
                        '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                        _ if id_init(c) => wr.write_char(c),
                        _ => break,
                    }

                    self.consume();
                }
            }
        }

        fn parse_string(&mut self) -> Result<~str, ~str> {
            let mut escape_fail = false;

            let val = do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.consume();
                    match(c) {
                        '\\' => if self.eof() {
                                    escape_fail = true;
                                } else {
                                    wr.write_char(self.consume());
                                },
                        '"' => break,
                        _ => wr.write_char(c),
                    }
                }
            };

            if(escape_fail) {
                Err(~"unexpected EOF")
            } else {
                Ok(val)
            }
        }
    }

    #[test]
    fn test_parse_ident() {
        let test_src = ~"a3!";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LIdent(~"a3!")), val);
        }
    }

    #[test]
    fn test_parse_string() {
        let test_src = ~"\"ab\\\"c\"";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LString(~"ab\"c")), val);
        }
    }

    #[test]
    fn test_parse_char() {
        let test_src = ~"#\\h";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LChar('h')), val);
        }
    }
}
<|endoftext|>