<commit_before>//  Copyright 2015 Nathanael Merrill
//
//  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.

//uifeature:
// press / to start filter/seatch
// change playlist to only display the things using regex filter of vector
// refresh/serach only when ch thread stops hanging for maximum performance
use playlist;

use ncurses::*;

pub enum UIResult {
    PlayPause,
    Next,
    Previous,
    Exit,
    Error(String),
    NA,
}

pub struct UI {
    cols: i32,
    lines: i32,
}
//there are three threads, one that hangs on the keyinput (the ncurse one), one that hangs on retrieving the data from main(which prints the output), and the gstreamer loop
//the cool part about this is that there is no looping in the ui, only hanging threads that send messages to awake other hanging threads

//current bug is in a stack thread in mobile bookmarks folder
impl UI {
    pub fn new() -> UI {
        initscr();
        noecho();
        refresh();
        start_color();
        use_default_colors();
        curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
        init_pair(1, -1, -1);
        init_pair(2, COLOR_YELLOW, -1);

        nodelay(stdscr, true);

        UI {
            cols: COLS,
            lines: LINES,
        }
    }

    pub fn manage_ui(&mut self, playlist: &playlist::Playlist,
                     time: i32, totaltime: i32) -> UIResult {
        let ch = getch() as u8 as char;

        match ch {
            'n' => return UIResult::Next,
            'p' => return UIResult::Previous,
            'x' => return UIResult::Exit,
            ' ' => return UIResult::PlayPause,
            _ => {},
        }

        if self.cols != COLS || self.lines != LINES {
            //redraw
        }

//if self.time != (time, totaltime) ||
            //(self.length, self.height) != (self.term.cols(), self.term.rows()){

            //self.time = (time, totaltime);

            //if totaltime/60 > 99 {
                //return UIResult::Error(String::from(
                    //"RFSMP does not support songs longer than 100 minutes"));
            //}

            //let curr_song = playlist.get_curr_song().unwrap_or("");
            //let mut curr_song_visable = String::from(curr_song);
            //let length_i32 = self.length as i32;
            //let mut spaces = (curr_song_visable.len() +
                //((totaltime/60).to_string().len()+3)*2) as i32;
            //spaces = length_i32 - spaces - 8;
            //if spaces < 0 {
                //curr_song_visable = String::new();
                //curr_song_visable.push_str(&curr_song[0..(curr_song.len() as i32+(spaces)-5) as usize]);
                //curr_song_visable.push_str("...");
                //spaces = 2;
            //}
            //spaces = spaces / 2;

            //let spaces_l = vec![' '; spaces as usize].into_iter().collect::<String>();
            //let spaces_r = match (length_i32-curr_song_visable.len() as i32).wrapping_rem(2) {
                //0 => spaces_l.clone(),
                //1 => spaces_l.clone() + " ",
                //_ => unreachable!(),
            //};
            //let status_chars: Vec<char> = format!("--{:0>7$}:{:0>2}{}--{}--{}{:0>7$}:{:0>2}--",
                                  //time/60, time%60, spaces_l, curr_song_visable, spaces_r,
                                  //totaltime/60, totaltime%60,
                                  //(totaltime/60).to_string().len())
                                  //.chars().collect();

            //let (cols, rows) = self.canvas.size();
            //let (cols, rows) = (cols as isize, rows as isize);
            //let number_of_x;

            //if totaltime == 0 {
                //number_of_x = 0;
            //}
            //else if totaltime < time {
                //number_of_x = length_i32;
            //}
            //else {
                //number_of_x = (time as f32 / totaltime as f32
                         //* length_i32 as f32).round() as i32;
            //}

            //let mut load_chars = vec!['x'; number_of_x as usize];
            //load_chars.append(&mut vec!['-'; (length_i32 - number_of_x) as usize]);

            //for x in 0..cols {
                //for y in 0..rows {
                    //let fep ='*';
                    //let mut cell = match self.canvas.get_mut(x as usize, y as usize) {
                        //Some(a) => a,
                        //None => return UIResult::Error(
                            //"Could not draw to screen".to_string()),
                    //};
                    //match y {
                        //0 => cell.set_ch(*status_chars.get(x as usize).unwrap_or_else(|| &fep)),
                        //1 => cell.set_ch(*load_chars.get(x as usize).unwrap_or_else(|| &fep)),
                        //_ => unreachable!(),
                    //};
                //}
            //}

        for (x, i) in playlist.songs.iter().zip(0..) {
            match x == playlist.get_curr_song().unwrap_or("") {
                false => {},
                true => {attron(COLOR_PAIR(2));},
            };
            mvprintw(i, 0, x);
            attron(COLOR_PAIR(1));
        }
        refresh();
        return UIResult::NA;
    }

}
<commit_msg>Finish implementing basic new UI<commit_after>//  Copyright 2015 Nathanael Merrill
//
//  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.

//uifeature:
// press / to start filter/seatch
// change playlist to only display the things using regex filter of vector
// refresh/serach only when ch thread stops hanging for maximum performance
use playlist;

use ncurses::*;

pub enum UIResult {
    PlayPause,
    Next,
    Previous,
    Exit,
    Error(String),
    NA,
}

pub struct UI {
    cols: i32,
    lines: i32,
    prev_time: i32,
    prev_song_num: i32,
}

fn split_time(time: i32) -> String {
    return format!("{}:{:0>2}", time / 60, time % 60);
}

impl UI {
    pub fn new() -> UI {
        initscr();
        noecho();
        refresh();
        start_color();
        use_default_colors();
        curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
        init_pair(1, -1, -1);
        init_pair(2, COLOR_YELLOW, -1);

        nodelay(stdscr, true);

        UI {
            cols: COLS,
            lines: LINES,
            prev_time: -1,
            prev_song_num: -1,
        }
    }

    pub fn manage_ui(&mut self, playlist: &playlist::Playlist,
                     time: i32, totaltime: i32) -> UIResult {
        let ch = getch() as u8 as char;

        match ch {
            'n' => return UIResult::Next,
            'p' => return UIResult::Previous,
            'x' => return UIResult::Exit,
            ' ' => return UIResult::PlayPause,
            _ => {},
        }

        if self.cols != COLS || self.lines != LINES {
            self.cols = COLS;
            self.lines = LINES;
            self.prev_time = -1;
            self.prev_song_num = -1;
        }

        let squares;

        if time == 0 || totaltime == 0 {
            squares = 0;
        }
        else {
            squares = (time as f64 / totaltime as f64 * COLS as f64) as usize;
        }

        if playlist.song_index != self.prev_song_num {
            // redraw everything on song change

            // song name
            mvprintw(LINES-3, 0, &*format!("{:^1$}", playlist.get_curr_song().unwrap_or(""), COLS as usize));
            // end time
            mvprintw(LINES-2, 0, &*format!("{:>1$}", split_time(totaltime), COLS as usize));
            // current time
            mvprintw(LINES-2, 0, &*split_time(time));
            self.prev_song_num = playlist.song_index;
            self.prev_time = time;

            for (x, i) in playlist.songs.iter().zip(0..) {
                match x == playlist.get_curr_song().unwrap_or("") {
                    false => {},
                    true => {attron(COLOR_PAIR(2));},
                };
                let mut visable = x.clone();
                if x.len() > COLS as usize {
                    visable = format!("{}...", &x[..(COLS-3) as usize]);
                }

                mvprintw(i, 0, &*visable);
                attron(COLOR_PAIR(1));
            }

            // progress bar
            mvprintw(LINES-1, 0, &*format!("{:#<1$}{0:<2$}", "", squares, COLS as usize-squares));

        }

        else if time != self.prev_time {
            // redraw the progress bar and times

            // end time
            mvprintw(LINES-2, 0, &*format!("{:>1$}", split_time(totaltime), COLS as usize));
            // current time
            mvprintw(LINES-2, 0, &*split_time(time));
            self.prev_time = time;

            // progress bar
            mvprintw(LINES-1, 0, &*format!("{:#<1$}{0:<2$}", "", squares, COLS as usize-squares));
        }

        refresh();
        return UIResult::NA;
    }
}
<|endoftext|>


<commit_before>use cocoa::base::id;

pub trait MTLRenderPassDepthAttachmentDescriptor {
    /// The depth to use when the depth attachment is cleared.
    ///
    /// # Discussion
    ///
    /// The default value is 1.0.
    ///
    /// If the `loadAction` property of the attachment is set to
    /// `MTLLoadActionClear`, then at the start of a rendering pass,
    /// the contents of the texture are filled with the value stored
    /// in the `clearDepth` property. Otherwise, `clearDepth` is ignored.
    unsafe fn clearDepth(self) -> f64;
    unsafe fn setClearDepth(self, clearDepth: f64);

    /// The filter used for an MSAA depth resolve operation.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLMultisampleDepthResolveFilterSample0`.
    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter;
    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter);

    unsafe fn copy(self) -> Self;
}

impl MTLRenderPassDepthAttachmentDescriptor for id {
    unsafe fn clearDepth(self) -> f64 {
        msg_send![self, clearDepth]
    }

    unsafe fn setClearDepth(self, clearDepth: f64) {
        msg_send![self, setClearDepth:clearDepth]
    }

    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter {
        msg_send![self, depthResolveFilter]
    }

    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter) {
        msg_send![self, setDepthResolveFilter:resolveFilter]
    }

    unsafe fn copy(self) -> Self {
        msg_send![self, copy]
    }
}

