<commit_before>//
//  rss reader - main program
//
//
extern crate reqwest;
extern crate xml;
extern crate chrono;
use std::convert;
use std::io;
use std::io::Read;
use std::fmt;
use std::env;
use wordwrap;

//
//  xml::Element utility functions.
//  These should be in the XML module.
//
//
//  find_all --  find all elements for which test function returns true.
//
//  Someday this will accept unboxed lambdas for testfn, but that's not working yet in Rust 1.0 pre-alpha
//
pub fn find_all<'a>(tree: &'a xml::Element, testfn: fn(&xml::Element) -> bool, finds: &mut Vec<&'a xml::Element>, recurse: bool) {
    if testfn(tree)                                         // if match
    {   finds.push(tree);                                   // save if match on name
        if !recurse { return }                              // don't explore within finds if non-recursive
    }
    for child in tree.children.iter() {                     // for all children
        match *child {                                      // child is an Xml enum
            xml::Xml::ElementNode(ref childelt) => { find_all(childelt, testfn, finds, recurse ); }, // do ElementNode recursively
            _ => ()                                         // ignore non ElementNode children
        }                                                   // end match child
    }
}
//
//  find_all_text -- find all text below a tag.
//
pub fn find_all_text<'a>(tree: &'a xml::Element, s: &mut String, recurse: bool) {
    for child in tree.children.iter() {                     // for all children
        match *child {                                      // child is an Xml enum
            xml::Xml::ElementNode(ref childelt) => {
                if recurse {
                    find_all_text(childelt, s, recurse);    // do ElementNode recursively
                    }
                },
            xml::Xml::CharacterNode(ref text) => { s.push_str(text) }  // append text
            _ => ()                                         // ignore non ElementNode children
        }                                                   // end match child
    }
}
//
//  find_tag_text -- find text of single tag for which test function returns true.
//
//  No find, or multiple finds. return an empty string.
//
//  Yes, it's somewhat inefficient to create a Vec and collect all the items to find only one.
//
pub fn find_tag_text(tree: &xml::Element, testfn: fn(&xml::Element) -> bool, s: &mut String) {
    let mut itemelts = Vec::<&xml::Element>::new();         // accumulate tag elements
    find_all(tree, testfn, &mut itemelts, false);           // find item elts
    if itemelts.len() != 1 { return }                       // should be a singleton
    find_all_text(itemelts[0], s, false);                   // find text
}

//
//  Return type and its error handling
//
pub type FeedResult<T> = Result<T, FeedError>;

/// A set of errors that can occur handling RSS or Atom feeds.
//#[derive(Debug, PartialEq, Clone)] // crank out default functions
pub enum FeedError {
    /// Error detected at the I/O level
    Io(io::Error),
    /// Error detected at the HTTP level
    Http(reqwest::Error),
    /// Error detected at the XML parsing level
    XMLParse(xml::BuilderError),
    /// Error detected at the date parsing level
    DateParse(chrono::format::ParseError),
    /// XML, but feed type not recognized,
    UnknownFeedType,
    /// Required feed field missing or invalid
    Field(String),
    /// Got an HTML page instead of an XML page
    WasHTML(String)
}
//
//  Encapsulate errors from each of the lower level error types
//
impl convert::From<reqwest::Error> for FeedError {
    fn from(err: reqwest::Error) -> FeedError {
        FeedError::Http(err)
    }
}
impl convert::From<io::Error> for FeedError {
    fn from(err: io::Error) -> FeedError {
        FeedError::Io(err)
    }
}

impl convert::From<xml::BuilderError> for FeedError {
    fn from(err: xml::BuilderError) -> FeedError {
        FeedError::XMLParse(err)
    }
}

impl convert::From<chrono::format::ParseError> for FeedError {
    fn from(err: chrono::format::ParseError) -> FeedError {
        FeedError::DateParse(err)
    }
}

impl fmt::Display for FeedError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            FeedError::Io(ref xerr) => xerr.fmt(f),   // I/O error
            FeedError::Http(ref xerr) => xerr.fmt(f), // HTTP error
            FeedError::XMLParse(ref xerr) => xerr.fmt(f), // XML parse error
            FeedError::DateParse(ref xerr) => xerr.fmt(f), // Date parse error
            FeedError::UnknownFeedType => write!(f, "Unknown feed type."),
            FeedError::Field(ref s) => write!(f, "Required field \"{}\" missing from RSS/Atom feed.", s),
            FeedError::WasHTML(ref s) => write!(f, "Expected an RSS/ATOM feed but received a web page \"{}\".", s)
            //_(ref xerr) => xerr.fmt(f) // would be convenient, but not allowed in Rust.
        }
    }
}

//
//  FeedChannel --  an RSS or Atom channel
//
pub struct FeedChannel {
    title: String,                                          // channel title
    link: String,                                           // URL of channel (from RSS channel)
    description: String,                                    // channel description if present
    }
//
//  FeedItem - a RSS or Atom feed item
//
pub struct FeedItem {
    title: String,                                          // the title
    description: String,                                    // the description, i.e. content, as HTML
    author: String,                                         // name of author
    pubdate: chrono::DateTime<chrono::FixedOffset>          // publication date
    }
//
//  FeedReply -- data returned from a feed
//
pub struct FeedReply {
    channel: FeedChannel,                                   // channel info
    items: Vec<FeedItem>                                    // items found
    }

impl FeedItem {
    pub fn dump(&self){                                     // dump content for debug
        println!("Feed Item");
        println!(" Title: {}", self.title);
        println!(" Author: {}", self.author);
        println!(" Publication date: {}", self.pubdate);
        println!(" Description:\n{}", &wordwrap::wordwrap(&self.description, 72,20));
        println!();
    }
}

impl FeedChannel {
    pub fn new() -> FeedChannel {
        FeedChannel{title: String::new(), link: String::new(), description: String::new()}
    }

    pub fn dump(&self) {
        println!("Feed Channel");
        println!(" Title: {}", self.title);
        println!(" Link: {}", self.link);
        println!(" Description: {}", self.description);
        println!();
    }
}

impl FeedReply {
    pub fn new() -> FeedReply {
        FeedReply{channel: FeedChannel::new(), items: Vec::<FeedItem>::new()}
    }

    pub fn dump(&self) {
        self.channel.dump();
        for item in self.items.iter() {
            item.dump()
        }
    }
}
//
//  handletree  --  handle a tree generated by the XML parser
//
//  May be RSS, Atom, or HTML.
//
//  HTML is an error, usually indicating some problem with a firewall or the site.
//
pub fn handletree(tree: &xml::Element, reply: &mut FeedReply) -> FeedResult<()> {
                                                            // ***MORE***
    handlersstree(tree, reply)                              // for now, just RSS
}
//
//  handlersstree -- handle a tree of RSS items
//
pub fn handlersstree(tree: &xml::Element, reply: &mut FeedReply) -> FeedResult<()> {
    //println!("Tree: {}\n\n", tree);                       // ***TEMP***
    //  ***NEED TO COLLECT CHANNEL INFO***
    let mut itemelts = Vec::<&xml::Element>::new();         // accumulate ITEM entries
    fn isitem(e: &xml::Element) -> bool { e.name == "item" }// someday this will be an unboxed lambda
    find_all(tree, isitem, &mut itemelts, false);           // find all items
    for itemelt in itemelts.iter() {                        // extract important fields from items
        let mut authorstr = String::new();                  // title string
        fn isauthor(e: &xml::Element) -> bool { e.name == "author" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, isauthor, &mut authorstr);

        let mut pubdatestr = String::new();                 // date string
        fn ispubdate(e: &xml::Element) -> bool { e.name == "pubDate" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, ispubdate, &mut pubdatestr);
        let pubtimestamp = match chrono::DateTime::parse_from_rfc2822(&pubdatestr) {
            Ok(date) => date,
            Err(xerr) => return Err(convert::From::from(xerr))
        };

        let mut titlestr = String::new();                   // title string
        fn istitle(e: &xml::Element) -> bool { e.name == "title" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, istitle, &mut titlestr);

        let mut descriptionstr = String::new();             // description string
        fn isdescription(e: &xml::Element) -> bool { e.name == "description" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, isdescription, &mut descriptionstr);

        let feeditem = FeedItem{title: titlestr, description: descriptionstr, author: authorstr, pubdate: pubtimestamp};
        reply.items.push(feeditem);
    }
    ////println!("Item: {}", item);
    Ok(())
}
//
//  readfeed -- read from an RSS or Atom feed.
//
pub fn readfeed(url: &str, reply: &mut FeedReply, verbose: bool) -> FeedResult<()> {
    ////let client = hyper::Client::new();                  // create HTTP client from Hyper crate.
    let mut res = match reqwest::blocking::get(url) {
    ////let mut res = match client.get(url).send() {            // HTTP GET request
        Ok(res) => res,
        Err(xerr) => return Err(convert::From::from(xerr)) // fails, return error
    };
    //  Successful read of URL.  Have valid result object.
    if verbose {
        println!("Response: {}", res.status());               // debug print
        println!("Headers:\n{:?}", res.headers());
    }
    let mut p = xml::Parser::new();                         // get XML parser
    let mut e = xml::ElementBuilder::new();                 // get tree builder
    let mut ws = String::new();                             // get work string for XML
    match res.read_to_string(&mut ws) {                     // read the XML
        Ok(_) => (),                                        // OK, keep going
        Err(xerr) => { return Err(convert::From::from(xerr)) }   // I/O error
    };
    p.feed_str(&ws[..]);                                    // prepare XML parser
    for event in p {                                        // for each full XML tree (normally only one)
        match e.handle_event(event) {                       // process the tree
            Some(rep) => {                                  // returns an Option wrapped around a Result
                match rep {
                    Ok(ev) => match handletree(&ev, reply) {// we have an XML tree to process
                        Ok(()) => (),
                        Err(xerr) => return Err(xerr)   // RSS/Atom error
                        },                                  // end match handletree
                    Err(xerr) => return Err(convert::From::from(xerr))
                    }                                       // end match rep
                }                                           // end some rep
            None => ()                                      // no full tree yet, keep going
        }                                                   // end match handle_event
    }                                                       // end for
    Ok(())
}

//
//  test1  -- temporary test function
//
//  Ask for URL of RSS feed, handle it.
//
pub fn test1() {
    let args : Vec<_> = env::args().collect();      // command line args as vector of strings
    match args.len() {
        2 => (),
        _ => {
            println!("Usage: client <url>");
            return;
        }
    };
    let url = &*args[1];
    println!("Reading \"{}\"", url);
    let mut result = FeedReply::new();            // accumulate ITEM entries
    let res = readfeed(url, &mut result, true);
    match res {
        Ok(_) => println!("OK."),
        Err(err) => println!("Error: {}", err)
        }
    result.dump();
}
//
//  Unit tests.
//
#[test]
fn testreutersrss() {
    ////let url = "http://feeds.reuters.com/reuters/topNews?format=xml";    // ***TEMP***
    let url = "https://rss.nytimes.com/services/xml/rss/nyt/World.xml";
    let mut freply = FeedReply::new();            // accumulate ITEM entries
    let res = readfeed(url, &mut freply, true);
    match res {
        Ok(_) => println!("OK."),
        Err(err) => panic!("Error: {}", err)
        }
    freply.dump();
}

<commit_msg>Cleanup per Clippy<commit_after>//
//  rss reader - main program
//
//
extern crate reqwest;
extern crate xml;
extern crate chrono;
use std::convert;
use std::io;
use std::io::Read;
use std::fmt;
use std::env;
use wordwrap;

//
//  xml::Element utility functions.
//  These should be in the XML module.
//
//
//  find_all --  find all elements for which test function returns true.
//
//  Someday this will accept unboxed lambdas for testfn, but that's not working yet in Rust 1.0 pre-alpha
//
pub fn find_all<'a>(tree: &'a xml::Element, testfn: fn(&xml::Element) -> bool, finds: &mut Vec<&'a xml::Element>, recurse: bool) {
    if testfn(tree)                                         // if match
    {   finds.push(tree);                                   // save if match on name
        if !recurse { return }                              // don't explore within finds if non-recursive
    }
    for child in tree.children.iter() {                     // for all children
        if let xml::Xml::ElementNode(ref childelt) = *child { find_all(childelt, testfn, finds, recurse ); }
    }
}
//
//  find_all_text -- find all text below a tag.
//
pub fn find_all_text(tree: &xml::Element, s: &mut String, recurse: bool) {
    for child in tree.children.iter() {                     // for all children
        match *child {                                      // child is an Xml enum
            xml::Xml::ElementNode(ref childelt) => {
                if recurse {
                    find_all_text(childelt, s, recurse);    // do ElementNode recursively
                    }
                },
            xml::Xml::CharacterNode(ref text) => { s.push_str(text) }  // append text
            _ => ()                                         // ignore non ElementNode children
        }                                                   // end match child
    }
}
//
//  find_tag_text -- find text of single tag for which test function returns true.
//
//  No find, or multiple finds. return an empty string.
//
//  Yes, it's somewhat inefficient to create a Vec and collect all the items to find only one.
//
pub fn find_tag_text(tree: &xml::Element, testfn: fn(&xml::Element) -> bool, s: &mut String) {
    let mut itemelts = Vec::<&xml::Element>::new();         // accumulate tag elements
    find_all(tree, testfn, &mut itemelts, false);           // find item elts
    if itemelts.len() != 1 { return }                       // should be a singleton
    find_all_text(itemelts[0], s, false);                   // find text
}

//
//  Return type and its error handling
//
pub type FeedResult<T> = Result<T, FeedError>;

/// A set of errors that can occur handling RSS or Atom feeds.
//#[derive(Debug, PartialEq, Clone)] // crank out default functions
pub enum FeedError {
    /// Error detected at the I/O level
    Io(io::Error),
    /// Error detected at the HTTP level
    Http(reqwest::Error),
    /// Error detected at the XML parsing level
    XMLParse(xml::BuilderError),
    /// Error detected at the date parsing level
    DateParse(chrono::format::ParseError),
    /// XML, but feed type not recognized,
    UnknownFeedType,
    /// Required feed field missing or invalid
    Field(String),
    /// Got an HTML page instead of an XML page
    WasHTML(String)
}
//
//  Encapsulate errors from each of the lower level error types
//
impl convert::From<reqwest::Error> for FeedError {
    fn from(err: reqwest::Error) -> FeedError {
        FeedError::Http(err)
    }
}
impl convert::From<io::Error> for FeedError {
    fn from(err: io::Error) -> FeedError {
        FeedError::Io(err)
    }
}

impl convert::From<xml::BuilderError> for FeedError {
    fn from(err: xml::BuilderError) -> FeedError {
        FeedError::XMLParse(err)
    }
}

impl convert::From<chrono::format::ParseError> for FeedError {
    fn from(err: chrono::format::ParseError) -> FeedError {
        FeedError::DateParse(err)
    }
}

impl fmt::Display for FeedError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            FeedError::Io(ref xerr) => xerr.fmt(f),   // I/O error
            FeedError::Http(ref xerr) => xerr.fmt(f), // HTTP error
            FeedError::XMLParse(ref xerr) => xerr.fmt(f), // XML parse error
            FeedError::DateParse(ref xerr) => xerr.fmt(f), // Date parse error
            FeedError::UnknownFeedType => write!(f, "Unknown feed type."),
            FeedError::Field(ref s) => write!(f, "Required field \"{}\" missing from RSS/Atom feed.", s),
            FeedError::WasHTML(ref s) => write!(f, "Expected an RSS/ATOM feed but received a web page \"{}\".", s)
            //_(ref xerr) => xerr.fmt(f) // would be convenient, but not allowed in Rust.
        }
    }
}

//
//  FeedChannel --  an RSS or Atom channel
//
pub struct FeedChannel {
    title: String,                                          // channel title
    link: String,                                           // URL of channel (from RSS channel)
    description: String,                                    // channel description if present
    }
//
//  FeedItem - a RSS or Atom feed item
//
pub struct FeedItem {
    title: String,                                          // the title
    description: String,                                    // the description, i.e. content, as HTML
    author: String,                                         // name of author
    pubdate: chrono::DateTime<chrono::FixedOffset>          // publication date
    }
//
//  FeedReply -- data returned from a feed
//
pub struct FeedReply {
    channel: FeedChannel,                                   // channel info
    items: Vec<FeedItem>                                    // items found
    }

impl FeedItem {
    pub fn dump(&self){                                     // dump content for debug
        println!("Feed Item");
        println!(" Title: {}", self.title);
        println!(" Author: {}", self.author);
        println!(" Publication date: {}", self.pubdate);
        println!(" Description:\n{}", &wordwrap::wordwrap(&self.description, 72,20));
        println!();
    }
}

impl FeedChannel {
    pub fn new() -> FeedChannel {
        FeedChannel{title: String::new(), link: String::new(), description: String::new()}
    }

    pub fn dump(&self) {
        println!("Feed Channel");
        println!(" Title: {}", self.title);
        println!(" Link: {}", self.link);
        println!(" Description: {}", self.description);
        println!();
    }
}

impl FeedReply {
    pub fn new() -> FeedReply {
        FeedReply{channel: FeedChannel::new(), items: Vec::<FeedItem>::new()}
    }

    pub fn dump(&self) {
        self.channel.dump();
        for item in self.items.iter() {
            item.dump()
        }
    }
}
//
//  handletree  --  handle a tree generated by the XML parser
//
//  May be RSS, Atom, or HTML.
//
//  HTML is an error, usually indicating some problem with a firewall or the site.
//
pub fn handletree(tree: &xml::Element, reply: &mut FeedReply) -> FeedResult<()> {
                                                            // ***MORE***
    handlersstree(tree, reply)                              // for now, just RSS
}
//
//  handlersstree -- handle a tree of RSS items
//
pub fn handlersstree(tree: &xml::Element, reply: &mut FeedReply) -> FeedResult<()> {
    //println!("Tree: {}\n\n", tree);                       // ***TEMP***
    //  ***NEED TO COLLECT CHANNEL INFO***
    let mut itemelts = Vec::<&xml::Element>::new();         // accumulate ITEM entries
    fn isitem(e: &xml::Element) -> bool { e.name == "item" }// someday this will be an unboxed lambda
    find_all(tree, isitem, &mut itemelts, false);           // find all items
    for itemelt in itemelts.iter() {                        // extract important fields from items
        let mut authorstr = String::new();                  // title string
        fn isauthor(e: &xml::Element) -> bool { e.name == "author" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, isauthor, &mut authorstr);

        let mut pubdatestr = String::new();                 // date string
        fn ispubdate(e: &xml::Element) -> bool { e.name == "pubDate" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, ispubdate, &mut pubdatestr);
        let pubtimestamp = match chrono::DateTime::parse_from_rfc2822(&pubdatestr) {
            Ok(date) => date,
            Err(xerr) => return Err(convert::From::from(xerr))
        };

        let mut titlestr = String::new();                   // title string
        fn istitle(e: &xml::Element) -> bool { e.name == "title" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, istitle, &mut titlestr);

        let mut descriptionstr = String::new();             // description string
        fn isdescription(e: &xml::Element) -> bool { e.name == "description" } // someday this will be an unboxed lambda
        find_tag_text(*itemelt, isdescription, &mut descriptionstr);

        let feeditem = FeedItem{title: titlestr, description: descriptionstr, author: authorstr, pubdate: pubtimestamp};
        reply.items.push(feeditem);
    }
    ////println!("Item: {}", item);
    Ok(())
}
//
//  readfeed -- read from an RSS or Atom feed.
//
pub fn readfeed(url: &str, reply: &mut FeedReply, verbose: bool) -> FeedResult<()> {
    ////let client = hyper::Client::new();                  // create HTTP client from Hyper crate.
    let mut res = match reqwest::blocking::get(url) {
    ////let mut res = match client.get(url).send() {            // HTTP GET request
        Ok(res) => res,
        Err(xerr) => return Err(convert::From::from(xerr)) // fails, return error
    };
    //  Successful read of URL.  Have valid result object.
    if verbose {
        println!("Response: {}", res.status());               // debug print
        println!("Headers:\n{:?}", res.headers());
    }
    let mut p = xml::Parser::new();                         // get XML parser
    let mut e = xml::ElementBuilder::new();                 // get tree builder
    let mut ws = String::new();                             // get work string for XML
    match res.read_to_string(&mut ws) {                     // read the XML
        Ok(_) => (),                                        // OK, keep going
        Err(xerr) => { return Err(convert::From::from(xerr)) }   // I/O error
    };
    p.feed_str(&ws[..]);                                    // prepare XML parser
    for event in p {                                        // for each full XML tree (normally only one)
        if let Some(rep) = e.handle_event(event) {                                  // returns an Option wrapped around a Result
            match rep {
                Ok(ev) => match handletree(&ev, reply) {    // we have an XML tree to process
                    Ok(()) => (),
                    Err(xerr) => return Err(xerr)           // RSS/Atom error
                    },                                      // end match handletree
                Err(xerr) => return Err(convert::From::from(xerr))
            }                                           // end match rep
        }                                                   // end match handle_event
    }                                                       // end for
    Ok(())
}