#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLMultisampleDepthResolveFilter {
    MTLMultisampleDepthResolveFilterSample0 = 0,
    MTLMultisampleDepthResolveFilterMin = 1,
    MTLMultisampleDepthResolveFilterMax = 2,
}
<commit_msg>rustfmt<commit_after>use cocoa::base::id;

pub trait MTLRenderPassDepthAttachmentDescriptor {
    /// The depth to use when the depth attachment is cleared.
    ///
    /// # Discussion
    ///
    /// The default value is 1.0.
    ///
    /// If the `loadAction` property of the attachment is set to
    /// `MTLLoadActionClear`, then at the start of a rendering pass,
    /// the contents of the texture are filled with the value stored
    /// in the `clearDepth` property. Otherwise, `clearDepth` is ignored.
    unsafe fn clearDepth(self) -> f64;
    unsafe fn setClearDepth(self, clearDepth: f64);

    /// The filter used for an MSAA depth resolve operation.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLMultisampleDepthResolveFilterSample0`.
    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter;
    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter);

    unsafe fn copy(self) -> Self;
}

impl MTLRenderPassDepthAttachmentDescriptor for id {
    unsafe fn clearDepth(self) -> f64 {
        msg_send![self, clearDepth]
    }

    unsafe fn setClearDepth(self, clearDepth: f64) {
        msg_send![self, setClearDepth:clearDepth]
    }

    unsafe fn depthResolveFilter(self) -> MTLMultisampleDepthResolveFilter {
        msg_send![self, depthResolveFilter]
    }

    unsafe fn setDepthResolveFilter(self, resolveFilter: MTLMultisampleDepthResolveFilter) {
        msg_send![self, setDepthResolveFilter:resolveFilter]
    }

    unsafe fn copy(self) -> Self {
        msg_send![self, copy]
    }
}

#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLMultisampleDepthResolveFilter {
    MTLMultisampleDepthResolveFilterSample0 = 0,
    MTLMultisampleDepthResolveFilterMin = 1,
    MTLMultisampleDepthResolveFilterMax = 2
}
<|endoftext|>


<commit_before>// can you solve the passcode riddle https://www.youtube.com/watch?v=7Vd1dTBVbFg

fn main() {
    for x in 1..9 {
        for y in 1..9 {
            for z in 1..9 {
                if (x<=y)&&(y<=z)&&(z != y)&&(x*y*z==36) {
                    println!("{} {} {} sum={}",x,y,z,x+y+z);
                }
            }
        }
    }
}
<commit_msg>oops: for upper bound is exclusive!<commit_after>// can you solve the passcode riddle https://www.youtube.com/watch?v=7Vd1dTBVbFg
//uhm, why am I not getting 2 2 9?
fn main() {
    for x in 1..10 {
        for y in 1..10 {
            for z in 1..10 {
                if (x<=y)&&(y<=z)&&(z != y)&&(x*y*z==36) {
                    println!("{} {} {} sum={}",x,y,z,x+y+z);
                } else {
//                    println!("{} {} {} rejected",x,y,z);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("%s: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.2",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum ParseType {
    FieldLabel,
    FieldValue,
    Field,
    Record,
    Ltsv
}

#[deriving_eq]
enum ParseDelimiter {
    EOF, TAB, NL, MISC
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, ParseDelimiter, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool);
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool);
}

pub impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

pub impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_ltsv() {
            ParseError(reason) => fail!(reason),
            ParseOk(_, _, records) => records
        }
    }
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_record() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, record) => if !f(&record) { break; }
            }
        }
    }
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_field() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, field) => if !f(&field) { break; }
            }
        }
    }
}

struct LTSVParser<T> {
    priv rd: &T,
    priv mut cur: int
}

impl<T: io::Reader> LTSVParser<T> {
    static fn new(rd: &r/T) -> LTSVParser/&r<T> {
        let cur = rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn eof(&self) -> bool { self.cur == -1 }

    fn bump(&self) {
        if !self.eof() {
            self.cur = self.rd.read_byte();
        }
    }

    fn parse_ltsv(&self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_record() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, EOF, record) => {
                    records.push(record);
                    break;
                }
                ParseOk(_, _, record) => {
                    records.push(record);
                }
            }
        }
        ParseOk(Ltsv, EOF, records)
    }

    fn parse_record(&self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        loop {
            match self.parse_field() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, TAB, (label, value)) => {
                    record.insert(label, value);
                }
                ParseOk(_, delim, (label, value)) => {
                    record.insert(label, value);
                    return ParseOk(Record, delim, record);
                }
            }
        }
    }

    fn parse_field(&self) -> ParseResult<(~str, ~str)> {
        self.skip_whitespaces();
        let label = match self.parse_field_label() {
            ParseError(reason) => return ParseError(reason),
            ParseOk(_, _, label) => { self.bump(); label }
        };
        match self.parse_field_value() {
            ParseError(reason) => {
                ParseError(reason)
            }
            ParseOk(_, delim, value) => {
                self.bump();
                // avoid skipping whitespaces in the middle of parsing record.
                if delim != TAB { self.skip_whitespaces(); }
                // re-check EOF
                let delim = if self.eof() { EOF } else { delim };
                ParseOk(Field, delim, (label, value))
            }
        }
    }

    priv fn parse_field_label(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, MISC, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn parse_field_value(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(self.cur as u8),
                0x0d => return self.consume_forward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue, NL, str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue, TAB, str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue, EOF, str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn consume_forward_LF(&self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue, NL, rv)
        }
    }

    priv fn skip_whitespaces(&self) {
        while char::is_whitespace(self.cur as char) {
            self.bump();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::io::WriterUtil;

    fn mk_record_string() -> ~str {
        do io::with_str_writer |wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        }
    }

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert records.len() == 1;
    }

    #[test]
    fn test_parse_full() {
        let s = mk_record_string();
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert records.len() == 2;
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = mk_record_string();
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert records_1 == records_2;
    }

    #[test]
    fn test_each_read_each_record() {
        let s = mk_record_string();
        let ks = [~"tofu", ~"kamaboko", ~"sukonbu"];
        let vs = [~"豆", ~"魚", ~"海藻", ~"好き", ~"普通", ~"苦手"];
        do io::with_str_reader(s) |rd| {
            for rd.each_ltsv_record |record| {
                for record.each |&(k, v)| {
                    assert ks.contains(k);
                    assert vs.contains(v);
                }
            }
        }
    }
}
<commit_msg>"pub impl" is now invalid<commit_after>/*!
Library for reading/writing Labeled Tab-Separated Values

# Example

~~~~~~~~~~~~~~~~~~~~~~
extern mod ltsv;
use ltsv::LTSVWriter;
use ltsv::LTSVReader;

fn main() {
    let infile = io::file_reader(&Path("path/fo/file.tlsv")).get();
    for infile.read_ltsv().each |record| {
        for record.each |&(label, value)| {
            io::println(fmt!("%s: %s", *label, *value));
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~
*/
#[link(name = "ltsv",
       vers = "0.2",
       uuid = "E0EA0251-E165-4612-919F-38E89ACECBE9",
       url  = "https://github.com/tychosci/rust-ltsv/")];

#[comment = "Library for reading/writing Labeled Tab-Separated Values"];
#[license = "MIT license"];
#[crate_type = "lib"];

use core::container::Map;
use core::hashmap::linear::LinearMap;
use io::WriterUtil;

pub type Record = LinearMap<~str, ~str>;

enum ParseType {
    FieldLabel,
    FieldValue,
    Field,
    Record,
    Ltsv
}

#[deriving_eq]
enum ParseDelimiter {
    EOF, TAB, NL, MISC
}

enum ParseResult<T> {
    ParseError(~str),
    ParseOk(ParseType, ParseDelimiter, T)
}

pub trait LTSVWriter {
    fn write_ltsv(&self, ltsv: &[Record]);
    fn write_ltsv_record(&self, record: &Record);
}

pub trait LTSVReader {
    fn read_ltsv(&self) -> ~[Record];
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool);
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool);
}

impl<T: io::Writer> LTSVWriter for T {
    fn write_ltsv(&self, ltsv: &[Record]) {
        for ltsv.each |record| {
            self.write_ltsv_record(record);
            self.write_char('\n');
        }
    }
    fn write_ltsv_record(&self, record: &Record) {
        let mut is_first = true;
        for record.each |&(k, v)| {
            if !is_first { self.write_char('\t'); }
            self.write_str(fmt!("%s:%s", *k, *v));
            if is_first { is_first = false; }
        }
    }
}

impl<T: io::Reader> LTSVReader for T {
    fn read_ltsv(&self) -> ~[Record] {
        let mut parser = LTSVParser::new(self);
        match parser.parse_ltsv() {
            ParseError(reason) => fail!(reason),
            ParseOk(_, _, records) => records
        }
    }
    fn each_ltsv_record(&self, f: &fn(&Record) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_record() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, record) => if !f(&record) { break; }
            }
        }
    }
    fn each_ltsv_field(&self, f: &fn(&(~str, ~str)) -> bool) {
        let mut parser = LTSVParser::new(self);
        while !parser.eof() {
            match parser.parse_field() {
                ParseError(reason) => fail!(reason),
                ParseOk(_, _, field) => if !f(&field) { break; }
            }
        }
    }
}

struct LTSVParser<T> {
    priv rd: &T,
    priv mut cur: int
}

impl<T: io::Reader> LTSVParser<T> {
    static fn new(rd: &r/T) -> LTSVParser/&r<T> {
        let cur = rd.read_byte();
        LTSVParser { rd: rd, cur: cur }
    }

    fn eof(&self) -> bool { self.cur == -1 }