//
//  test1  -- temporary test function
//
//  Ask for URL of RSS feed, handle it.
//
pub fn test1() {
    let args : Vec<_> = env::args().collect();      // command line args as vector of strings
    match args.len() {
        2 => (),
        _ => {
            println!("Usage: client <url>");
            return;
        }
    };
    let url = &*args[1];
    println!("Reading \"{}\"", url);
    let mut result = FeedReply::new();            // accumulate ITEM entries
    let res = readfeed(url, &mut result, true);
    match res {
        Ok(_) => println!("OK."),
        Err(err) => println!("Error: {}", err)
        }
    result.dump();
}
//
//  Unit tests.
//
#[test]
fn testreutersrss() {
    ////let url = "http://feeds.reuters.com/reuters/topNews?format=xml";    // ***TEMP***
    let url = "https://rss.nytimes.com/services/xml/rss/nyt/World.xml";
    let mut freply = FeedReply::new();            // accumulate ITEM entries
    let res = readfeed(url, &mut freply, true);
    match res {
        Ok(_) => println!("OK."),
        Err(err) => panic!("Error: {}", err)
        }
    freply.dump();
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;
extern crate clap;
extern crate definitions;

mod error;
mod compiler;
mod ast;

use clap::{App, Arg};
use error::*;
use std::fs::File;

fn main() {
    if let Err(ref e) = run() {
        println!("error: {}", e);

        for e in e.iter().skip(1) {
            println!("caused by: {}", e);
        }

        // The backtrace is not always generated. Try to run this example
        // with `RUST_BACKTRACE=1`.
        if let Some(backtrace) = e.backtrace() {
            println!("backtrace: {:?}", backtrace);
        }

        ::std::process::exit(1);
    }
}

fn run() -> CompilationResult<()> {
    let matches = App::new("basm")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Julian Laubstein <contact@julianlaubstein.de>")
        .about("The assembler for the bakerVM")
        .arg(Arg::with_name("input").index(1).required(true).help("Sets the source file to use."),)
        .arg(Arg::with_name("output").index(2).required(true).help("Sets the destination file."),)
        .get_matches();

    let input_file_name = matches.value_of("input").unwrap_or("");

    let output_file_name = matches.value_of("output").unwrap_or("");

    let input_file = File::open(input_file_name).chain_err(|| "unable to open input file")?;

    // compiler::compile(input_file, output_file_name).chain_err(|| "unable to
    // compile file")?;

    Ok(())
}
<commit_msg>Renamed basm to blimpc<commit_after>#[macro_use]
extern crate error_chain;
extern crate clap;
extern crate definitions;

mod error;
mod compiler;
mod ast;

use clap::{App, Arg};
use error::*;
use std::fs::File;

fn main() {
    if let Err(ref e) = run() {
        println!("error: {}", e);

        for e in e.iter().skip(1) {
            println!("caused by: {}", e);
        }

        // The backtrace is not always generated. Try to run this example
        // with `RUST_BACKTRACE=1`.
        if let Some(backtrace) = e.backtrace() {
            println!("backtrace: {:?}", backtrace);
        }

        ::std::process::exit(1);
    }
}

fn run() -> CompilationResult<()> {
    let matches = App::new("blimpc")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Julian Laubstein <contact@julianlaubstein.de>")
        .about("The blimp compiler")
        .arg(Arg::with_name("input").index(1).required(true).help("Sets the source file to use."),)
        .arg(Arg::with_name("output").index(2).required(true).help("Sets the destination file."),)
        .get_matches();

    let input_file_name = matches.value_of("input").unwrap_or("");

    let output_file_name = matches.value_of("output").unwrap_or("");

    let input_file = File::open(input_file_name).chain_err(|| "unable to open input file")?;

    // compiler::compile(input_file, output_file_name).chain_err(|| "unable to
    // compile file")?;

    Ok(())
}
<|endoftext|>


<commit_before>mod unchecked {
    // 0 < val <= u8::MAX
    pub const fn u8(val: u8) -> u32 {
        let val = val as u32;

        // For better performance, avoid branches by assembling the solution
        // in the bits above the low 8 bits.

        // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
        const C1: u32 = 0b11_00000000 - 10; // 758
        // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
        const C2: u32 = 0b10_00000000 - 100; // 412

        // Value of top bits:
        //            +c1  +c2  1&2
        //     0..=9   10   01   00 = 0
        //   10..=99   11   01   01 = 1
        // 100..=255   11   10   10 = 2
        ((val + C1) & (val + C2)) >> 8
    }

    // 0 < val < 100_000
    const fn less_than_5(val: u32) -> u32 {
        // Similar to u8, when adding one of these constants to val,
        // we get two possible bit patterns above the low 17 bits,
        // depending on whether val is below or above the threshold.
        const C1: u32 = 0b011_00000000000000000 - 10; // 393206
        const C2: u32 = 0b100_00000000000000000 - 100; // 524188
        const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
        const C4: u32 = 0b100_00000000000000000 - 10000; // 514288

        // Value of top bits:
        //                +c1  +c2  1&2  +c3  +c4  3&4   ^
        //         0..=9  010  011  010  110  011  010  000 = 0
        //       10..=99  011  011  011  110  011  010  001 = 1
        //     100..=999  011  100  000  110  011  010  010 = 2
        //   1000..=9999  011  100  000  111  011  011  011 = 3
        // 10000..=99999  011  100  000  111  100  100  100 = 4
        (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
    }

    // 0 < val <= u16::MAX
    pub const fn u16(val: u16) -> u32 {
        less_than_5(val as u32)
    }

    // 0 < val <= u32::MAX
    pub const fn u32(mut val: u32) -> u32 {
        let mut log = 0;
        if val >= 100_000 {
            val /= 100_000;
            log += 5;
        }
        log + less_than_5(val)
    }

    // 0 < val <= u64::MAX
    pub const fn u64(mut val: u64) -> u32 {
        let mut log = 0;
        if val >= 10_000_000_000 {
            val /= 10_000_000_000;
            log += 10;
        }
        if val >= 100_000 {
            val /= 100_000;
            log += 5;
        }
        log + less_than_5(val as u32)
    }

    // 0 < val <= u128::MAX
    pub const fn u128(mut val: u128) -> u32 {
        let mut log = 0;
        if val >= 100_000_000_000_000_000_000_000_000_000_000 {
            val /= 100_000_000_000_000_000_000_000_000_000_000;
            log += 32;
            return log + u32(val as u32);
        }
        if val >= 10_000_000_000_000_000 {
            val /= 10_000_000_000_000_000;
            log += 16;
        }
        log + u64(val as u64)
    }

    // 0 < val <= i8::MAX
    pub const fn i8(val: i8) -> u32 {
        u8(val as u8)
    }

    // 0 < val <= i16::MAX
    pub const fn i16(val: i16) -> u32 {
        u16(val as u16)
    }

    // 0 < val <= i32::MAX
    pub const fn i32(val: i32) -> u32 {
        u32(val as u32)
    }

    // 0 < val <= i64::MAX
    pub const fn i64(val: i64) -> u32 {
        u64(val as u64)
    }

    // 0 < val <= i128::MAX
    pub const fn i128(val: i128) -> u32 {
        u128(val as u128)
    }
}

macro_rules! impl_checked {
    ($T:ident) => {
        pub const fn $T(val: $T) -> Option<u32> {
            if val > 0 { Some(unchecked::$T(val)) } else { None }
        }
    };
}

impl_checked! { u8 }
impl_checked! { u16 }
impl_checked! { u32 }
impl_checked! { u64 }
impl_checked! { u128 }
impl_checked! { i8 }
impl_checked! { i16 }
impl_checked! { i32 }
impl_checked! { i64 }
impl_checked! { i128 }
<commit_msg>Add #[inline] to int log10 functions.<commit_after>mod unchecked {
    // 0 < val <= u8::MAX
    #[inline]
    pub const fn u8(val: u8) -> u32 {
        let val = val as u32;

        // For better performance, avoid branches by assembling the solution
        // in the bits above the low 8 bits.

        // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
        const C1: u32 = 0b11_00000000 - 10; // 758
        // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
        const C2: u32 = 0b10_00000000 - 100; // 412

        // Value of top bits:
        //            +c1  +c2  1&2
        //     0..=9   10   01   00 = 0
        //   10..=99   11   01   01 = 1
        // 100..=255   11   10   10 = 2
        ((val + C1) & (val + C2)) >> 8
    }

    // 0 < val < 100_000
    #[inline]
    const fn less_than_5(val: u32) -> u32 {
        // Similar to u8, when adding one of these constants to val,
        // we get two possible bit patterns above the low 17 bits,
        // depending on whether val is below or above the threshold.
        const C1: u32 = 0b011_00000000000000000 - 10; // 393206
        const C2: u32 = 0b100_00000000000000000 - 100; // 524188
        const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
        const C4: u32 = 0b100_00000000000000000 - 10000; // 514288

        // Value of top bits:
        //                +c1  +c2  1&2  +c3  +c4  3&4   ^
        //         0..=9  010  011  010  110  011  010  000 = 0
        //       10..=99  011  011  011  110  011  010  001 = 1
        //     100..=999  011  100  000  110  011  010  010 = 2
        //   1000..=9999  011  100  000  111  011  011  011 = 3
        // 10000..=99999  011  100  000  111  100  100  100 = 4
        (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
    }

    // 0 < val <= u16::MAX
    #[inline]
    pub const fn u16(val: u16) -> u32 {
        less_than_5(val as u32)
    }

    // 0 < val <= u32::MAX
    #[inline]
    pub const fn u32(mut val: u32) -> u32 {
        let mut log = 0;
        if val >= 100_000 {
            val /= 100_000;
            log += 5;
        }
        log + less_than_5(val)
    }

    // 0 < val <= u64::MAX
    #[inline]
    pub const fn u64(mut val: u64) -> u32 {
        let mut log = 0;
        if val >= 10_000_000_000 {
            val /= 10_000_000_000;
            log += 10;
        }
        if val >= 100_000 {
            val /= 100_000;
            log += 5;
        }
        log + less_than_5(val as u32)
    }

    // 0 < val <= u128::MAX
    #[inline]
    pub const fn u128(mut val: u128) -> u32 {
        let mut log = 0;
        if val >= 100_000_000_000_000_000_000_000_000_000_000 {
            val /= 100_000_000_000_000_000_000_000_000_000_000;
            log += 32;
            return log + u32(val as u32);
        }
        if val >= 10_000_000_000_000_000 {
            val /= 10_000_000_000_000_000;
            log += 16;
        }
        log + u64(val as u64)
    }

    // 0 < val <= i8::MAX
    #[inline]
    pub const fn i8(val: i8) -> u32 {
        u8(val as u8)
    }

    // 0 < val <= i16::MAX
    #[inline]
    pub const fn i16(val: i16) -> u32 {
        u16(val as u16)
    }

    // 0 < val <= i32::MAX
    #[inline]
    pub const fn i32(val: i32) -> u32 {
        u32(val as u32)
    }

    // 0 < val <= i64::MAX
    #[inline]
    pub const fn i64(val: i64) -> u32 {
        u64(val as u64)
    }

    // 0 < val <= i128::MAX
    #[inline]
    pub const fn i128(val: i128) -> u32 {
        u128(val as u128)
    }
}

macro_rules! impl_checked {
    ($T:ident) => {
        #[inline]
        pub const fn $T(val: $T) -> Option<u32> {
            if val > 0 { Some(unchecked::$T(val)) } else { None }
        }
    };
}

impl_checked! { u8 }
impl_checked! { u16 }
impl_checked! { u32 }
impl_checked! { u64 }
impl_checked! { u128 }
impl_checked! { i8 }
impl_checked! { i16 }
impl_checked! { i32 }
impl_checked! { i64 }
impl_checked! { i128 }
<|endoftext|>


<commit_before>use super::generate;

#[test]
fn test() {
    let set1 = generate(vec![('2', '7')]);
    let set2 = generate(vec![('0', '1'),   // disjoint left
                             ('1', '2'),   // partial overlap left
                             ('4', '5'),   // subset
                             ('7', '8'),   // partial overlap right
                             ('9', '9')]); // disjoint right
    let letters1 = generate(vec![('c', 'e')]);
    let letters2 = generate(vec![('a', 'g')]); // superset

    let difference_set     = set1.difference(&set2);
    let difference_letters = letters1.difference(&letters2);

    let other_set     = generate(vec![('3', '3'), ('6', '6')]);
    let other_letters = generate(vec![]);

    assert_eq!(difference_set, other_set);
    assert_eq!(difference_letters, other_letters);
}
<commit_msg>Update range_set difference tests<commit_after>use super::generate;

#[test]
fn partial_overlap() {
    let set   = generate(vec![('2', '7')]);

    let left  = generate(vec![('0', '3')]);
    let right = generate(vec![('6', '8')]);

    let other_left  = generate(vec![('4', '7')]);
    let other_right = generate(vec![('2', '5')]);

    assert_eq!(set.difference(&left), other_left);
    assert_eq!(set.difference(&right), other_right);
}
#[test]
fn subset() {
    let set = generate(vec![('2', '7')]);

    let subset      = generate(vec![('3', '6')]);
    let exact_left  = generate(vec![('2', '6')]);
    let exact_right = generate(vec![('3', '7')]);

    let other_subset = generate(vec![('2', '2'), ('7', '7')]);
    let other_left   = generate(vec![('7', '7')]);
    let other_right  = generate(vec![('2', '2')]);
    let empty        = generate(vec![]);

    assert_eq!(set.difference(&subset), other_subset);
    assert_eq!(set.difference(&exact_left), other_left);
    assert_eq!(set.difference(&exact_right), other_right);
    assert_eq!(set.difference(&set), empty);
}
#[test]
fn superset() {
    let set      = generate(vec![('2', '7')]);
    let superset = generate(vec![('1', '8')]);

    let empty = generate(vec![]);

    assert_eq!(set.difference(&superset), empty);
}

#[test]
fn disjoint() {
    let set = generate(vec![('3', '4')]);

    let left  = generate(vec![('1', '2')]);
    let right = generate(vec![('5', '6')]);

    assert_eq!(set.difference(&left), set);
    assert_eq!(set.difference(&right), set);
}
<|endoftext|>


<commit_before>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use utils::Optional;
use status::Status;

//--- Templates ---//

/// A trait for all possible sensor templates.
/// the `SensorTemplate`s are capable of registering themselves in a `Status` struct
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, status: &mut Status);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, status: &mut Status) {
        // TODO error handling
        let value = value_str.parse::<i64>().unwrap();
        let sensor = PeopleNowPresentSensor {
            location: self.location.clone(),
            name: self.name.clone(),
            names: self.names.clone(),
            description: self.description.clone(),
            value: value,
        };
        // TODO handle empty
        status.sensors.as_mut().map_or((), |v| {
            match v.people_now_present {
                Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
                Optional::Absent => v.people_now_present = Optional::Value(vec![sensor]),
            }
        });
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, status: &mut Status) {
        // TODO error handling
        let value = value_str.parse::<f64>().unwrap();
        let sensor = TemperatureSensor {
            unit: self.unit.clone(),
            location: self.location.clone(),
            name: self.name.clone(),
            description: self.description.clone(),
            value: value,
        };
        // TODO handle empty
        status.sensors.as_mut().map_or((), |v| {
            match v.temperature {
                Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
                Optional::Absent => v.temperature = Optional::Value(vec![sensor]),
            }
        });
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<commit_msg>SensorTemplate: Pass Sensors instead of Status reference<commit_after>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use utils::Optional;

//--- Templates ---//

/// A trait for all possible sensor templates.
/// the `SensorTemplate`s are capable of registering themselves in a `Sensors` struct
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        // TODO error handling
        let value = value_str.parse::<i64>().unwrap();
        let sensor = PeopleNowPresentSensor {
            location: self.location.clone(),
            name: self.name.clone(),
            names: self.names.clone(),
            description: self.description.clone(),
            value: value,
        };

        match sensors.people_now_present {
            Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
            Optional::Absent => sensors.people_now_present = Optional::Value(vec![sensor]),
        }
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        // TODO error handling
        let value = value_str.parse::<f64>().unwrap();
        let sensor = TemperatureSensor {
            unit: self.unit.clone(),
            location: self.location.clone(),
            name: self.name.clone(),
            description: self.description.clone(),
            value: value,
        };
        match sensors.temperature {
            Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
            Optional::Absent => sensors.temperature = Optional::Value(vec![sensor]),
        }
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<|endoftext|>


<commit_before>use super::{alloc_cell_shapes, Cell, CellId, Mesh, PointId};
use crate::{shapes::Shape, StrError};
use russell_lab::sort2;
use std::collections::{HashMap, HashSet};

/// Aliases (usize,usize) as the key of Edge
///
/// # Note
///
/// Since the local numbering scheme runs over "corners" first, we can compare
/// edges using only two points; i.e., the middle points don't matter.
pub type EdgeKey = (usize, usize);

/// Aliases (usize,usize,usize,usize) as the key of Face
///
/// # Note
///
/// If all faces have at most 3 points, the fourth entry in the key will be equal to the total number of points.
/// In this way, we can compare 4-node (or more nodes) faces with each other, since that the local numbering
/// scheme runs over the "corners" first; i.e., the middle points don't matter.
pub type FaceKey = (usize, usize, usize, usize);

/// Holds edge data (derived data structure)
#[derive(Clone, Debug)]
pub struct Edge {
    /// List of points defining this edge; in the right order (unsorted)
    pub points: Vec<PointId>,
}

/// Holds face data (derived data structure)
#[derive(Clone, Debug)]
pub struct Face {
    /// List of points defining this face; in the right order (unsorted)
    pub points: Vec<PointId>,
}

/// Holds points, edges and faces on the boundaries of a mesh
pub struct MeshBoundaries {
    /// Set of points on the boundaries
    ///
    /// Note: a boundary point belongs to a boundary edge or a boundary face
    pub points: HashSet<PointId>,

    /// Set of edges on the boundaries
    ///
    /// Note:
    ///
    /// * In 2D, a boundary edge is such that it is shared by one 2D cell only (1D cells are ignored)
    /// * In 3D, a boundary edge belongs to a boundary face
    pub edges: HashMap<EdgeKey, Edge>,

    /// Set of faces on the boundaries
    ///
    /// Note: A boundary face is such that it is shared by one 3D cell only
    pub faces: HashMap<FaceKey, Face>,
}

impl MeshBoundaries {
    /// Finds the boundary entities and allocates a new instance
    pub fn new(mesh: &Mesh) -> Result<Self, StrError> {
        // maps all face keys to (cell_id, f) where f is the cell's local face index
        // let mut all_faces: HashMap<FaceKey, Vec<(CellId, usize)>> = HashMap::new(); // (face_key) => [(cell_id,f)]

        // let shapes = alloc_cell_shapes(mesh)?;
        // let mut edges: HashMap<EdgeKey, Edge> = HashMap::new();
        // let mut faces: HashMap<FaceKey, Face> = HashMap::new();

        // match mesh.space_ndim {
        //     2 => find_boundaries_2d(mesh, &shapes)?,
        //     _ => panic!("space_ndim must be 2 or 3"),
        // };

        Ok(MeshBoundaries {
            points: HashSet::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),
        })
    }
}

/// Maps all edges (internal and boundary) in 2D
///
/// Returns a map relating edge keys to `Vec<(cell_id, e)>` where:
///
/// * `cell_id` -- the id of the cell sharing the edge
/// * `e` -- is the cell's local edge index
pub fn map_edges_2d(mesh: &Mesh, shapes: &Vec<Shape>) -> HashMap<EdgeKey, Vec<(CellId, usize)>> {
    assert_eq!(mesh.space_ndim, 2);
    let mut edges: HashMap<EdgeKey, Vec<(CellId, usize)>> = HashMap::new();
    mesh.cells.iter().zip(shapes).for_each(|(cell, shape)| {
        if shape.geo_ndim == 2 {
            for e in 0..shape.nedge {
                let mut edge_key: EdgeKey = (
                    cell.points[shape.edge_node_id(e, 0)],
                    cell.points[shape.edge_node_id(e, 1)],
                );
                sort2(&mut edge_key);
                let data = edges.entry(edge_key).or_insert(Vec::new());
                data.push((cell.id, e));
            }
        }
    });
    edges
}

/*
fn find_boundaries_2d(
    mesh: &Mesh,
    shapes: &Vec<Shape>,
) -> Result<(HashSet<PointId>, HashMap<EdgeKey, Edge>), StrError> {
    // holds the ids of points on boundary or on shapes with geo_ndim == 1
    let mut points: HashSet<PointId> = HashSet::new();

    // find all edges
    mesh.cells
        .iter()
        .zip(shapes)
        .for_each(|(cell, shape)| match shape.geo_ndim {
            1 => {
                for m in 0..shape.nnode {
                    points.insert(cell.points[m]);
                }
            }
            2 => {
                for e in 0..shape.nedge {
                    let mut edge_key: EdgeKey = (
                        cell.points[shape.edge_node_id(e, 0)],
                        cell.points[shape.edge_node_id(e, 1)],
                    );
                    sort2(&mut edge_key);
                    match all_edges.get_mut(&edge_key) {
                        Some((_, _, internal)) => {
                            *internal = true;
                        }
                        None => {
                            all_edges.insert(edge_key, (cell.id, e, false));
                        }
                    }
                }
            }
            _ => panic!("shape.geo_ndim is invalid in 2D"),
        });

    // allocate boundary edges
    let edges: HashMap<_, _> = all_edges
        .iter()
        .filter_map(|(edge_key, (cell_id, e, internal))| match internal {
            true => None,
            false => Some((
                *edge_key,
                Edge {
                    points: (0..shapes[*cell_id].edge_nnode)
                        .into_iter()
                        .map(|i| shapes[*cell_id].edge_node_id(*e, i))
                        .collect(),
                },
            )),
        })
        .collect();

    Ok((points, edges))
}
*/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::map_edges_2d;
    use crate::mesh::{alloc_cell_shapes, Samples};
    use crate::StrError;

    #[test]
    fn map_edges_2d_works() -> Result<(), StrError> {
        //  3---------2---------5
        //  |         |         |
        //  |   [0]   |   [1]   |
        //  |         |         |
        //  0---------1---------4
        let mesh = Samples::two_quads_horizontal();
        let shapes = alloc_cell_shapes(&mesh)?;
        let edges = map_edges_2d(&mesh, &shapes);
        let mut keys: Vec<_> = edges.keys().collect();
        keys.sort();
        assert_eq!(keys, [&(0, 1), &(0, 3), &(1, 2), &(1, 4), &(2, 3), &(2, 5), &(4, 5)]);
        assert_eq!(edges.get(&(0, 1)).unwrap(), &[(0, 0)]);
        assert_eq!(edges.get(&(0, 3)).unwrap(), &[(0, 3)]);
        assert_eq!(edges.get(&(1, 2)).unwrap(), &[(0, 1), (1, 3)]);
        assert_eq!(edges.get(&(1, 4)).unwrap(), &[(1, 0)]);
        assert_eq!(edges.get(&(2, 3)).unwrap(), &[(0, 2)]);
        assert_eq!(edges.get(&(2, 5)).unwrap(), &[(1, 2)]);
        assert_eq!(edges.get(&(4, 5)).unwrap(), &[(1, 1)]);
        Ok(())
    }
}
<commit_msg>Impl map_faces and add tests<commit_after>use super::{alloc_cell_shapes, Cell, CellId, Mesh, PointId};
use crate::{shapes::Shape, StrError};
use russell_lab::{sort2, sort4};
use std::collections::{HashMap, HashSet};