    fn bump(&self) {
        if !self.eof() {
            self.cur = self.rd.read_byte();
        }
    }

    fn parse_ltsv(&self) -> ParseResult<~[Record]> {
        let mut records = ~[];
        loop {
            match self.parse_record() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, EOF, record) => {
                    records.push(record);
                    break;
                }
                ParseOk(_, _, record) => {
                    records.push(record);
                }
            }
        }
        ParseOk(Ltsv, EOF, records)
    }

    fn parse_record(&self) -> ParseResult<Record> {
        let mut record = LinearMap::new();
        loop {
            match self.parse_field() {
                ParseError(reason) => {
                    return ParseError(reason);
                }
                ParseOk(_, TAB, (label, value)) => {
                    record.insert(label, value);
                }
                ParseOk(_, delim, (label, value)) => {
                    record.insert(label, value);
                    return ParseOk(Record, delim, record);
                }
            }
        }
    }

    fn parse_field(&self) -> ParseResult<(~str, ~str)> {
        self.skip_whitespaces();
        let label = match self.parse_field_label() {
            ParseError(reason) => return ParseError(reason),
            ParseOk(_, _, label) => { self.bump(); label }
        };
        match self.parse_field_value() {
            ParseError(reason) => {
                ParseError(reason)
            }
            ParseOk(_, delim, value) => {
                self.bump();
                // avoid skipping whitespaces in the middle of parsing record.
                if delim != TAB { self.skip_whitespaces(); }
                // re-check EOF
                let delim = if self.eof() { EOF } else { delim };
                ParseOk(Field, delim, (label, value))
            }
        }
    }

    priv fn parse_field_label(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x30..0x39 | 0x41..0x5a | 0x61..0x7a | 0x5f |
                0x2e | 0x2d => bytes.push(self.cur as u8),
                0x3a if bytes.len() == 0 => return ParseError(~"label is empty"),
                0x3a => return ParseOk(FieldLabel, MISC, str::from_bytes(bytes)),
                -1   => return ParseError(~"EOF while parsing field label"),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn parse_field_value(&self) -> ParseResult<~str> {
        let mut bytes = ~[];
        loop {
            match self.cur {
                0x01..0x08 | 0x0b | 0x0c |
                0x0e..0xff => bytes.push(self.cur as u8),
                0x0d => return self.consume_forward_LF(str::from_bytes(bytes)),
                0x0a => return ParseOk(FieldValue, NL, str::from_bytes(bytes)),
                0x09 => return ParseOk(FieldValue, TAB, str::from_bytes(bytes)),
                -1   => return ParseOk(FieldValue, EOF, str::from_bytes(bytes)),
                _    => return ParseError(~"invalid byte detected")
            }
            self.bump();
        }
    }

    priv fn consume_forward_LF(&self, rv: ~str) -> ParseResult<~str> {
        self.bump();
        if self.cur != 0x0a {
            ParseError(~"CR detected, but not provided with LF")
        } else {
            ParseOk(FieldValue, NL, rv)
        }
    }

    priv fn skip_whitespaces(&self) {
        while char::is_whitespace(self.cur as char) {
            self.bump();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::io::WriterUtil;

    fn mk_record_string() -> ~str {
        do io::with_str_writer |wr| {
            // genzairyou
            wr.write_str(fmt!("%s:%s\t", "tofu", "豆"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "魚"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "海藻"));
            // konomi
            wr.write_str(fmt!("%s:%s\t", "tofu", "好き"));
            wr.write_str(fmt!("%s:%s\t", "kamaboko", "普通"));
            wr.write_str(fmt!("%s:%s\n", "sukonbu", "苦手"));
        }
    }

    #[test]
    fn test_parse_simple() {
        let records = io::with_str_reader(~"a:1\tb:2", |rd| rd.read_ltsv());
        assert records.len() == 1;
    }

    #[test]
    fn test_parse_full() {
        let s = mk_record_string();
        let records = io::with_str_reader(s, |rd| rd.read_ltsv());
        assert records.len() == 2;
    }

    #[test]
    fn test_parse_ltsv_trailing_nl_and_write() {
        let s = mk_record_string();
        let records_1 = io::with_str_reader(s, |rd| rd.read_ltsv());
        let s2 = io::with_str_writer(|wr| wr.write_ltsv(records_1));
        let records_2 = io::with_str_reader(s2, |rd| rd.read_ltsv());
        assert records_1 == records_2;
    }

    #[test]
    fn test_each_read_each_record() {
        let s = mk_record_string();
        let ks = [~"tofu", ~"kamaboko", ~"sukonbu"];
        let vs = [~"豆", ~"魚", ~"海藻", ~"好き", ~"普通", ~"苦手"];
        do io::with_str_reader(s) |rd| {
            for rd.each_ltsv_record |record| {
                for record.each |&(k, v)| {
                    assert ks.contains(k);
                    assert vs.contains(v);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

/// Represents a vertex in the vertex buffer.
#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

/// We emulate `GL_ARB_shader_draw_parameters` by storing draw IDs in a buffer.
#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

/// Contains the list of transforms to apply to individual cubes.
struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

// You can modify these three values.
const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;

// But don't touch this one.
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .with_depth_buffer(24)
                    .build_glium()
                    .unwrap();

    // building a vertex buffer that contains the cube
    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    // matches `vertex_buffer`
    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    // storing each number from `0` to `OBJECTS_COUNT` linearly in a buffer
    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    // compiling the program ; if `.unwrap()` panicks, then your hardware is probably not good
    // enough
    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    // creating the buffer that will hold our draw commands
    // we have one command per cube, and we mulitply by 3 to use triple buffering
    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();

    // storing all the transforms ; one transform per cube
    let mut transform_buffer =
                  glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    // looping forever with a counter
    for iteration in 0u32.. {
        // we are doing triple buffering
        // while part X of the buffer is used to draw, part X+1 is being uploaded and part X+2
        // is waiting
        let buf_num = (iteration as usize) % 3;

        // writing the commands to the commands buffer
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT ..
                                              (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();

            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transform matrices
        {
            let angle = iteration as f32 * 0.01;

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[3][0] = 2.0 * x as f32 - OBJECTS_X as f32;
                        mat[3][1] = 2.0 * y as f32 - OBJECTS_Y as f32;
                        mat[3][2] = 2.0 * z as f32 - OBJECTS_Z as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        // building the source of indices
        // ideally you shouldn't build a `IndicesSource` directly, but a limitation in glium
        // currently makes this mandatory
        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT ..
                                          (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        // the matrix of the camera to use when drawing the cubes
        let camera = build_camera(display.get_framebuffer_dimensions());

        // the parameters to use when drawing
        // nothing fancy, just depth testing and backface culling
        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.01, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: camera },
                    &params).unwrap();
        target.finish().unwrap();

        // handling events so that we can quit if the window is closed by the user
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}

fn build_camera((w, h): (u32, u32)) -> cgmath::Matrix4<f32> {
    let persp = cgmath::perspective(cgmath::deg(45.0), w as f32 / h as f32, 0.1, 10000.0);

    let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
    let at = cgmath::Vector3::new(0.0, 0.0, 0.0);
    let eye = at - dir.mul_s(250.0);

    let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&eye),
                                        &cgmath::Point3::from_vec(&at),
                                        &cgmath::Vector3::new(0.0, 0.0, 1.0));

    persp * view
}
<commit_msg>Fix colors in untextured object<commit_after>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

/// Represents a vertex in the vertex buffer.
#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

/// We emulate `GL_ARB_shader_draw_parameters` by storing draw IDs in a buffer.
#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

/// Contains the list of transforms to apply to individual cubes.
struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

// You can modify these three values.
const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;

// But don't touch this one.
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .with_depth_buffer(24)
                    .build_glium()
                    .unwrap();

    // building a vertex buffer that contains the cube
    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    // matches `vertex_buffer`
    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    // storing each number from `0` to `OBJECTS_COUNT` linearly in a buffer
    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    // compiling the program ; if `.unwrap()` panicks, then your hardware is probably not good
    // enough
    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    // creating the buffer that will hold our draw commands
    // we have one command per cube, and we mulitply by 3 to use triple buffering
    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();

    // storing all the transforms ; one transform per cube
    let mut transform_buffer =
                  glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    // looping forever with a counter
    for iteration in 0u32.. {
        // we are doing triple buffering
        // while part X of the buffer is used to draw, part X+1 is being uploaded and part X+2
        // is waiting
        let buf_num = (iteration as usize) % 3;

        // writing the commands to the commands buffer
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT ..
                                              (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();

            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transform matrices
        {
            let angle = iteration as f32 * 0.01;

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[3][0] = 2.0 * x as f32 - OBJECTS_X as f32;
                        mat[3][1] = 2.0 * y as f32 - OBJECTS_Y as f32;
                        mat[3][2] = 2.0 * z as f32 - OBJECTS_Z as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        // building the source of indices
        // ideally you shouldn't build a `IndicesSource` directly, but a limitation in glium
        // currently makes this mandatory
        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT ..
                                          (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        // the matrix of the camera to use when drawing the cubes
        let camera = build_camera(display.get_framebuffer_dimensions());

        // the parameters to use when drawing
        // nothing fancy, just depth testing and backface culling
        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.01, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: camera },
                    &params).unwrap();
        target.finish().unwrap();

        // handling events so that we can quit if the window is closed by the user
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}

fn build_camera((w, h): (u32, u32)) -> cgmath::Matrix4<f32> {
    let persp = cgmath::perspective(cgmath::deg(45.0), w as f32 / h as f32, 0.1, 10000.0);

    let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
    let at = cgmath::Vector3::new(0.0, 0.0, 0.0);
    let eye = at - dir.mul_s(250.0);

    let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&eye),
                                        &cgmath::Point3::from_vec(&at),
                                        &cgmath::Vector3::new(0.0, 0.0, 1.0));

    persp * view
}
<|endoftext|>


<commit_before>// Copyright 2012-2016 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.

// Tests that the `vec!` macro does not overflow the stack when it is
// given data larger than the stack.

const LEN: usize = 1 << 15;

use std::thread::Builder;

fn main() {
    assert!(Builder::new().stack_size(LEN / 2).spawn(|| {
        let vec = vec![[0; LEN]];
        assert_eq!(vec.len(), 1);
    }).unwrap().join().is_ok());
}
<commit_msg>tests: don't use -Zorbit on run-pass/issue-28950, it stack overflows.<commit_after>// Copyright 2012-2016 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.

// compile-flags: -Z orbit=off
// (blows the stack with MIR trans and no optimizations)

// Tests that the `vec!` macro does not overflow the stack when it is
// given data larger than the stack.

const LEN: usize = 1 << 15;

use std::thread::Builder;

fn main() {
    assert!(Builder::new().stack_size(LEN / 2).spawn(|| {
        let vec = vec![[0; LEN]];
        assert_eq!(vec.len(), 1);
    }).unwrap().join().is_ok());
}
<|endoftext|>


<commit_before>#[deny(missing_doc)];
#[feature(managed_boxes)];

extern mod extra;
extern mod syntax;
extern mod rustc;
use std::{io, os, str};
use std::hashmap::HashSet;
use extra::priority_queue;
use syntax::{ast, codemap};

pub mod words;
mod visitor;

static DEFAULT_DICT: &'static str = "/usr/share/dict/words";

fn main() {
    use extra::getopts::groups;

    let args = std::os::args();
    let opts = ~[groups::optmulti("d", "dict",
                                  "dictionary file (a list of words, one per line)", "PATH"),
                 groups::optflag("n", "no-def-dict", "don't use the default dictionary"),
                 groups::optflag("h", "help", "show this help message")];

    let matches = groups::getopts(args.tail(), opts).unwrap();
    if matches.opt_present("h") || matches.opt_present("help") {
        println(groups::usage(args[0], opts));
        return;
    }

    let mut words = HashSet::new();

    if !(matches.opt_present("n") ||
         matches.opt_present("no-def-dict")) {
        if !read_lines_into(&Path::new(DEFAULT_DICT), &mut words) {
            return
        }
    }
    for dict in matches.opt_strs("d").move_iter() {
        if !read_lines_into(&Path::new(dict), &mut words) {
            return
        }
    }

    // one visitor; the internal list of misspelled words gets reset
    // for each file, since the spans could conflict.
    let mut any_mistakes = false;

    for name in matches.free.iter() {
        let (cm, crate) = get_ast(Path::new(name.as_slice()));

        let mut visitor = visitor::SpellingVisitor::new(&words);
        visitor.check_crate(&crate);

        struct Sort<'self> {
            sp: codemap::Span,
            words: &'self HashSet<~str>
        }
        impl<'self> Ord for Sort<'self> {
            fn lt(&self, other: &Sort<'self>) -> bool {
                self.sp.lo < other.sp.lo ||
                    (self.sp.lo == other.sp.lo && self.sp.hi < other.sp.hi)
            }
        }

        // extract the lines in order of the spans, so that e.g. files
        // are grouped together, and lines occur in increasing order.
        let pq: priority_queue::PriorityQueue<Sort> =
            do visitor.misspellings.iter().map |(k, v)| {
                Sort { sp: *k, words: v }
            }.collect();

        // run through the spans, printing the words that are
        // apparently misspelled
        for Sort {sp, words} in pq.to_sorted_vec().move_iter() {
            any_mistakes = true;

            let lines = cm.span_to_lines(sp);
            let sp_text = cm.span_to_str(sp);

            // [] required for connect :(
            let word_vec = words.iter().map(|s| s.as_slice()).to_owned_vec();

            println!("{}: misspelled {len, plural, =1{word} other{words}}: {}",
                     sp_text,
                     word_vec.connect(", "),
                     len=words.len());

            // first line; no lines = no printing
            match lines.lines {
                [line_num, .. _] => {
                    let line = lines.file.get_line(line_num as int);
                    println!("{}: {}", sp_text, line);
                }
                _ => {}
            }
        }
    }

    if any_mistakes {
        os::set_exit_status(1)
    }
}

/// Load each line of the file `p` into the given `Extendable` object.
fn read_lines_into<E: Extendable<~str>>
                  (p: &Path, e: &mut E) -> bool {
    match io::result(|| io::File::open(p)) {
        Ok(Some(mut r)) => {
            let r = r.read_to_end();
            let s = str::from_utf8_owned(r);
            e.extend(&mut s.line_iter().map(|ss| ss.to_owned()));
            true
        }
        Ok(None) => fail!("impossible?"),
        Err(e) => {
            write!(&mut io::stderr() as &mut Writer,
                   "Error reading {}: {}", p.display(), e.to_str());
            os::set_exit_status(10);
            false
        }
    }
}

/// Extract the expanded ast of a crate, along with the codemap which
/// connects source code locations to the actual code.
fn get_ast(path: Path) -> (@codemap::CodeMap, ast::Crate) {
    use rustc::driver::{driver, session};
    use syntax::diagnostic;

    // cargo culted from rustdoc_ng :(
    let parsesess = syntax::parse::new_parse_sess(None);
    let input = driver::file_input(path);

    let sessopts = @session::options {
        binary: @"spellck",
        .. (*session::basic_options()).clone()
    };

    let diagnostic_handler = diagnostic::mk_handler(None);
    let span_diagnostic_handler =
        diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);

    let sess = driver::build_session_(sessopts, parsesess.cm,
                                      @diagnostic::DefaultEmitter as @diagnostic::Emitter,
                                      span_diagnostic_handler);

    let cfg = driver::build_configuration(sess);

    let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);

    (parsesess.cm,
     driver::phase_2_configure_and_expand(sess, cfg, crate))
}
<commit_msg>Handle --dict, and use the helper methods provided by extra::getopts for checking multiple options.<commit_after>#[deny(missing_doc)];
#[feature(managed_boxes)];

extern mod extra;
extern mod syntax;
extern mod rustc;
use std::{io, os, str};
use std::hashmap::HashSet;
use extra::priority_queue;
use syntax::{ast, codemap};

pub mod words;
mod visitor;

static DEFAULT_DICT: &'static str = "/usr/share/dict/words";

fn main() {
    use extra::getopts::groups;

    let args = std::os::args();
    let opts = ~[groups::optmulti("d", "dict",
                                  "dictionary file (a list of words, one per line)", "PATH"),
                 groups::optflag("n", "no-def-dict", "don't use the default dictionary"),
                 groups::optflag("h", "help", "show this help message")];

    let matches = groups::getopts(args.tail(), opts).unwrap();
    if matches.opts_present([~"h", ~"help"]) {
        println(groups::usage(args[0], opts));
        return;
    }

    let mut words = HashSet::new();

    if !matches.opts_present([~"n", ~"no-def-dict"]) {
        if !read_lines_into(&Path::new(DEFAULT_DICT), &mut words) {
            return
        }
    }
    for dict in matches.opt_strs("d").move_iter().chain(matches.opt_strs("dict").move_iter()) {
        if !read_lines_into(&Path::new(dict), &mut words) {
            return
        }
    }

    // one visitor; the internal list of misspelled words gets reset
    // for each file, since the spans could conflict.
    let mut any_mistakes = false;

    for name in matches.free.iter() {
        let (cm, crate) = get_ast(Path::new(name.as_slice()));

        let mut visitor = visitor::SpellingVisitor::new(&words);
        visitor.check_crate(&crate);

        struct Sort<'self> {
            sp: codemap::Span,
            words: &'self HashSet<~str>
        }
        impl<'self> Ord for Sort<'self> {
            fn lt(&self, other: &Sort<'self>) -> bool {
                self.sp.lo < other.sp.lo ||
                    (self.sp.lo == other.sp.lo && self.sp.hi < other.sp.hi)
            }
        }

        // extract the lines in order of the spans, so that e.g. files
        // are grouped together, and lines occur in increasing order.
        let pq: priority_queue::PriorityQueue<Sort> =
            do visitor.misspellings.iter().map |(k, v)| {
                Sort { sp: *k, words: v }
            }.collect();

        // run through the spans, printing the words that are
        // apparently misspelled
        for Sort {sp, words} in pq.to_sorted_vec().move_iter() {
            any_mistakes = true;

            let lines = cm.span_to_lines(sp);
            let sp_text = cm.span_to_str(sp);

            // [] required for connect :(
            let word_vec = words.iter().map(|s| s.as_slice()).to_owned_vec();

            println!("{}: misspelled {len, plural, =1{word} other{words}}: {}",
                     sp_text,
                     word_vec.connect(", "),
                     len=words.len());

            // first line; no lines = no printing
            match lines.lines {
                [line_num, .. _] => {
                    let line = lines.file.get_line(line_num as int);
                    println!("{}: {}", sp_text, line);
                }
                _ => {}
            }
        }
    }

    if any_mistakes {
        os::set_exit_status(1)
    }
}

/// Load each line of the file `p` into the given `Extendable` object.
fn read_lines_into<E: Extendable<~str>>
                  (p: &Path, e: &mut E) -> bool {
    match io::result(|| io::File::open(p)) {
        Ok(Some(mut r)) => {
            let r = r.read_to_end();
            let s = str::from_utf8_owned(r);
            e.extend(&mut s.line_iter().map(|ss| ss.to_owned()));
            true
        }
        Ok(None) => fail!("impossible?"),
        Err(e) => {
            write!(&mut io::stderr() as &mut Writer,
                   "Error reading {}: {}", p.display(), e.to_str());
            os::set_exit_status(10);
            false
        }
    }
}

/// Extract the expanded ast of a crate, along with the codemap which
/// connects source code locations to the actual code.
fn get_ast(path: Path) -> (@codemap::CodeMap, ast::Crate) {
    use rustc::driver::{driver, session};
    use syntax::diagnostic;

    // cargo culted from rustdoc_ng :(
    let parsesess = syntax::parse::new_parse_sess(None);
    let input = driver::file_input(path);

    let sessopts = @session::options {
        binary: @"spellck",
        .. (*session::basic_options()).clone()
    };

    let diagnostic_handler = diagnostic::mk_handler(None);
    let span_diagnostic_handler =
        diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);

    let sess = driver::build_session_(sessopts, parsesess.cm,
                                      @diagnostic::DefaultEmitter as @diagnostic::Emitter,
                                      span_diagnostic_handler);

    let cfg = driver::build_configuration(sess);

    let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);

    (parsesess.cm,
     driver::phase_2_configure_and_expand(sess, cfg, crate))
}
<|endoftext|>