/// Aliases (usize,usize) as the key of Edge
///
/// # Note
///
/// Since the local numbering scheme runs over "corners" first, we can compare
/// edges using only two points; i.e., the middle points don't matter.
pub type EdgeKey = (usize, usize);

/// Aliases (usize,usize,usize,usize) as the key of Face
///
/// # Note
///
/// If all faces have at most 3 points, the fourth entry in the key will be equal to the total number of points.
/// In this way, we can compare 4-node (or more nodes) faces with each other, since that the local numbering
/// scheme runs over the "corners" first; i.e., the middle points don't matter.
pub type FaceKey = (usize, usize, usize, usize);

/// Holds edge data (derived data structure)
#[derive(Clone, Debug)]
pub struct Edge {
    /// List of points defining this edge; in the right order (unsorted)
    pub points: Vec<PointId>,
}

/// Holds face data (derived data structure)
#[derive(Clone, Debug)]
pub struct Face {
    /// List of points defining this face; in the right order (unsorted)
    pub points: Vec<PointId>,
}

/// Holds points, edges and faces on the boundaries of a mesh
pub struct MeshBoundaries {
    /// Set of points on the boundaries
    ///
    /// Note: a boundary point belongs to a boundary edge or a boundary face
    pub points: HashSet<PointId>,

    /// Set of edges on the boundaries
    ///
    /// Note:
    ///
    /// * In 2D, a boundary edge is such that it is shared by one 2D cell only (1D cells are ignored)
    /// * In 3D, a boundary edge belongs to a boundary face
    pub edges: HashMap<EdgeKey, Edge>,

    /// Set of faces on the boundaries
    ///
    /// Note: A boundary face is such that it is shared by one 3D cell only
    pub faces: HashMap<FaceKey, Face>,
}

impl MeshBoundaries {
    /// Finds the boundary entities and allocates a new instance
    pub fn new(mesh: &Mesh) -> Result<Self, StrError> {
        // maps all face keys to (cell_id, f) where f is the cell's local face index
        // let mut all_faces: HashMap<FaceKey, Vec<(CellId, usize)>> = HashMap::new(); // (face_key) => [(cell_id,f)]

        // let shapes = alloc_cell_shapes(mesh)?;
        // let mut edges: HashMap<EdgeKey, Edge> = HashMap::new();
        // let mut faces: HashMap<FaceKey, Face> = HashMap::new();

        // match mesh.space_ndim {
        //     2 => find_boundaries_2d(mesh, &shapes)?,
        //     _ => panic!("space_ndim must be 2 or 3"),
        // };

        Ok(MeshBoundaries {
            points: HashSet::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),
        })
    }
}

/// Maps all edges (internal and boundary) in 2D
///
/// # Output
///
/// Returns a map relating edge keys to `Vec<(cell_id, e)>` where:
///
/// * `cell_id` -- the id of the cell sharing the edge
/// * `e` -- is the cell's local edge index
///
/// # Panics
///
/// The `mesh.space_ndim` must be equal to 2, otherwise a panic occurs.
pub fn map_edges_2d(mesh: &Mesh, shapes: &Vec<Shape>) -> HashMap<EdgeKey, Vec<(CellId, usize)>> {
    assert_eq!(mesh.space_ndim, 2);
    let mut edges: HashMap<EdgeKey, Vec<(CellId, usize)>> = HashMap::new();
    mesh.cells.iter().zip(shapes).for_each(|(cell, shape)| {
        if shape.geo_ndim == 2 {
            for e in 0..shape.nedge {
                let mut edge_key: EdgeKey = (
                    cell.points[shape.edge_node_id(e, 0)],
                    cell.points[shape.edge_node_id(e, 1)],
                );
                sort2(&mut edge_key);
                let data = edges.entry(edge_key).or_insert(Vec::new());
                data.push((cell.id, e));
            }
        }
    });
    edges
}

/// Maps all faces (internal and boundary)
///
/// Returns a map relating face keys to `Vec<(cell_id, f)>` where:
///
/// * `cell_id` -- the id of the cell sharing the face
/// * `f` -- is the cell's local face index
///
/// # Panics
///
/// The `mesh.space_ndim` must be equal to 3, otherwise a panic occurs.
pub fn map_faces(mesh: &Mesh, shapes: &Vec<Shape>) -> HashMap<FaceKey, Vec<(CellId, usize)>> {
    assert_eq!(mesh.space_ndim, 3);
    let mut faces: HashMap<FaceKey, Vec<(CellId, usize)>> = HashMap::new();
    mesh.cells.iter().zip(shapes).for_each(|(cell, shape)| {
        if shape.geo_ndim == 3 {
            for f in 0..shape.nface {
                let mut face_key: FaceKey = if shape.face_nnode > 3 {
                    (
                        cell.points[shape.face_node_id(f, 0)],
                        cell.points[shape.face_node_id(f, 1)],
                        cell.points[shape.face_node_id(f, 2)],
                        cell.points[shape.face_node_id(f, 3)],
                    )
                } else {
                    (
                        cell.points[shape.face_node_id(f, 0)],
                        cell.points[shape.face_node_id(f, 1)],
                        cell.points[shape.face_node_id(f, 2)],
                        mesh.points.len(),
                    )
                };
                sort4(&mut face_key);
                let data = faces.entry(face_key).or_insert(Vec::new());
                data.push((cell.id, f));
            }
        }
    });
    faces
}