<commit_before>extern crate gcc;
extern crate syntex_syntax as syntax;

use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::*;
use std::iter;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token::InternedString;
use syntax::attr::{self, ReprAttr};
use syntax::parse::{self, ParseSess};
use syntax::visit::{self, Visitor};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

struct TestGenerator<'a> {
    target: String,
    rust: Box<Write>,
    c: Box<Write>,
    sh: &'a SpanHandler,
    structs: HashSet<String>,
}

struct StructFinder {
    structs: HashSet<String>,
}

impl<'a> TestGenerator<'a> {
    fn defines(&self) -> Vec<&'static str> {
        let mut ret = Vec::new();
        if self.target.contains("unknown-linux") {
            ret.push("_GNU_SOURCE");
        }
        if self.target.contains("msvc") {
            ret.push("alignof __alignof");
        }
        return ret
    }

    fn headers(&self) -> Vec<&'static str> {
        let mut base = Vec::new();

        if self.target.contains("windows") {
            base.push("windows.h");
        }

        base.extend(&[
            "errno.h",
            "fcntl.h",
            "limits.h",
            "stddef.h",
            "stdint.h",
            "stdio.h",
            "stdlib.h",
            "sys/stat.h",
            "sys/types.h",
            "time.h",
            "wchar.h",
        ]);

        if self.target.contains("apple-darwin") {
            base.push("mach/mach_time.h");
        }

        if self.target.contains("unknown-linux") {
            base.push("linux/if_packet.h");
            base.push("net/ethernet.h");
        }

        if self.target.contains("windows") {
            base.push("ws2tcpip.h");
        } else {
            base.push("glob.h");
            base.push("ifaddrs.h");
            base.push("net/if.h");
            base.push("netdb.h");
            base.push("netinet/in.h");
            base.push("netinet/ip.h");
            base.push("netinet/tcp.h");
            base.push("pthread.h");
            base.push("signal.h");
            base.push("stdalign.h");
            base.push("sys/mman.h");
            base.push("sys/resource.h");
            base.push("sys/socket.h");
            base.push("sys/time.h");
            base.push("sys/un.h");
            base.push("utime.h");
            base.push("unistd.h");
        }

        return base
    }

    fn rust2c(&self, ty: &str) -> String {
        match ty {
            t if t.starts_with("c_") => {
                match &ty[2..].replace("long", " long")[..] {
                    s if s.starts_with("u") => format!("unsigned {}", &s[1..]),
                    "short" => format!("short"),
                    s if s.starts_with("s") => format!("signed {}", &s[1..]),
                    s => s.to_string(),
                }
            }
            "ip6_mreq" => "struct ipv6_mreq".to_string(),
            "glob_t" => "glob_t".to_string(),
            t if t.starts_with("pthread") => t.to_string(),

            t if self.structs.contains(t) => format!("struct {}", t),

            t => t.to_string(),
        }
    }

    fn rust2cfield(&self, struct_: &str, field: &str) -> String {
        match field {
            s if s.ends_with("_nsec") && struct_ == "stat" => {
                if self.target.contains("apple-darwin") {
                    s.replace("_nsec", "spec.tv_nsec")
                } else {
                    s.replace("e_nsec", ".tv_nsec")
                }
            }
            s => s.to_string(),
        }
    }

    fn cfg_list(&self) -> Vec<(&'static str, Option<&'static str>)> {
        let mut ret = Vec::new();
        let (arch, target_pointer_width) = if self.target.starts_with("x86_64") {
            ("x86_64", "64")
        } else if self.target.starts_with("i686") {
            ("x86", "32")
        } else {
            panic!("unknown arch/pointer width: {}", self.target)
        };
        let (os, family, env) = if self.target.contains("unknown-linux") {
            ("linux", "unix", "gnu")
        } else if self.target.contains("apple-darwin") {
            ("macos", "unix", "")
        } else if self.target.contains("windows-msvc") {
            ("windows", "windows", "msvc")
        } else if self.target.contains("windows-gnu") {
            ("windows", "windows", "gnu")
        } else {
            panic!("unknown os/family width: {}", self.target)
        };

        ret.push((family, None));
        ret.push(("target_os", Some(os)));
        ret.push(("target_family", Some(family)));
        ret.push(("target_arch", Some(arch)));
        // skip endianness
        ret.push(("target_pointer_width", Some(target_pointer_width)));
        ret.push(("target_env", Some(env)));

        return ret
    }
}