/*
fn find_boundaries_2d(
    mesh: &Mesh,
    shapes: &Vec<Shape>,
) -> Result<(HashSet<PointId>, HashMap<EdgeKey, Edge>), StrError> {
    // holds the ids of points on boundary or on shapes with geo_ndim == 1
    let mut points: HashSet<PointId> = HashSet::new();

    // find all edges
    mesh.cells
        .iter()
        .zip(shapes)
        .for_each(|(cell, shape)| match shape.geo_ndim {
            1 => {
                for m in 0..shape.nnode {
                    points.insert(cell.points[m]);
                }
            }
            2 => {
                for e in 0..shape.nedge {
                    let mut edge_key: EdgeKey = (
                        cell.points[shape.edge_node_id(e, 0)],
                        cell.points[shape.edge_node_id(e, 1)],
                    );
                    sort2(&mut edge_key);
                    match all_edges.get_mut(&edge_key) {
                        Some((_, _, internal)) => {
                            *internal = true;
                        }
                        None => {
                            all_edges.insert(edge_key, (cell.id, e, false));
                        }
                    }
                }
            }
            _ => panic!("shape.geo_ndim is invalid in 2D"),
        });

    // allocate boundary edges
    let edges: HashMap<_, _> = all_edges
        .iter()
        .filter_map(|(edge_key, (cell_id, e, internal))| match internal {
            true => None,
            false => Some((
                *edge_key,
                Edge {
                    points: (0..shapes[*cell_id].edge_nnode)
                        .into_iter()
                        .map(|i| shapes[*cell_id].edge_node_id(*e, i))
                        .collect(),
                },
            )),
        })
        .collect();

    Ok((points, edges))
}
*/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{map_edges_2d, map_faces};
    use crate::mesh::{alloc_cell_shapes, Samples};
    use crate::StrError;

    #[test]
    fn map_edges_2d_works() -> Result<(), StrError> {
        //  3---------2---------5
        //  |         |         |
        //  |   [0]   |   [1]   |
        //  |         |         |
        //  0---------1---------4
        let mesh = Samples::two_quads_horizontal();
        let shapes = alloc_cell_shapes(&mesh)?;
        let edges = map_edges_2d(&mesh, &shapes);
        let mut keys: Vec<_> = edges.keys().collect();
        keys.sort();
        assert_eq!(keys, [&(0, 1), &(0, 3), &(1, 2), &(1, 4), &(2, 3), &(2, 5), &(4, 5)]);
        assert_eq!(edges.get(&(0, 1)).unwrap(), &[(0, 0)]);
        assert_eq!(edges.get(&(0, 3)).unwrap(), &[(0, 3)]);
        assert_eq!(edges.get(&(1, 2)).unwrap(), &[(0, 1), (1, 3)]);
        assert_eq!(edges.get(&(1, 4)).unwrap(), &[(1, 0)]);
        assert_eq!(edges.get(&(2, 3)).unwrap(), &[(0, 2)]);
        assert_eq!(edges.get(&(2, 5)).unwrap(), &[(1, 2)]);
        assert_eq!(edges.get(&(4, 5)).unwrap(), &[(1, 1)]);

        //           4---------3
        //           |         |
        //           |   [1]   |
        //           |         |
        //  0--------1---------2
        let mesh = Samples::mixed_shapes_2d();
        let shapes = alloc_cell_shapes(&mesh)?;
        let edges = map_edges_2d(&mesh, &shapes);
        let mut keys: Vec<_> = edges.keys().collect();
        keys.sort();
        assert_eq!(keys, [&(1, 2), &(1, 4), &(2, 3), &(3, 4)]);
        assert_eq!(edges.get(&(1, 2)).unwrap(), &[(1, 0)]);
        assert_eq!(edges.get(&(1, 4)).unwrap(), &[(1, 3)]);
        assert_eq!(edges.get(&(2, 3)).unwrap(), &[(1, 1)]);
        assert_eq!(edges.get(&(3, 4)).unwrap(), &[(1, 2)]);
        Ok(())
    }

    #[test]
    fn map_faces_works() -> Result<(), StrError> {
        //      8-------------11
        //     /.             /|
        //    / .            / |
        //   /  .           /  |
        //  /   .          /   |       id = 1
        // 9-------------10    |       attribute_id = 2
        // |    .         |    |
        // |    4---------|----7
        // |   /.         |   /|
        // |  / .         |  / |
        // | /  .         | /  |
        // |/   .         |/   |
        // 5--------------6    |       id = 0
        // |    .         |    |       attribute_id = 1
        // |    0---------|----3
        // |   /          |   /
        // |  /           |  /
        // | /            | /
        // |/             |/
        // 1--------------2
        let mesh = Samples::two_cubes_vertical();
        let shapes = alloc_cell_shapes(&mesh)?;
        let faces = map_faces(&mesh, &shapes);
        let mut keys: Vec<_> = faces.keys().collect();
        keys.sort();
        assert_eq!(
            keys,
            [
                &(0, 1, 2, 3),
                &(0, 1, 4, 5),
                &(0, 3, 4, 7),
                &(1, 2, 5, 6),
                &(2, 3, 6, 7),
                &(4, 5, 6, 7),
                &(4, 5, 8, 9),
                &(4, 7, 8, 11),
                &(5, 6, 9, 10),
                &(6, 7, 10, 11),
                &(8, 9, 10, 11),
            ]
        );
        assert_eq!(faces.get(&(0, 1, 2, 3)).unwrap(), &[(0, 4)]);
        assert_eq!(faces.get(&(0, 1, 4, 5)).unwrap(), &[(0, 2)]);
        assert_eq!(faces.get(&(0, 3, 4, 7)).unwrap(), &[(0, 0)]);
        assert_eq!(faces.get(&(1, 2, 5, 6)).unwrap(), &[(0, 1)]);
        assert_eq!(faces.get(&(2, 3, 6, 7)).unwrap(), &[(0, 3)]);
        assert_eq!(faces.get(&(4, 5, 6, 7)).unwrap(), &[(0, 5), (1, 4)]);
        assert_eq!(faces.get(&(4, 5, 8, 9)).unwrap(), &[(1, 2)]);
        assert_eq!(faces.get(&(4, 7, 8, 11)).unwrap(), &[(1, 0)]);
        assert_eq!(faces.get(&(5, 6, 9, 10)).unwrap(), &[(1, 1)]);
        assert_eq!(faces.get(&(6, 7, 10, 11)).unwrap(), &[(1, 3)]);
        assert_eq!(faces.get(&(8, 9, 10, 11)).unwrap(), &[(1, 5)]);

        //                       4------------7-----------10
        //                      /.           /|            |
        //                     / .          / |            |
        //                    /  .         /  |            |
        //                   /   .        /   |            |
        //                  5------------6    |            |
        //                  |    .       |`.  |            |
        //                  |    0-------|--`.3------------9
        //                  |   /        |   /`.          /
        //                  |  /         |  /   `.       /
        //                  | /          | /      `.    /
        //                  |/           |/         `. /
        //  12-----11-------1------------2------------8
        //
        let mesh = Samples::mixed_shapes_3d();
        let shapes = alloc_cell_shapes(&mesh)?;
        let faces = map_faces(&mesh, &shapes);
        let mut keys: Vec<_> = faces.keys().collect();
        keys.sort();
        assert_eq!(
            keys,
            [
                &(0, 1, 2, 3),
                &(0, 1, 4, 5),
                &(0, 3, 4, 7),
                &(1, 2, 5, 6),
                &(2, 3, 6, 7),
                &(2, 3, 6, 13),
                &(2, 3, 8, 13),
                &(2, 6, 8, 13),
                &(3, 6, 8, 13),
                &(4, 5, 6, 7),
            ]
        );
        assert_eq!(faces.get(&(0, 1, 2, 3)).unwrap(), &[(0, 4)]);
        assert_eq!(faces.get(&(0, 1, 4, 5)).unwrap(), &[(0, 2)]);
        assert_eq!(faces.get(&(0, 3, 4, 7)).unwrap(), &[(0, 0)]);
        assert_eq!(faces.get(&(1, 2, 5, 6)).unwrap(), &[(0, 1)]);
        assert_eq!(faces.get(&(2, 3, 6, 7)).unwrap(), &[(0, 3)]);
        assert_eq!(faces.get(&(2, 3, 6, 13)).unwrap(), &[(1, 0)]);
        assert_eq!(faces.get(&(2, 3, 8, 13)).unwrap(), &[(1, 2)]);
        assert_eq!(faces.get(&(2, 6, 8, 13)).unwrap(), &[(1, 1)]);
        assert_eq!(faces.get(&(3, 6, 8, 13)).unwrap(), &[(1, 3)]);
        assert_eq!(faces.get(&(4, 5, 6, 7)).unwrap(), &[(0, 5)]);
        Ok(())
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bencher;
extern crate kdtree;
extern crate rand;

use bencher::Bencher;
use rand::Rng;

use kdtree::kdtree::distance::squared_euclidean;
use kdtree::kdtree::test_common::*;

fn gen_random() -> f64 {
    rand::thread_rng().gen_range(0., 10000.)
}

fn generate_points(point_count: usize) -> Vec<Point3WithId> {
    let mut points: Vec<Point3WithId> = vec![];

    for i in 0..point_count {
        points.push(Point3WithId::new(
            i as i32,
            gen_random(),
            gen_random(),
            gen_random(),
        ));
    }

    points
}

fn bench_creating_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let points = generate_points(len);

    b.iter(|| {
        kdtree::kdtree::Kdtree::new(&mut points.clone());
    });
}

fn bench_single_loop_times_for_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let points = generate_points(len);

    let tree = kdtree::kdtree::Kdtree::new(&mut points.clone());

    b.iter(|| tree.nearest_search(&points[0]));
}

fn bench_single_loop_times_for_1000_node_tree_within_1000(b: &mut Bencher) {
    let len = 1000usize;
    let points = generate_points(len);

    let tree = kdtree::kdtree::Kdtree::new(&mut points.clone());

    b.iter(|| tree.within(&points[0], 1000.0, squared_euclidean));
}

#[allow(dead_code)]
fn bench_creating_1000_000_node_tree(b: &mut Bencher) {
    let len = 1000_000usize;
    let points = generate_points(len);

    b.iter(|| {
        kdtree::kdtree::Kdtree::new(&mut points.clone());
    });
}