fn main() {
    // Prep the test generator
    let target = t!(env::var("TARGET"));
    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let rust_out = BufWriter::new(t!(File::create(out.join("all.rs"))));
    let c_out = BufWriter::new(t!(File::create(out.join("all.c"))));
    let sess = ParseSess::new();
    let mut tg = TestGenerator {
        target: target,
        rust: Box::new(rust_out),
        c: Box::new(c_out),
        sh: &sess.span_diagnostic,
        structs: HashSet::new(),
    };

    // Parse the libc crate
    let src = Path::new("../src/lib.rs");
    let cfg = Vec::new();
    let mut krate = parse::parse_crate_from_file(src, cfg, &sess);

    // Strip the crate down to just what's configured for our target
    for (k, v) in tg.cfg_list() {
        let s = InternedString::new;
        krate.config.push(match v {
            Some(v) => attr::mk_name_value_item_str(s(k), s(v)),
            None => attr::mk_word_item(s(k)),
        });
    }
    let mut gated_cfgs = Vec::new();
    let krate = syntax::config::strip_unconfigured_items(&sess.span_diagnostic,
                                                         krate,
                                                         &mut gated_cfgs);

    // Probe the crate to find all structs (used to convert type names to names
    // in C).
    let mut structs = StructFinder {
        structs: HashSet::new(),
    };
    visit::walk_crate(&mut structs, &krate);
    tg.structs = structs.structs;

    // Prep the C file by emitting header stuff
    for define in tg.defines() {
        t!(writeln!(tg.c, "#define {}", define));
    }
    for header in tg.headers() {
        t!(writeln!(tg.c, "#include <{}>", header));
    }

    // Walk the crate, emitting test cases for everything found
    visit::walk_crate(&mut tg, &krate);

    // Compile our C shim to be linked into tests
    let mut cfg = gcc::Config::new();
    cfg.file(out.join("all.c"));

    if tg.target.contains("msvc") {
        cfg.flag("/W3").flag("/Wall").flag("/WX");
    } else {
        cfg.flag("-Wall").flag("-Wextra").flag("-Werror");
    }

    drop(tg);
    cfg.compile("liball.a");
}

impl<'a> TestGenerator<'a> {
    fn test_type(&mut self, ty: &str) {
        match ty {
            "sighandler_t" => return,
            _ => {}
        }
        let c = self.rust2c(ty);
        self.test_size_align(ty, &c);
    }