fn bench_adding_same_node_to_1000_tree(b: &mut Bencher) {
    let len = 1000usize;
    let mut points = generate_points(len);
    let mut tree = kdtree::kdtree::Kdtree::new(&mut points);

    let point = Point3WithId::new(-1 as i32, gen_random(), gen_random(), gen_random());
    b.iter(|| {
        tree.insert_node(point);
    });
}

fn bench_incrementally_building_the_1000_tree(b: &mut Bencher) {
    b.iter(|| {
        let len = 1usize;
        let mut points = generate_points(len);
        let mut tree = kdtree::kdtree::Kdtree::new(&mut points);
        for _ in 0..1000 {
            let point = Point3WithId::new(-1 as i32, gen_random(), gen_random(), gen_random());
            tree.insert_node(point);
        }
    });
}

benchmark_group!(
    benches,
    bench_creating_1000_node_tree,
    bench_single_loop_times_for_1000_node_tree,
    bench_adding_same_node_to_1000_tree,
    bench_incrementally_building_the_1000_tree,
    bench_single_loop_times_for_1000_node_tree_within_1000
);
benchmark_main!(benches);
<commit_msg>Switch to criterion for benching<commit_after>#[macro_use]
extern crate criterion;

use criterion::Criterion;

extern crate kdtree;
extern crate rand;
use kdtree::distance::*;
use kdtree::test_common::*;
use rand::Rng;

fn gen_random() -> f64 {
    rand::thread_rng().gen_range(0., 1.)
}

fn generate_points(point_count: usize) -> Vec<Point3WithId> {
    let mut points: Vec<Point3WithId> = vec![];

    for i in 0..point_count {
        points.push(Point3WithId::new(
            i as i32,
            gen_random(),
            gen_random(),
            gen_random(),
        ));
    }

    points
}

fn bench_creating_1000_node_tree(c: &mut Criterion) {
    c.bench_function("bench_creating_1000_node_tree", |b| {
        let len = 1000usize;
        let points = generate_points(len);

        b.iter(|| {
            kdtree::Kdtree::new(&mut points.clone());
        })
    });
}

fn bench_creating_100_000_node_tree(c: &mut Criterion) {
    c.bench_function("bench_creating_100_000_node_tree", |b| {
        let len = 100_000usize;
        let points = generate_points(len);

        b.iter(|| {
            kdtree::Kdtree::new(&mut points.clone());
        })
    });
}

fn bench_single_loop_times_for_1000_node_tree(c: &mut Criterion) {
    c.bench_function("bench_single_loop_times_for_1000_node_tree", |b| {
        let len = 1000usize;
        let points = generate_points(len);

        let tree = kdtree::Kdtree::new(&mut points.clone());

        b.iter(|| tree.nearest_search(&points[0]))
    });
}

fn bench_single_loop_times_for_100_000_node_tree(c: &mut Criterion) {
    c.bench_function("bench_single_loop_times_for_100_000_node_tree", |b| {
        let len = 1000_000usize;
        let points = generate_points(len);

        let tree = kdtree::Kdtree::new(&mut points.clone());

        b.iter(|| tree.nearest_search(&points[0]))
    });
}

fn bench_single_loop_times_for_1000_node_tree_within_1000(c: &mut Criterion) {
    c.bench_function(
        "bench_single_loop_times_for_1000_node_tree_within_1000",
        |b| {
            let len = 1000usize;
            let points = generate_points(len);

            let tree = kdtree::Kdtree::new(&mut points.clone());

            b.iter(|| tree.within(&points[0], 1000.0, squared_euclidean))
        },
    );
}

#[allow(dead_code)]
fn bench_creating_1000_000_node_tree(c: &mut Criterion) {
    c.bench_function("bench_creating_1000_000_node_tree", |b| {
        let len = 1000_000usize;
        let points = generate_points(len);

        b.iter(|| {
            kdtree::Kdtree::new(&mut points.clone());
        })
    });
}

fn bench_adding_same_node_to_1000_tree(c: &mut Criterion) {
    c.bench_function("bench_adding_same_node_to_1000_tree", |b| {
        let len = 1000usize;
        let mut points = generate_points(len);
        let mut tree = kdtree::Kdtree::new(&mut points);

        let point = Point3WithId::new(-1 as i32, gen_random(), gen_random(), gen_random());
        b.iter(|| {
            tree.insert_node(point);
        })
    });
}

fn bench_incrementally_building_the_1000_tree(c: &mut Criterion) {
    c.bench_function("bench_incrementally_building_the_1000_tree", |b| {
        b.iter(|| {
            let len = 1usize;
            let mut points = generate_points(len);
            let mut tree = kdtree::Kdtree::new(&mut points);
            for _ in 0..1000 {
                let point = Point3WithId::new(-1 as i32, gen_random(), gen_random(), gen_random());
                tree.insert_node(point);
            }
        })
    });
}

criterion_group!(
    benches,
    bench_creating_1000_node_tree,
    bench_creating_100_000_node_tree,
    bench_single_loop_times_for_1000_node_tree,
    bench_single_loop_times_for_100_000_node_tree,
    bench_adding_same_node_to_1000_tree,
    bench_incrementally_building_the_1000_tree,
    bench_single_loop_times_for_1000_node_tree_within_1000
);
criterion_main!(benches);
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ast::*;
use syntax::attr;
use syntax::visit;
use utils::{span_lint_and_then, in_macro, span_lint};

/// **What it does:** This lint warns about names that are very similar and thus confusing
///
/// **Why is this bad?** It's hard to distinguish between names that differ only by a single character
///
/// **Known problems:** None?
///
/// **Example:** `checked_exp` and `checked_expr`
declare_lint! {
    pub SIMILAR_NAMES,
    Warn,
    "similarly named items and bindings"
}

/// **What it does:** This lint warns about having too many variables whose name consists of a single character
///
/// **Why is this bad?** It's hard to memorize what a variable means without a descriptive name.
///
/// **Known problems:** None?
///
/// **Example:** let (a, b, c, d, e, f, g) = (...);
declare_lint! {
    pub MANY_SINGLE_CHAR_NAMES,
    Warn,
    "too many single character bindings"
}

pub struct NonExpressiveNames {
    pub max_single_char_names: u64,
}

impl LintPass for NonExpressiveNames {
    fn get_lints(&self) -> LintArray {
        lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES)
    }
}

struct ExistingName {
    interned: InternedString,
    span: Span,
    len: usize,
    whitelist: &'static [&'static str],
}

struct SimilarNamesLocalVisitor<'a, 'b: 'a> {
    names: Vec<ExistingName>,
    cx: &'a EarlyContext<'b>,
    lint: &'a NonExpressiveNames,
    single_char_names: Vec<char>,
}

// this list contains lists of names that are allowed to be similar
// the assumption is that no name is ever contained in multiple lists.
#[cfg_attr(rustfmt, rustfmt_skip)]
const WHITELIST: &'static [&'static [&'static str]] = &[
    &["parsed", "parser"],
    &["lhs", "rhs"],
    &["tx", "rx"],
    &["set", "get"],
];

struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>);

impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn visit_pat(&mut self, pat: &'v Pat) {
        if let PatKind::Ident(_, id, _) = pat.node {
            self.check_name(id.span, id.node.name);
        }
        visit::walk_pat(self, pat);
    }
}

fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
    for &allow in WHITELIST {
        if whitelisted(interned_name, allow) {
            return Some(allow);
        }
    }
    None
}

fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
    if list.iter().any(|&name| interned_name == name) {
        return true;
    }
    for name in list {
        // name_*
        if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) {
            return true;
        }
        // *_name
        if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) {
            return true;
        }
    }
    false
}

impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn check_short_name(&mut self, c: char, span: Span) {
        // make sure we ignore shadowing
        if self.0.single_char_names.contains(&c) {
            return;
        }
        self.0.single_char_names.push(c);
        if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names {
            span_lint(self.0.cx,
                      MANY_SINGLE_CHAR_NAMES,
                      span,
                      &format!("{}th binding whose name is just one char", self.0.single_char_names.len()));
        }
    }
    fn check_name(&mut self, span: Span, name: Name) {
        if in_macro(self.0.cx, span) {
            return;
        }
        let interned_name = name.as_str();
        if interned_name.chars().any(char::is_uppercase) {
            return;
        }
        let count = interned_name.chars().count();
        if count < 3 {
            if count == 1 {
                let c = interned_name.chars().next().expect("already checked");
                self.check_short_name(c, span);
            }
            return;
        }
        for existing_name in &self.0.names {
            if whitelisted(&interned_name, existing_name.whitelist) {
                continue;
            }
            let mut split_at = None;
            if existing_name.len > count {
                if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
                    continue;
                }
            } else if existing_name.len < count {
                if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
                    continue;
                }
            } else {
                let mut interned_chars = interned_name.chars();
                let mut existing_chars = existing_name.interned.chars();
                let first_i = interned_chars.next().expect("we know we have at least one char");
                let first_e = existing_chars.next().expect("we know we have at least one char");
                let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric();

                if eq_or_numeric(first_i, first_e) {
                    let last_i = interned_chars.next_back().expect("we know we have at least two chars");
                    let last_e = existing_chars.next_back().expect("we know we have at least two chars");
                    if eq_or_numeric(last_i, last_e) {
                        if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 {
                            continue;
                        }
                    } else {
                        let second_last_i = interned_chars.next_back().expect("we know we have at least three chars");
                        let second_last_e = existing_chars.next_back().expect("we know we have at least three chars");
                        if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' ||
                           !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                            // allowed similarity foo_x, foo_y
                            // or too many chars differ (foo_x, boo_y) or (foox, booy)
                            continue;
                        }
                        split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
                    }
                } else {
                    let second_i = interned_chars.next().expect("we know we have at least two chars");
                    let second_e = existing_chars.next().expect("we know we have at least two chars");
                    if !eq_or_numeric(second_i, second_e) || second_i == '_' ||
                       !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                        // allowed similarity x_foo, y_foo
                        // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
                        continue;
                    }
                    split_at = interned_name.chars().next().map(|c| c.len_utf8());
                }
            }
            span_lint_and_then(self.0.cx,
                               SIMILAR_NAMES,
                               span,
                               "binding's name is too similar to existing binding",
                               |diag| {
                                   diag.span_note(existing_name.span, "existing binding defined here");
                                   if let Some(split) = split_at {
                                       diag.span_help(span,
                                                      &format!("separate the discriminating character by an \
                                                                underscore like: `{}_{}`",
                                                               &interned_name[..split],
                                                               &interned_name[split..]));
                                   }
                               });
            return;
        }
        self.0.names.push(ExistingName {
            whitelist: get_whitelist(&interned_name).unwrap_or(&[]),
            interned: interned_name,
            span: span,
            len: count,
        });
    }
}

impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
    /// ensure scoping rules work
    fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
        let n = self.names.len();
        let single_char_count = self.single_char_names.len();
        f(self);
        self.names.truncate(n);
        self.single_char_names.truncate(single_char_count);
    }
}

impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> {
    fn visit_local(&mut self, local: &'v Local) {
        if let Some(ref init) = local.init {
            self.apply(|this| visit::walk_expr(this, &**init));
        }
        // add the pattern after the expression because the bindings aren't available yet in the init expression
        SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
    }
    fn visit_block(&mut self, blk: &'v Block) {
        self.apply(|this| visit::walk_block(this, blk));
    }
    fn visit_arm(&mut self, arm: &'v Arm) {
        self.apply(|this| {
            // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier
            SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]);
            this.apply(|this| visit::walk_expr(this, &arm.body));
        });
    }
    fn visit_item(&mut self, _: &'v Item) {
        // do not recurse into inner items
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
        if let ItemKind::Fn(ref decl, _, _, _, _, ref blk) = item.node {
            if !attr::contains_name(&item.attrs, "test") {
                let mut visitor = SimilarNamesLocalVisitor {
                    names: Vec::new(),
                    cx: cx,
                    lint: &self,
                    single_char_names: Vec::new(),
                };
                // initialize with function arguments
                for arg in &decl.inputs {
                    visit::walk_pat(&mut SimilarNamesNameVisitor(&mut visitor), &arg.pat);
                }
                // walk all other bindings
                visit::walk_block(&mut visitor, blk);
            }
        }
    }
}

/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
    debug_assert!(a_name.chars().count() < b_name.chars().count());
    let mut a_chars = a_name.chars();
    let mut b_chars = b_name.chars();
    while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) {
        if a == b {
            continue;
        }
        if let Some(b2) = b_chars.next() {
            // check if there's just one character inserted
            return a != b2 || a_chars.ne(b_chars);
        } else {
            // tuple
            // ntuple
            return true;
        }
    }
    // for item in items
    true
}
<commit_msg>similar_names should be allow-by-default<commit_after>use rustc::lint::*;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ast::*;
use syntax::attr;
use syntax::visit;
use utils::{span_lint_and_then, in_macro, span_lint};

/// **What it does:** This lint warns about names that are very similar and thus confusing
///
/// **Why is this bad?** It's hard to distinguish between names that differ only by a single character
///
/// **Known problems:** None?
///
/// **Example:** `checked_exp` and `checked_expr`
declare_lint! {
    pub SIMILAR_NAMES,
    Allow,
    "similarly named items and bindings"
}

/// **What it does:** This lint warns about having too many variables whose name consists of a single character
///
/// **Why is this bad?** It's hard to memorize what a variable means without a descriptive name.
///
/// **Known problems:** None?
///
/// **Example:** let (a, b, c, d, e, f, g) = (...);
declare_lint! {
    pub MANY_SINGLE_CHAR_NAMES,
    Warn,
    "too many single character bindings"
}

pub struct NonExpressiveNames {
    pub max_single_char_names: u64,
}

impl LintPass for NonExpressiveNames {
    fn get_lints(&self) -> LintArray {
        lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES)
    }
}

struct ExistingName {
    interned: InternedString,
    span: Span,
    len: usize,
    whitelist: &'static [&'static str],
}

struct SimilarNamesLocalVisitor<'a, 'b: 'a> {
    names: Vec<ExistingName>,
    cx: &'a EarlyContext<'b>,
    lint: &'a NonExpressiveNames,
    single_char_names: Vec<char>,
}

// this list contains lists of names that are allowed to be similar
// the assumption is that no name is ever contained in multiple lists.
#[cfg_attr(rustfmt, rustfmt_skip)]
const WHITELIST: &'static [&'static [&'static str]] = &[
    &["parsed", "parser"],
    &["lhs", "rhs"],
    &["tx", "rx"],
    &["set", "get"],
];

struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>);

impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn visit_pat(&mut self, pat: &'v Pat) {
        if let PatKind::Ident(_, id, _) = pat.node {
            self.check_name(id.span, id.node.name);
        }
        visit::walk_pat(self, pat);
    }
}

fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
    for &allow in WHITELIST {
        if whitelisted(interned_name, allow) {
            return Some(allow);
        }
    }
    None
}

fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
    if list.iter().any(|&name| interned_name == name) {
        return true;
    }
    for name in list {
        // name_*
        if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) {
            return true;
        }
        // *_name
        if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) {
            return true;
        }
    }
    false
}

impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn check_short_name(&mut self, c: char, span: Span) {
        // make sure we ignore shadowing
        if self.0.single_char_names.contains(&c) {
            return;
        }
        self.0.single_char_names.push(c);
        if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names {
            span_lint(self.0.cx,
                      MANY_SINGLE_CHAR_NAMES,
                      span,
                      &format!("{}th binding whose name is just one char", self.0.single_char_names.len()));
        }
    }
    fn check_name(&mut self, span: Span, name: Name) {
        if in_macro(self.0.cx, span) {
            return;
        }
        let interned_name = name.as_str();
        if interned_name.chars().any(char::is_uppercase) {
            return;
        }
        let count = interned_name.chars().count();
        if count < 3 {
            if count == 1 {
                let c = interned_name.chars().next().expect("already checked");
                self.check_short_name(c, span);
            }
            return;
        }
        for existing_name in &self.0.names {
            if whitelisted(&interned_name, existing_name.whitelist) {
                continue;
            }
            let mut split_at = None;
            if existing_name.len > count {
                if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
                    continue;
                }
            } else if existing_name.len < count {
                if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
                    continue;
                }
            } else {
                let mut interned_chars = interned_name.chars();
                let mut existing_chars = existing_name.interned.chars();
                let first_i = interned_chars.next().expect("we know we have at least one char");
                let first_e = existing_chars.next().expect("we know we have at least one char");
                let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric();

                if eq_or_numeric(first_i, first_e) {
                    let last_i = interned_chars.next_back().expect("we know we have at least two chars");
                    let last_e = existing_chars.next_back().expect("we know we have at least two chars");
                    if eq_or_numeric(last_i, last_e) {
                        if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 {
                            continue;
                        }
                    } else {
                        let second_last_i = interned_chars.next_back().expect("we know we have at least three chars");
                        let second_last_e = existing_chars.next_back().expect("we know we have at least three chars");
                        if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' ||
                           !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                            // allowed similarity foo_x, foo_y
                            // or too many chars differ (foo_x, boo_y) or (foox, booy)
                            continue;
                        }
                        split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
                    }
                } else {
                    let second_i = interned_chars.next().expect("we know we have at least two chars");
                    let second_e = existing_chars.next().expect("we know we have at least two chars");
                    if !eq_or_numeric(second_i, second_e) || second_i == '_' ||
                       !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                        // allowed similarity x_foo, y_foo
                        // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
                        continue;
                    }
                    split_at = interned_name.chars().next().map(|c| c.len_utf8());
                }
            }
            span_lint_and_then(self.0.cx,
                               SIMILAR_NAMES,
                               span,
                               "binding's name is too similar to existing binding",
                               |diag| {
                                   diag.span_note(existing_name.span, "existing binding defined here");
                                   if let Some(split) = split_at {
                                       diag.span_help(span,
                                                      &format!("separate the discriminating character by an \
                                                                underscore like: `{}_{}`",
                                                               &interned_name[..split],
                                                               &interned_name[split..]));
                                   }
                               });
            return;
        }
        self.0.names.push(ExistingName {
            whitelist: get_whitelist(&interned_name).unwrap_or(&[]),
            interned: interned_name,
            span: span,
            len: count,
        });
    }
}

impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
    /// ensure scoping rules work
    fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
        let n = self.names.len();
        let single_char_count = self.single_char_names.len();
        f(self);
        self.names.truncate(n);
        self.single_char_names.truncate(single_char_count);
    }
}

impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> {
    fn visit_local(&mut self, local: &'v Local) {
        if let Some(ref init) = local.init {
            self.apply(|this| visit::walk_expr(this, &**init));
        }
        // add the pattern after the expression because the bindings aren't available yet in the init expression
        SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
    }
    fn visit_block(&mut self, blk: &'v Block) {
        self.apply(|this| visit::walk_block(this, blk));
    }
    fn visit_arm(&mut self, arm: &'v Arm) {
        self.apply(|this| {
            // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier
            SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]);
            this.apply(|this| visit::walk_expr(this, &arm.body));
        });
    }
    fn visit_item(&mut self, _: &'v Item) {
        // do not recurse into inner items
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
        if let ItemKind::Fn(ref decl, _, _, _, _, ref blk) = item.node {
            if !attr::contains_name(&item.attrs, "test") {
                let mut visitor = SimilarNamesLocalVisitor {
                    names: Vec::new(),
                    cx: cx,
                    lint: &self,
                    single_char_names: Vec::new(),
                };
                // initialize with function arguments
                for arg in &decl.inputs {
                    visit::walk_pat(&mut SimilarNamesNameVisitor(&mut visitor), &arg.pat);
                }
                // walk all other bindings
                visit::walk_block(&mut visitor, blk);
            }
        }
    }
}

/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
    debug_assert!(a_name.chars().count() < b_name.chars().count());
    let mut a_chars = a_name.chars();
    let mut b_chars = b_name.chars();
    while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) {
        if a == b {
            continue;
        }
        if let Some(b2) = b_chars.next() {
            // check if there's just one character inserted
            return a != b2 || a_chars.ne(b_chars);
        } else {
            // tuple
            // ntuple
            return true;
        }
    }
    // for item in items
    true
}
<|endoftext|>