    fn test_struct(&mut self, ty: &str, s: &ast::StructDef) {
        let cty = self.rust2c(ty);
        self.test_size_align(ty, &cty);

        t!(writeln!(self.rust, r#"
            #[test]
            fn field_offset_size_{ty}() {{
        "#, ty = ty));
        for field in s.fields.iter() {
            let name = match field.node.kind {
                ast::NamedField(name, ast::Public) => name,
                ast::NamedField(_, ast::Inherited) => continue,
                ast::UnnamedField(..) => panic!("no tuple structs in FFI"),
            };

            let cfield = self.rust2cfield(ty, &name.to_string());

            t!(writeln!(self.c, r#"
                uint64_t __test_offset_{ty}_{rust_field}() {{
                    return offsetof({cty}, {c_field});
                }}
                uint64_t __test_size_{ty}_{rust_field}() {{
                    {cty}* foo = NULL;
                    return sizeof(foo->{c_field});
                }}
            "#, ty = ty, cty = cty, rust_field = name, c_field = cfield));
            t!(writeln!(self.rust, r#"
                extern {{
                    fn __test_offset_{ty}_{field}() -> u64;
                    fn __test_size_{ty}_{field}() -> u64;
                }}
                unsafe {{
                    let foo = 0 as *const {ty};
                    same(offset_of!({ty}, {field}),
                         __test_offset_{ty}_{field}(),
                         "field offset {field} of {ty}");
                    same(mem::size_of_val(&(*foo).{field}) as u64,
                         __test_size_{ty}_{field}(),
                         "field size {field} of {ty}");
                }}
            "#, ty = ty, field = name));
        }
        t!(writeln!(self.rust, r#"
            }}
        "#));
    }

    fn test_size_align(&mut self, rust: &str, c: &str) {
        t!(writeln!(self.c, r#"
            uint64_t __test_size_{ty}() {{ return sizeof({cty}); }}
            uint64_t __test_align_{ty}() {{ return alignof({cty}); }}
        "#, ty = rust, cty = c));
        t!(writeln!(self.rust, r#"
            #[test]
            fn size_align_{ty}() {{
                extern {{
                    fn __test_size_{ty}() -> u64;
                    fn __test_align_{ty}() -> u64;
                }}
                unsafe {{
                    same(mem::size_of::<{ty}>() as u64,
                         __test_size_{ty}(), "size");
                    same(align::<{ty}>() as u64,
                         __test_align_{ty}(), "align");
                }}
            }}
        "#, ty = rust));
    }

    fn test_const(&mut self, name: &str, rust_ty: &str) {
        let cty = self.rust2c(&rust_ty.replace("*mut ", "")
                                      .replace("*const ", ""));
        let ptrs = rust_ty.matches("*").count();
        let cty = format!("{}{}", cty,
                          iter::repeat("*").take(ptrs).collect::<String>());
        let cast = if name == "SIG_IGN" {"(size_t)"} else {""};
        t!(writeln!(self.c, r#"
            int __test_const_{name}({cty} *out) {{
                int ret = 0;
                #if defined({name})
                    *out = {cast}({name});
                    ret = 1;
                #endif
                return ret;
            }}
        "#, name = name, cast = cast, cty = cty));
        t!(writeln!(self.rust, r#"
            #[test]
            fn const_{name}() {{
                extern {{
                    fn __test_const_{name}(out: *mut {ty}) -> c_int;
                }}
                unsafe {{
                    let mut o = mem::zeroed();
                    if __test_const_{name}(&mut o) == 0 {{
                        panic!("not defined");
                    }} else {{
                        same({name}, o, "value");
                    }}
                }}
            }}
        "#, ty = rust_ty, name = name));
    }

    fn assert_no_generics(&self, _i: &ast::Item, generics: &ast::Generics) {
         assert!(generics.lifetimes.len() == 0);
         assert!(generics.ty_params.len() == 0);
         assert!(generics.where_clause.predicates.len() == 0);
    }

    fn ty2name(&self, ty: &ast::Ty) -> String {
        match ty.node {
            ast::TyPath(_, ref path) => {
                path.segments.last().unwrap().identifier.to_string()
            }
            ast::TyPtr(ref t) => {
                format!("*{} {}", match t.mutbl {
                    ast::MutImmutable => "const",
                    ast::MutMutable => "mut",
                }, self.ty2name(&t.ty))
            }
            _ => panic!("unknown ty {:?}", ty),
        }
    }
}

impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemTy(_, ref generics) => {
                 self.assert_no_generics(i, generics);
                 self.test_type(&i.ident.to_string());
             }

             ast::ItemStruct(ref s, ref generics) => {
                 self.assert_no_generics(i, generics);
                 let is_c = i.attrs.iter().any(|a| {
                    attr::find_repr_attrs(self.sh, a).iter().any(|a| {
                        *a == ReprAttr::ReprExtern
                    })
                 });
                 if !is_c {
                     panic!("{} is not marked #[repr(C)]", i.ident);
                 }
                 self.test_struct(&i.ident.to_string(), s);
             }

             ast::ItemConst(ref ty, _) => {
                 let ty = self.ty2name(ty);
                 self.test_const(&i.ident.to_string(), &ty);
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}

impl<'v> Visitor<'v> for StructFinder {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemStruct(..) => {
                 self.structs.insert(i.ident.to_string());
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}
<commit_msg>Don't worry about unused parameters<commit_after>extern crate gcc;
extern crate syntex_syntax as syntax;

use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::*;
use std::iter;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token::InternedString;
use syntax::attr::{self, ReprAttr};
use syntax::parse::{self, ParseSess};
use syntax::visit::{self, Visitor};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

struct TestGenerator<'a> {
    target: String,
    rust: Box<Write>,
    c: Box<Write>,
    sh: &'a SpanHandler,
    structs: HashSet<String>,
}

struct StructFinder {
    structs: HashSet<String>,
}

impl<'a> TestGenerator<'a> {
    fn defines(&self) -> Vec<&'static str> {
        let mut ret = Vec::new();
        if self.target.contains("unknown-linux") {
            ret.push("_GNU_SOURCE");
        }
        if self.target.contains("msvc") {
            ret.push("alignof __alignof");
        }
        return ret
    }

    fn headers(&self) -> Vec<&'static str> {
        let mut base = Vec::new();

        if self.target.contains("windows") {
            base.push("windows.h");
        }

        base.extend(&[
            "errno.h",
            "fcntl.h",
            "limits.h",
            "stddef.h",
            "stdint.h",
            "stdio.h",
            "stdlib.h",
            "sys/stat.h",
            "sys/types.h",
            "time.h",
            "wchar.h",
        ]);

        if self.target.contains("apple-darwin") {
            base.push("mach/mach_time.h");
        }

        if self.target.contains("unknown-linux") {
            base.push("linux/if_packet.h");
            base.push("net/ethernet.h");
        }

        if self.target.contains("windows") {
            base.push("ws2tcpip.h");
        } else {
            base.push("glob.h");
            base.push("ifaddrs.h");
            base.push("net/if.h");
            base.push("netdb.h");
            base.push("netinet/in.h");
            base.push("netinet/ip.h");
            base.push("netinet/tcp.h");
            base.push("pthread.h");
            base.push("signal.h");
            base.push("stdalign.h");
            base.push("sys/mman.h");
            base.push("sys/resource.h");
            base.push("sys/socket.h");
            base.push("sys/time.h");
            base.push("sys/un.h");
            base.push("utime.h");
            base.push("unistd.h");
        }

        return base
    }

    fn rust2c(&self, ty: &str) -> String {
        match ty {
            t if t.starts_with("c_") => {
                match &ty[2..].replace("long", " long")[..] {
                    s if s.starts_with("u") => format!("unsigned {}", &s[1..]),
                    "short" => format!("short"),
                    s if s.starts_with("s") => format!("signed {}", &s[1..]),
                    s => s.to_string(),
                }
            }
            "ip6_mreq" => "struct ipv6_mreq".to_string(),
            "glob_t" => "glob_t".to_string(),
            t if t.starts_with("pthread") => t.to_string(),

            t if self.structs.contains(t) => format!("struct {}", t),

            t => t.to_string(),
        }
    }

    fn rust2cfield(&self, struct_: &str, field: &str) -> String {
        match field {
            s if s.ends_with("_nsec") && struct_ == "stat" => {
                if self.target.contains("apple-darwin") {
                    s.replace("_nsec", "spec.tv_nsec")
                } else {
                    s.replace("e_nsec", ".tv_nsec")
                }
            }
            s => s.to_string(),
        }
    }

    fn cfg_list(&self) -> Vec<(&'static str, Option<&'static str>)> {
        let mut ret = Vec::new();
        let (arch, target_pointer_width) = if self.target.starts_with("x86_64") {
            ("x86_64", "64")
        } else if self.target.starts_with("i686") {
            ("x86", "32")
        } else {
            panic!("unknown arch/pointer width: {}", self.target)
        };
        let (os, family, env) = if self.target.contains("unknown-linux") {
            ("linux", "unix", "gnu")
        } else if self.target.contains("apple-darwin") {
            ("macos", "unix", "")
        } else if self.target.contains("windows-msvc") {
            ("windows", "windows", "msvc")
        } else if self.target.contains("windows-gnu") {
            ("windows", "windows", "gnu")
        } else {
            panic!("unknown os/family width: {}", self.target)
        };

        ret.push((family, None));
        ret.push(("target_os", Some(os)));
        ret.push(("target_family", Some(family)));
        ret.push(("target_arch", Some(arch)));
        // skip endianness
        ret.push(("target_pointer_width", Some(target_pointer_width)));
        ret.push(("target_env", Some(env)));

        return ret
    }
}

fn main() {
    // Prep the test generator
    let target = t!(env::var("TARGET"));
    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let rust_out = BufWriter::new(t!(File::create(out.join("all.rs"))));
    let c_out = BufWriter::new(t!(File::create(out.join("all.c"))));
    let sess = ParseSess::new();
    let mut tg = TestGenerator {
        target: target,
        rust: Box::new(rust_out),
        c: Box::new(c_out),
        sh: &sess.span_diagnostic,
        structs: HashSet::new(),
    };

    // Parse the libc crate
    let src = Path::new("../src/lib.rs");
    let cfg = Vec::new();
    let mut krate = parse::parse_crate_from_file(src, cfg, &sess);

    // Strip the crate down to just what's configured for our target
    for (k, v) in tg.cfg_list() {
        let s = InternedString::new;
        krate.config.push(match v {
            Some(v) => attr::mk_name_value_item_str(s(k), s(v)),
            None => attr::mk_word_item(s(k)),
        });
    }
    let mut gated_cfgs = Vec::new();
    let krate = syntax::config::strip_unconfigured_items(&sess.span_diagnostic,
                                                         krate,
                                                         &mut gated_cfgs);

    // Probe the crate to find all structs (used to convert type names to names
    // in C).
    let mut structs = StructFinder {
        structs: HashSet::new(),
    };
    visit::walk_crate(&mut structs, &krate);
    tg.structs = structs.structs;

    // Prep the C file by emitting header stuff
    for define in tg.defines() {
        t!(writeln!(tg.c, "#define {}", define));
    }
    for header in tg.headers() {
        t!(writeln!(tg.c, "#include <{}>", header));
    }

    // Walk the crate, emitting test cases for everything found
    visit::walk_crate(&mut tg, &krate);

    // Compile our C shim to be linked into tests
    let mut cfg = gcc::Config::new();
    cfg.file(out.join("all.c"));

    if tg.target.contains("msvc") {
        cfg.flag("/W3").flag("/Wall").flag("/WX");
    } else {
        cfg.flag("-Wall").flag("-Wextra").flag("-Werror")
           .arg("-Wno-unused-parameter");
    }

    drop(tg);
    cfg.compile("liball.a");
}

impl<'a> TestGenerator<'a> {
    fn test_type(&mut self, ty: &str) {
        match ty {
            "sighandler_t" => return,
            _ => {}
        }
        let c = self.rust2c(ty);
        self.test_size_align(ty, &c);
    }

    fn test_struct(&mut self, ty: &str, s: &ast::StructDef) {
        let cty = self.rust2c(ty);
        self.test_size_align(ty, &cty);

        t!(writeln!(self.rust, r#"
            #[test]
            fn field_offset_size_{ty}() {{
        "#, ty = ty));
        for field in s.fields.iter() {
            let name = match field.node.kind {
                ast::NamedField(name, ast::Public) => name,
                ast::NamedField(_, ast::Inherited) => continue,
                ast::UnnamedField(..) => panic!("no tuple structs in FFI"),
            };

            let cfield = self.rust2cfield(ty, &name.to_string());

            t!(writeln!(self.c, r#"
                uint64_t __test_offset_{ty}_{rust_field}() {{
                    return offsetof({cty}, {c_field});
                }}
                uint64_t __test_size_{ty}_{rust_field}() {{
                    {cty}* foo = NULL;
                    return sizeof(foo->{c_field});
                }}
            "#, ty = ty, cty = cty, rust_field = name, c_field = cfield));
            t!(writeln!(self.rust, r#"
                extern {{
                    fn __test_offset_{ty}_{field}() -> u64;
                    fn __test_size_{ty}_{field}() -> u64;
                }}
                unsafe {{
                    let foo = 0 as *const {ty};
                    same(offset_of!({ty}, {field}),
                         __test_offset_{ty}_{field}(),
                         "field offset {field} of {ty}");
                    same(mem::size_of_val(&(*foo).{field}) as u64,
                         __test_size_{ty}_{field}(),
                         "field size {field} of {ty}");
                }}
            "#, ty = ty, field = name));
        }
        t!(writeln!(self.rust, r#"
            }}
        "#));
    }

    fn test_size_align(&mut self, rust: &str, c: &str) {
        t!(writeln!(self.c, r#"
            uint64_t __test_size_{ty}() {{ return sizeof({cty}); }}
            uint64_t __test_align_{ty}() {{ return alignof({cty}); }}
        "#, ty = rust, cty = c));
        t!(writeln!(self.rust, r#"
            #[test]
            fn size_align_{ty}() {{
                extern {{
                    fn __test_size_{ty}() -> u64;
                    fn __test_align_{ty}() -> u64;
                }}
                unsafe {{
                    same(mem::size_of::<{ty}>() as u64,
                         __test_size_{ty}(), "size");
                    same(align::<{ty}>() as u64,
                         __test_align_{ty}(), "align");
                }}
            }}
        "#, ty = rust));
    }

    fn test_const(&mut self, name: &str, rust_ty: &str) {
        let cty = self.rust2c(&rust_ty.replace("*mut ", "")
                                      .replace("*const ", ""));
        let ptrs = rust_ty.matches("*").count();
        let cty = format!("{}{}", cty,
                          iter::repeat("*").take(ptrs).collect::<String>());
        let cast = if name == "SIG_IGN" {"(size_t)"} else {""};
        t!(writeln!(self.c, r#"
            int __test_const_{name}({cty} *out) {{
                int ret = 0;
                #if defined({name})
                    *out = {cast}({name});
                    ret = 1;
                #endif
                return ret;
            }}
        "#, name = name, cast = cast, cty = cty));
        t!(writeln!(self.rust, r#"
            #[test]
            fn const_{name}() {{
                extern {{
                    fn __test_const_{name}(out: *mut {ty}) -> c_int;
                }}
                unsafe {{
                    let mut o = mem::zeroed();
                    if __test_const_{name}(&mut o) == 0 {{
                        panic!("not defined");
                    }} else {{
                        same({name}, o, "value");
                    }}
                }}
            }}
        "#, ty = rust_ty, name = name));
    }

    fn assert_no_generics(&self, _i: &ast::Item, generics: &ast::Generics) {
         assert!(generics.lifetimes.len() == 0);
         assert!(generics.ty_params.len() == 0);
         assert!(generics.where_clause.predicates.len() == 0);
    }

    fn ty2name(&self, ty: &ast::Ty) -> String {
        match ty.node {
            ast::TyPath(_, ref path) => {
                path.segments.last().unwrap().identifier.to_string()
            }
            ast::TyPtr(ref t) => {
                format!("*{} {}", match t.mutbl {
                    ast::MutImmutable => "const",
                    ast::MutMutable => "mut",
                }, self.ty2name(&t.ty))
            }
            _ => panic!("unknown ty {:?}", ty),
        }
    }
}

impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemTy(_, ref generics) => {
                 self.assert_no_generics(i, generics);
                 self.test_type(&i.ident.to_string());
             }

             ast::ItemStruct(ref s, ref generics) => {
                 self.assert_no_generics(i, generics);
                 let is_c = i.attrs.iter().any(|a| {
                    attr::find_repr_attrs(self.sh, a).iter().any(|a| {
                        *a == ReprAttr::ReprExtern
                    })
                 });
                 if !is_c {
                     panic!("{} is not marked #[repr(C)]", i.ident);
                 }
                 self.test_struct(&i.ident.to_string(), s);
             }

             ast::ItemConst(ref ty, _) => {
                 let ty = self.ty2name(ty);
                 self.test_const(&i.ident.to_string(), &ty);
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}

impl<'v> Visitor<'v> for StructFinder {
     fn visit_item(&mut self, i: &'v ast::Item) {
         match i.node {
             ast::ItemStruct(..) => {
                 self.structs.insert(i.ident.to_string());
             }

             _ => {}
         }
         visit::walk_item(self, i)
     }
}
<|endoftext|>


<commit_before>fn to_palindromic(n: u64, dup_flag: bool) -> u64 {
    let cs = str::chars(u64::to_str(n, 10u));
    let s = str::from_chars(
        if dup_flag { cs + vec::tail(vec::reversed(cs)) } else { cs + vec::reversed(cs) }
    );
    alt u64::from_str(s, 10u) {
      none    { fail }
      some(x) { ret x }
    }
}

fn dividable_pairs(num: u64, min: u64, max: u64) -> [(u64, u64)] {
    let mut div = u64::max(uint::div_ceil(num, max), min);
    let mut result = [];
    while div * div <= num {
        if num % div == 0u64 {
            result += [(div, num / div)];
        }
        div += 1u64;
    }
    ret result;
}

fn main() {
    let mut dup_flag = false;
    while true {
        let mut seed = 999u64;
        while (seed >= 100u64) {
            let num = to_palindromic(seed, dup_flag);
            let pairs = dividable_pairs(num, 100u64, 999u64);
            if vec::is_not_empty(pairs) {
                io::print(#fmt("%u", num));
                for pairs.each() { |tp|
                    let (d1, d2) = tp;
                    io::print(#fmt(" = %u * %u", d1, d2));
                }
                io::print("\n");
            }
            seed -= 1u64;
        }
        if (!dup_flag) {
            dup_flag = true;
        } else {
            break
        }
    }
}
<commit_msg>Use `loop` instead of `while true`<commit_after>fn to_palindromic(n: u64, dup_flag: bool) -> u64 {
    let cs = str::chars(u64::to_str(n, 10u));
    let s = str::from_chars(
        if dup_flag { cs + vec::tail(vec::reversed(cs)) } else { cs + vec::reversed(cs) }
    );
    alt u64::from_str(s, 10u) {
      none    { fail }
      some(x) { ret x }
    }
}

fn dividable_pairs(num: u64, min: u64, max: u64) -> [(u64, u64)] {
    let mut div = u64::max(uint::div_ceil(num, max), min);
    let mut result = [];
    while div * div <= num {
        if num % div == 0u64 {
            result += [(div, num / div)];
        }
        div += 1u64;
    }
    ret result;
}

fn main() {
    let mut dup_flag = false;
    loop {
        let mut seed = 999u64;
        while (seed >= 100u64) {
            let num = to_palindromic(seed, dup_flag);
            let pairs = dividable_pairs(num, 100u64, 999u64);
            if vec::is_not_empty(pairs) {
                io::print(#fmt("%u", num));
                for pairs.each() { |tp|
                    let (d1, d2) = tp;
                    io::print(#fmt(" = %u * %u", d1, d2));
                }
                io::print("\n");
            }
            seed -= 1u64;
        }
        if (!dup_flag) {
            dup_flag = true;
        } else {
            break
        }
    }
}
<|endoftext|>


<commit_before>
macro_rules! NODE_ID
{
  () => { < < Self as GraphNodesNominalInterface >::NodeHandle as HasId >::Id };
}

macro_rules! EDGE_ID
{
  () => { < < Self as GraphEdgesNominalInterface >::EdgeHandle as HasId >::Id };
}

impls!
{

  //

  fn node< IntoId >( &self, id : IntoId ) -> &Self::NodeHandle
  where
    IntoId : Into< NODE_ID!() >,
  {
    let id = id.into();
    let got = self.id_to_node_map.get( &id );
    if got.is_some()
    {
      let result : &Self::NodeHandle = got.unwrap();
      return result;
    }
    unreachable!( "No node with id {:?} found", id );
  }

  //

  fn nodes< 'a, 'b >( &'a self )
  ->
  // impl Iterator< Item = ( NODE_ID!(), &'b < Self as GraphNodesNominalInterface >::NodeHandle ) >
  Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
  // It
  // core::slice::Iter< 'a, ( NODE_ID!(), &'b < Self as GraphNodesNominalInterface >::NodeHandle ) >
  where
    'a : 'b,
    // It : Iterator< Item = ( NODE_ID!(), &'b < Self as GraphNodesNominalInterface >::NodeHandle ) >,
  {
    Box::new( self.id_to_node_map.iter().map( | el | ( *el.0, el.1 ) ) )
  }

  //

  fn nnodes( &self ) -> usize
  {
    self.id_to_node_map.len()
  }

  //

  fn edge< IntoId >( &self, id : IntoId ) -> &Self::EdgeHandle
  where
    IntoId : Into< EDGE_ID!() >,
  {
    let id = id.into();
    let got = self.id_to_edge_map.get( &id );
    if got.is_some()
    {
      let result : &Self::EdgeHandle = got.unwrap();
      return result;
    }
    unreachable!( "No edge with id {:?} found", id );
  }

  //

  fn edges< 'a, 'b >( &'a self )
  ->
  Box< dyn Iterator< Item = ( EDGE_ID!(), &Self::EdgeHandle ) > + 'b >
  where
    'a : 'b,
  {
    Box::new( self.id_to_edge_map.iter().map( | el | ( *el.0, el.1 ) ) )
  }

  //

  fn nedges( &self ) -> usize
  {
    self.id_to_edge_map.len()
  }

  //

  fn node_mut< IntoId >( &mut self, id : IntoId ) -> &mut Self::NodeHandle
  where
    IntoId : Into< NODE_ID!() >
  {
    let id = id.into();
    let got = self.id_to_node_map.get_mut( &id );
    if got.is_some()
    {
      let result : &mut Self::NodeHandle = got.unwrap();
      return result;
    }
    unreachable!( "No node with id {:?} found", id );
  }

  //

  fn node_making< IntoId >( &mut self, id : IntoId ) -> NODE_ID!()
  where
    IntoId : Into< NODE_ID!() >,
  {
    let id = id.into();

    let result = self.id_to_node_map
    .entry( id )
    .or_insert_with( || canonical::Node::make_with_id( id ).into() )
    ;
    result.id()
  }

  //

  fn _edge_id_generate( &mut self, _in_node : NODE_ID!(), _out_node : NODE_ID!() ) -> EDGE_ID!()
  {
    while self.id_to_edge_map.contains_key( &self._current_edge_id )
    {
      self._current_edge_id = self._current_edge_id.next();
      assert!( self._current_edge_id.is_valid(), "Not more space for ids" );
    }
    self._current_edge_id
  }

  //

  fn _edge_add( &mut self, edge_id : EDGE_ID!(), in_node : NODE_ID!(), out_node : NODE_ID!() )
  {

    self.id_to_edge_map
    .entry( edge_id )
    .and_modify( | _ | { panic!( "Edge {:?} already exists", edge_id ) } )
    .or_insert_with( ||
    {
      canonical::Edge
      {
        id : edge_id,
        in_node,
        out_node,
        kind : Default::default(),
      }
    });

  }

  //

  fn make_0() -> Self
  {
    let id_to_node_map = IndexMap::new();
    let id_to_edge_map = IndexMap::new();
    let _current_edge_id = EdgeId::first();
    Self
    {
      id_to_node_map,
      id_to_edge_map,
      _current_edge_id,
    }
  }

  //

  fn fmt( &self, f : &mut fmt::Formatter<'_> ) -> fmt::Result
  {
    f.write_fmt( format_args!( "NodeFactory\n" ) )?;
    let mut first = true;
    for ( _id, node ) in self.nodes()
    {
      if !first
      {
        f.write_str( "\n" )?;
      }
      first = false;
      f.write_str( &wtools::string::indentation( "  ", format!( "{:?}", node ), "" ) )?;
    }
    f.write_str( "" )
  }

}
<commit_msg>!test<commit_after>
macro_rules! NODE_ID
{
  () => { < < Self as GraphNodesNominalInterface >::NodeHandle as HasId >::Id };
}

macro_rules! EDGE_ID
{
  () => { < < Self as GraphEdgesNominalInterface >::EdgeHandle as HasId >::Id };
}

impls!
{

  //

  fn node< IntoId >( &self, id : IntoId ) -> &Self::NodeHandle
  where
    IntoId : Into< NODE_ID!() >,
  {
    let id = id.into();
    let got = self.id_to_node_map.get( &id );
    if got.is_some()
    {
      let result : &Self::NodeHandle = got.unwrap();
      return result;
    }
    unreachable!( "No node with id {:?} found", id );
  }

  //

  fn nodes< 'a, 'b >( &'a self )
  ->
  // impl Iterator< Item = ( NODE_ID!(), &'b < Self as GraphNodesNominalInterface >::NodeHandle ) >
  Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
  // It
  // core::slice::Iter< 'a, ( NODE_ID!(), &'b < Self as GraphNodesNominalInterface >::NodeHandle ) >
  where
    'a : 'b,
    // It : Iterator< Item = ( NODE_ID!(), &'b < Self as GraphNodesNominalInterface >::NodeHandle ) >,
  {
    Box::new( self.id_to_node_map.iter().map( | el | ( *el.0, el.1 ) ) )
  }

  //

  fn nnodes( &self ) -> usize
  {
    self.id_to_node_map.len()
  }

  //

  fn edge< IntoId >( &self, id : IntoId ) -> &Self::EdgeHandle
  where
    IntoId : Into< EDGE_ID!() >,
  {
    let id = id.into();
    let got = self.id_to_edge_map.get( &id );
    if got.is_some()
    {
      let result : &Self::EdgeHandle = got.unwrap();
      return result;
    }
    unreachable!( "No edge with id {:?} found", id );
  }

  //

  fn edges< 'a, 'b >( &'a self )
  ->
  Box< dyn Iterator< Item = ( EDGE_ID!(), &Self::EdgeHandle ) > + 'b >
  where
    'a : 'b,
  {
    Box::new( self.id_to_edge_map.iter().map( | el | ( *el.0, el.1 ) ) )
  }

  //

  fn nedges( &self ) -> usize
  {
    self.id_to_edge_map.len()
  }

  //

  fn node_mut< IntoId >( &mut self, id : IntoId ) -> &mut Self::NodeHandle
  where
    IntoId : Into< NODE_ID!() >
  {
    let id = id.into();
    let got = self.id_to_node_map.get_mut( &id );
    if got.is_some()
    {
      let result : &mut Self::NodeHandle = got.unwrap();
      return result;
    }
    unreachable!( "No node with id {:?} found", id );
  }

  //

  fn node_making< IntoId >( &mut self, id : IntoId ) -> NODE_ID!()
  where
    IntoId : Into< NODE_ID!() >,
  {
    let id = id.into();

    let result = self.id_to_node_map
    .entry( id )
    .or_insert_with( || canonical::Node::make_with_id( id ).into() )
    ;
    result.id()
  }

  //

  fn _edge_id_generate( &mut self, _in_node : NODE_ID!(), _out_node : NODE_ID!() ) -> EDGE_ID!()
  {
    while self.id_to_edge_map.contains_key( &self._current_edge_id )
    {
      self._current_edge_id = self._current_edge_id.next();
      assert!( self._current_edge_id.is_valid(), "Not more space for ids" );
    }
    self._current_edge_id
  }

  //

  fn _edge_add( &mut self, edge_id : EDGE_ID!(), in_node : NODE_ID!(), out_node : NODE_ID!() )
  {

    self.id_to_edge_map
    .entry( edge_id )
    .and_modify( | _ | { panic!( "Edge {:?} already exists", edge_id ) } )
    .or_insert_with( ||
    {
      canonical::Edge
      {
        id : edge_id,
        in_node,
        out_node,
        kind : Default::default(),
      }
    });

  }

  //

  fn make_0() -> Self
  {
    let id_to_node_map = IndexMap::new();
    let id_to_edge_map = IndexMap::new();
    let _current_edge_id = EdgeId::first();
    Self
    {
      id_to_node_map,
      id_to_edge_map,
      _current_edge_id,
    }
  }

  //

  fn fmt( &self, f : &mut fmt::Formatter<'_> ) -> fmt::Result
  {
    f.write_fmt( format_args!( "NodeFactory\n" ) )?;
    let mut first = true;
    for ( _id, node ) in self.nodes()
    {
      if !first
      {
        f.write_str( "\n" )?;
      }
      first = false;
      f.write_str( &wtools::string::indentation( "  ", format!( "{:?}", node ), "" ) )?;
    }
    f.write_str( "" )
  }

}

<|endoftext|>