<commit_before>use std::error;
use std::process;
use std::fmt;
use std::io;

use std::io::{Read, Write};
use std::string::FromUtf8Error;

use ini::ini;
use clap;
use hyper;
use serde_json;
use url;
use walkdir;
use zip;
use sourcemap;

pub type CliResult<T> = Result<T, CliError>;

#[derive(Debug)]
pub struct CliError {
    repr: CliErrorRepr,
}

#[derive(Debug)]
enum CliErrorRepr {
    ClapError(clap::Error),
    BasicError(String),
}

macro_rules! basic_error {
    ($ty:ty, $msg:expr) => {
        impl From<$ty> for CliError {
            fn from(err: $ty) -> CliError {
                CliError {
                    repr: CliErrorRepr::BasicError(format!("{}: {}", $msg, err))
                }
            }
        }
    }
}

basic_error!(io::Error, "i/o failure");
basic_error!(zip::result::ZipError, "could not zip");
basic_error!(walkdir::Error, "could not walk path");
basic_error!(url::ParseError, "could not parse URL");
basic_error!(hyper::error::Error, "could not perform HTTP request");
basic_error!(serde_json::Error, "failed to parse JSON");
basic_error!(FromUtf8Error, "invalid UTF-8");
basic_error!(ini::Error, "ini error");
basic_error!(sourcemap::Error, "sourcemap error");

impl From<hyper::client::response::Response> for CliError {
    fn from(mut resp: hyper::client::response::Response) -> CliError {
        let mut err = String::new();
        resp.read_to_string(&mut err).ok();
        CliError {
            repr: CliErrorRepr::BasicError(format!(
                "request failed ({}, {})", resp.status, err))
        }
    }
}

impl From<clap::Error> for CliError {
    fn from(err: clap::Error) -> CliError {
        CliError {
            repr: CliErrorRepr::ClapError(err)
        }
    }
}

impl From<String> for CliError {
    fn from(err: String) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err)
        }
    }
}

impl<'a> From<&'a str> for CliError {
    fn from(err: &'a str) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err.to_owned())
        }
    }
}

impl CliError {

    pub fn exit(&self) -> ! {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => err.exit(),
            _ => {
                writeln!(&mut io::stderr(), "error: {}", self).ok();
                process::exit(1)
            },
        }
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => write!(f, "{}", msg),
            CliErrorRepr::ClapError(ref err) => write!(f, "{}", err),
        }
    }
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => &msg,
            CliErrorRepr::ClapError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => Some(&*err),
            _ => None,
        }
    }
}
<commit_msg>Added better error message for permission errors<commit_after>use std::error;
use std::process;
use std::fmt;
use std::io;
use std::io::{Read, Write};
use std::string::FromUtf8Error;

use hyper::status::StatusCode;
use hyper::header::ContentType;

use ini::ini;
use clap;
use hyper;
use serde_json;
use url;
use walkdir;
use zip;
use sourcemap;

pub type CliResult<T> = Result<T, CliError>;

#[derive(Debug)]
pub struct CliError {
    repr: CliErrorRepr,
}

#[derive(Debug)]
enum CliErrorRepr {
    ClapError(clap::Error),
    HyperResponse(StatusCode, String),
    BasicError(String),
}

#[derive(Debug, Deserialize)]
struct ErrorInfo {
    detail: Option<String>,
}

macro_rules! basic_error {
    ($ty:ty, $msg:expr) => {
        impl From<$ty> for CliError {
            fn from(err: $ty) -> CliError {
                CliError {
                    repr: CliErrorRepr::BasicError(format!("{}: {}", $msg, err))
                }
            }
        }
    }
}

basic_error!(io::Error, "i/o failure");
basic_error!(zip::result::ZipError, "could not zip");
basic_error!(walkdir::Error, "could not walk path");
basic_error!(url::ParseError, "could not parse URL");
basic_error!(hyper::error::Error, "could not perform HTTP request");
basic_error!(serde_json::Error, "failed to parse JSON");
basic_error!(FromUtf8Error, "invalid UTF-8");
basic_error!(ini::Error, "ini error");
basic_error!(sourcemap::Error, "sourcemap error");

impl From<hyper::client::response::Response> for CliError {
    fn from(mut resp: hyper::client::response::Response) -> CliError {
        let mut err = None;
        let mut body = String::new();
        resp.read_to_string(&mut body).ok();

        if resp.headers.get::<ContentType>() == Some(&ContentType::json()) {
            let rv : serde_json::Result<ErrorInfo> = serde_json::from_reader(body.as_bytes());
            if let Ok(error_info) = rv {
                err = error_info.detail;
            }
        }
        if err.is_none() {
            err = Some(body);
        }
        CliError {
            repr: CliErrorRepr::HyperResponse(resp.status, err.unwrap())
        }
    }
}

impl From<clap::Error> for CliError {
    fn from(err: clap::Error) -> CliError {
        CliError {
            repr: CliErrorRepr::ClapError(err)
        }
    }
}

impl From<String> for CliError {
    fn from(err: String) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err)
        }
    }
}

impl<'a> From<&'a str> for CliError {
    fn from(err: &'a str) -> CliError {
        CliError {
            repr: CliErrorRepr::BasicError(err.to_owned())
        }
    }
}

impl CliError {

    pub fn exit(&self) -> ! {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => err.exit(),
            CliErrorRepr::HyperResponse(status, _) => {
                writeln!(&mut io::stderr(), "error: {}", self).ok();
                if status == StatusCode::Unauthorized {
                    writeln!(&mut io::stderr(), "").ok();
                    writeln!(&mut io::stderr(), "You can use 'sentry-cli login' to sign in.").ok();
                }
                process::exit(1)
            },
            _ => {
                writeln!(&mut io::stderr(), "error: {}", self).ok();
                process::exit(1)
            },
        }
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => write!(f, "{}", msg),
            CliErrorRepr::ClapError(ref err) => write!(f, "{}", err),
            CliErrorRepr::HyperResponse(status, ref err) => {
                write!(f, "request failed ({}: {})", status, err)
            },
        }
    }
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        match self.repr {
            CliErrorRepr::BasicError(ref msg) => &msg,
            CliErrorRepr::ClapError(ref err) => err.description(),
            CliErrorRepr::HyperResponse(_, _) => "HTTP response error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            CliErrorRepr::ClapError(ref err) => Some(&*err),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use std::comm::*;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath
}

fn main() {
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    //Visitor Counting
    let visitor_count: uint = 0;
    let shared_visitor_count = arc::RWArc::new(visitor_count);

    //Wahoo Scheduling
    let wahoo_index:uint = 0;
    let shared_wahoo_index = arc::RWArc::new(wahoo_index);
    let local_wahoo_index = shared_wahoo_index.clone();

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle
                match io::read_whole_file(tf.filepath) { // killed if file size is larger than memory size.
                    Ok(file_data) => {
                        println(fmt!("begin serving file [%?]", tf.filepath));
                        if tf.filepath.to_str().ends_with(".shtml") {
                            parse_gash(file_data);
                        }
                        // A web server should always reply a HTTP header for any legal HTTP request.
                        tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes());
                        tf.stream.write(file_data);
                        println(fmt!("finish file [%?]", tf.filepath));
                    }
                    Err(err) => {
                        println(err);
                    }
                }
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    /*
                    let tf_opt: Option<sched_msg> = (*vec).shift_opt();
                    let tf = tf_opt.unwrap();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                    */
                    //Find shortest process
                    let mut wahoo_index = 0;
                    let mut min_index: uint = 0;      let mut min_size: int = 0;
                    do local_wahoo_index.write |count| { wahoo_index = (*count) }

                    //Find shortest Charlottesville request, else do other requests
                    if wahoo_index > 0 {
                        for i in range(0, wahoo_index) {
                            let size =  (*vec)[i].filepath.get_size().unwrap_or_zero();
                            if min_size <= 0 || min_size > size as int{
                                min_size = size as int;
                                min_index = i;
                            }
                        }
                    }
                    else {
                        for i in range(0, (*vec).len()) {
                            let size =  (*vec)[i].filepath.get_size().unwrap_or_zero();
                            if min_size <= 0 || min_size > size as int {
                                min_size = size as int;
                                min_index = i;
                            }
                        }
                    }

                    let tf = (*vec).remove(min_index);
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.

                    //Decrement wahoo index
                    do local_wahoo_index.write |count| {
                        if (wahoo_index > 0) {
                            (*count) -= 1;
                            println(fmt!("wahoo index decremented to %u", (*count)));
                        }
                    }
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    for stream in acceptor.incoming() {
        //Getting the ip address of the socket
        let mut stream = stream;
        let mut incoming_ip: ~str = ~"";
        match stream {
            Some(ref mut theTcpStream) => {
                match theTcpStream.peer_name() {
                    Some(peername) => {
                        incoming_ip = peername.to_str();
                    }
                    None => ()
                }
            }
            None => ()
        }

        //Cells to pass in the strem and ip address to the closure function
        let stream = Cell::new(stream);
        let incoming_ip = Cell::new(incoming_ip);

        let local_visitor_count = shared_visitor_count.clone();
        let local_wahoo_index = shared_wahoo_index.clone();
        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();

        do spawn {
            let mut visitor_count = 0;
            do local_visitor_count.write |count| {
                (*count) += 1;
                visitor_count = (*count);
            }

            let mut stream = stream.take();
            let mut incoming_ip = incoming_ip.take();

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", visitor_count);

                    stream.write(response.as_bytes());
                }
                else {
                    // Requests scheduling
                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone()};
                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    incoming_ip = ~"128.143.";
                    let mut wahoo_index = 0;
                    if checkWahoo(incoming_ip)
                    {
                        println("Found a Charlottesville address");
                        do local_wahoo_index.write |count| {
                            (*count) += 1;
                            wahoo_index = (*count);
                        }
                        println(fmt!("Wahoo requests end at index: %u", wahoo_index));
                    }

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        if wahoo_index > 0 {
                            (*vec).insert(wahoo_index-1, msg); //place at back of Charlottesville queue
                            println("inserted at back of Charlottesville queue");
                        }
                        else {
                            (*vec).push(msg); // enqueue new request.
                            println("add to queue");
                        }
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}

fn checkWahoo(ip: ~str) -> bool {
    let WAHOO_IP = ~["128.143.", "137.54."];
    println(fmt!("ip: %s", ip));

    for matcher in WAHOO_IP.iter() {
        if ip.contains(*matcher) {
            return true;
        }
    }
    return false;
}

fn parse_gash(cmd: &[u8]) {
    let mut cmd_str = str::from_utf8(cmd);
    while cmd_str.contains("


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use std::comm::*;
use extra::priority_queue;
use extra::md4;
use extra::sort;
use std::path;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

static MAX_CACHE_SIZE_BYTES: u64 = 50000000;
static CACHE_MANAGER_A_RATE: u64 = 2000;
static CACHE_MANAGER_B_RATE: u64 = 6000;

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    topPriority: int,
    fileSize: u64

}

impl Ord for sched_msg {
    fn lt(&self, other: &sched_msg) -> bool {

        let mut retVal:bool = false;

        //If self has a lower geographic priority, then it is less than
        if (self.topPriority < other.topPriority) {
            retVal = true;
        }
        else if (self.topPriority == other.topPriority) {

            //If the two have equal priorities, then we will sort by file size
            //Smaller files get a higher priority
            if (self.fileSize > other.fileSize) {
                retVal = true;
            }
        }

        retVal
    }
}

struct cache_item {
    name: ~str,
    in_use_flag: bool,
    ssi_flag: bool,
    hash: ~str,
    data: ~[u8],
    count: uint,
    size: u64

}

impl cache_item {
    fn le(&self, other: &cache_item) -> bool {
        let mut retVal:bool = false;

        if(self.count <= other.count) {
            retVal = true;
        }

        retVal
    }
}

fn le(this: &cache_item, other: &cache_item) -> bool {
        let mut retVal:bool = false;

        if(this.count <= other.count) {
            retVal = true;
        }

        retVal
    }

fn main() {
    let req_vec: ~priority_queue::PriorityQueue<sched_msg> = ~priority_queue::PriorityQueue::new();
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    let safe_count: ~[uint] = ~[0];
    let shared_visit = arc::RWArc::new(safe_count);

    let cache_list: ~[cache_item] = ~[];
    let shared_cache_list = arc::RWArc::new(cache_list);

    let cache_manager_a = shared_cache_list.clone();
    let cache_manager_b = shared_cache_list.clone();

    //CACHE UPDATE MANAGER (Manager B)
    //This will handle making sure that items in the cache are up-to-date in case they are changed
    do spawn {

        loop {

            do cache_manager_b.write |vec| {

                for i in range(0, (*vec).len()) {

                    //If it is in the cache and in use, we will check to see if the file has been updated
                    if((*vec)[i].in_use_flag) {

                        let curr_path = ~path::Path((*vec)[i].name);
                        if os::path_exists(curr_path) {

                            match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {

                                        let temp_md4 = md4::md4_str(file_data.to_owned());

                                        if(temp_md4 != (*vec)[i].hash)
                                        {
                                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                                Some(s) => s,
                                                None => fail!("Could not access file stats for cache")
                                            };

                                            println(fmt!("===== UPDATING FILE: %?", (*vec)[i].name));

                                            (*vec)[i].data = file_data;
                                            (*vec)[i].size = fileInfo.size;
                                            (*vec)[i].hash = temp_md4;
                                        }
                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }
                                }
                        }
                    }
                }
            }

            timer::sleep(CACHE_MANAGER_B_RATE);
        }
    }

    //MAIN CACHE MANAGER (Manager A)
    do spawn {

        loop {
            do cache_manager_a.write |vec| {

                sort::quick_sort((*vec), le);

                let mut cache_remaining = MAX_CACHE_SIZE_BYTES;

                for i in range(0, (*vec).len()) {

                    if((*vec)[i].size <= cache_remaining && !(*vec)[i].in_use_flag) {

                        let curr_path = ~path::Path((*vec)[i].name);

                        if os::path_exists(curr_path) {

                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats for cache")
                            };

                            if(fileInfo.size <= cache_remaining) {

                                match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {

                                        //NEED TO ADD CHECK IF IT HAS SSI
                                        //PERHAPS EXCLUDE ALL SSI FROM CACHE?
                                        //ADD TO IF: size < remaining, !in use, !ssi?

                                        (*vec)[i].data = file_data.to_owned();
                                        (*vec)[i].size = fileInfo.size;
                                        (*vec)[i].hash = md4::md4_str(file_data);
                                        (*vec)[i].in_use_flag = true;

                                        cache_remaining = cache_remaining - fileInfo.size;

                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }

                                }

                            }
                        }
                    }
                    else if((*vec)[i].size <= cache_remaining && (*vec)[i].in_use_flag) {
                        cache_remaining = cache_remaining - (*vec)[i].size;
                    }
                    else if((*vec)[i].size > cache_remaining) {
                        (*vec)[i].in_use_flag = false;
                        (*vec)[i].data = ~[];
                    }

                }

            }

            timer::sleep(CACHE_MANAGER_A_RATE);

        }
    }

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                //Check if file is in cache
                //Will do so using RWArc

                let mut serve_from_cache: bool = false;

                do shared_cache_list.write |vec| {

                    //if((*vec).len() > 0) {

                        let mut found: bool = false;

                        for i in range(0, (*vec).len()) {

                            if( (*vec)[i].name == tf.filepath.to_str() && (*vec)[i].in_use_flag) {
                                serve_from_cache = true;
                                found = true;

                                println(fmt!("===== SERVING FROM CACHE: %?", tf.filepath.to_str()));

                                tf.stream.write((*vec)[i].data);

                                (*vec)[i].count += 1;
                            }
                            else if( (*vec)[i].name == tf.filepath.to_str() && !(*vec)[i].in_use_flag) {
                                (*vec)[i].count += 1;
                                found = true;
                            }
                        }

                        //If it isn't found, we will create a blank entry and enter basic info, and add the
                        //data and md4 later
                        if(!found) {

                            println(fmt!("===== ADDING ITEM %?", tf.filepath.to_str()));

                            let new_cache_item: cache_item = cache_item{name: tf.filepath.to_str(), in_use_flag: false,
                                ssi_flag: false, hash: ~"", data: ~[], count: 1, size: tf.fileSize};

                            (*vec).push(new_cache_item);

                        }
                    //}
                }

                if(!serve_from_cache) {

                    match io::read_whole_file(tf.filepath) { // killed if file size is larger than memory size.
                        Ok(file_data) => {
                            //println(fmt!("begin serving file [%?]", tf.filepath));

                            tf.stream.write(file_data);
                            //println(fmt!("finish file [%?]", tf.filepath));

                            println(fmt!("===== SERVING FROM DISK: %?", tf.filepath.to_str()));

                            /*

                            let md4_val = md4::md4_str(file_data);

                            do shared_cache_list.write |vec| {

                                let mut found_flag: bool = false;

                                for i in range(0, (*vec).len()) {

                                    if( (*vec)[i].name == tf.filepath.to_str() ) {

                                        println("=====FOUND NAME");

                                        found_flag = true;

                                        (*vec)[i].in_use_flag = true;
                                        (*vec)[i].data = file_data.to_owned();
                                        (*vec)[i].hash = md4_val.to_owned();
                                    }
                                }

                                if(!found_flag) {
                                    println(fmt!("===== DID NOT FIND NAME FOR %?", tf.filepath.to_str()));
                                }
                            }

                            */

                        }
                        Err(err) => {
                            println("ERROR IN SEND");
                            println(err);
                        }
                    }
                }
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {

                    //Since we are using a priority queue, we will use pop()
                    let tf = (*vec).pop();
                    //println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    loop {
        let stream = acceptor.accept();
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        let child_arc = shared_visit.clone();
        do spawn {

            let mut actual_count:uint = 0;

            //We will use the cloned RWARC
            do child_arc.write |count_vec| {

                let prev_count = (*count_vec).pop();
                let new_count: uint = prev_count + 1;

                actual_count = new_count;

                (*count_vec).push(new_count);
            }

            let stream = stream.take();

            match stream {
                Some(s) => {

                    let mut stream = s;

                    let mut buf = [0, ..500];
                    stream.read(buf);
                    let request_str = str::from_utf8(buf);

                    let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
                    if req_group.len() > 2 {
                        let path = req_group[1];
                        //println(fmt!("Request for path: \n%?", path));

                        let file_path = ~os::getcwd().push(path.replace("/../", ""));
                        if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                            //println(fmt!("Request received:\n%s", request_str));
                            let response: ~str = fmt!(
                                "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                                 \r\n", actual_count);

                            stream.write(response.as_bytes());
                        }
                        else {
                            // Requests scheduling

                            let mut streamPriority: int = 0;

                            //Retrieving the requesting IP address
                            let ipStr: ~str = match (stream).peer_name() {
                                Some(pr) => pr.ip.to_str(),
                                None => ~"0.0.0.0"
                            };

                            //Split the IP address by '.' so that we can compare
                            let ipSplit: ~[~str] = ipStr.split_iter('.').filter(|&x| x != "")
                                 .map(|x| x.to_owned()).collect();

                            //Assign priority based on geography or if localhost
                            if ( (ipSplit[0] == ~"127" && ipSplit[1] == ~"0") || (ipSplit[0] == ~"128" && ipSplit[1] == ~"143")
                                || (ipSplit[0] == ~"137" && ipSplit[1] == ~"54") ) {

                                streamPriority = 1;
                            }

                            //Get filetype in order to determine HTTP header type
                            let fileType = match file_path.filetype() {
                                Some(s) => s,
                                None => &""
                            };

                            //In order to optimize for the benchmark, we will send the HTTP header quickly before adding to the queue
                            let httpHeader: ~str = match fileType {
                                ".html" | ".htm" | ".php" => ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n",
                                _ => ~"HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n"
                            };

                            stream.write(httpHeader.as_bytes());
                            stream.flush();

                            //Retrieve file info for additional latency fixes
                            let fileInfo = match std::rt::io::file::stat(file_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats")
                            };

                            let msg: sched_msg = sched_msg{stream: Some(stream), filepath: file_path.clone(), topPriority: streamPriority, fileSize: fileInfo.size};
                            let (sm_port, sm_chan) = std::comm::stream();
                            sm_chan.send(msg);

                            do child_add_vec.write |vec| {
                                let msg = sm_port.recv();
                                (*vec).push(msg); // enqueue new request.
                                //println("add to queue");
                            }
                            child_chan.send(""); //notify the new arriving request.
                            //println(fmt!("get file request: %?", file_path));
                        }
                    }
                    println!("connection terminates")

                },
                None => ()
            }

        }
    }
}<commit_msg>Cleaned up some code, removed some legacy code<commit_after>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use std::comm::*;
use extra::priority_queue;
use extra::md4;
use extra::sort;
use std::path;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

static MAX_CACHE_SIZE_BYTES: u64 = 50000000;
static CACHE_MANAGER_A_RATE: u64 = 2000;
static CACHE_MANAGER_B_RATE: u64 = 6000;

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    topPriority: int,
    fileSize: u64
}

impl Ord for sched_msg {
    fn lt(&self, other: &sched_msg) -> bool {

        let mut retVal:bool = false;

        //If self has a lower geographic priority, then it is less than
        if (self.topPriority < other.topPriority) {
            retVal = true;
        }
        else if (self.topPriority == other.topPriority) {

            //If the two have equal priorities, then we will sort by file size
            //Smaller files get a higher priority
            if (self.fileSize > other.fileSize) {
                retVal = true;
            }
        }

        retVal
    }
}

struct cache_item {
    name: ~str,
    in_use_flag: bool,
    ssi_flag: bool,
    hash: ~str,
    data: ~[u8],
    count: uint,
    size: u64
}

impl cache_item {
    fn le(&self, other: &cache_item) -> bool {
        let mut retVal:bool = false;

        if(self.count <= other.count) {
            retVal = true;
        }

        retVal
    }
}

fn le(this: &cache_item, other: &cache_item) -> bool {
        let mut retVal:bool = false;

        if(this.count <= other.count) {
            retVal = true;
        }

        retVal
    }

fn main() {
    let req_vec: ~priority_queue::PriorityQueue<sched_msg> = ~priority_queue::PriorityQueue::new();
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    let safe_count: ~[uint] = ~[0];
    let shared_visit = arc::RWArc::new(safe_count);

    let cache_list: ~[cache_item] = ~[];
    let shared_cache_list = arc::RWArc::new(cache_list);

    let cache_manager_a = shared_cache_list.clone();
    let cache_manager_b = shared_cache_list.clone();

    //CACHE UPDATE MANAGER (Manager B)
    //This will handle making sure that items in the cache are up-to-date in case they are changed
    do spawn {

        loop {

            do cache_manager_b.write |vec| {

                for i in range(0, (*vec).len()) {

                    //If it is in the cache and in use, we will check to see if the file has been updated
                    if((*vec)[i].in_use_flag) {

                        let curr_path = ~path::Path((*vec)[i].name);
                        if os::path_exists(curr_path) {

                            match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {

                                        let temp_md4 = md4::md4_str(file_data.to_owned());

                                        if(temp_md4 != (*vec)[i].hash)
                                        {
                                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                                Some(s) => s,
                                                None => fail!("Could not access file stats for cache")
                                            };

                                            println(fmt!("===== UPDATING FILE: %?", (*vec)[i].name));

                                            (*vec)[i].data = file_data;
                                            (*vec)[i].size = fileInfo.size;
                                            (*vec)[i].hash = temp_md4;
                                        }
                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }
                                }
                        }
                    }
                }
            }

            timer::sleep(CACHE_MANAGER_B_RATE);
        }
    }

    //MAIN CACHE MANAGER (Manager A)
    do spawn {

        loop {
            do cache_manager_a.write |vec| {

                //Perhaps switch to a struct keeping a dict, so that we don't consume more memory?
                sort::quick_sort((*vec), le);

                let mut cache_remaining = MAX_CACHE_SIZE_BYTES;

                for i in range(0, (*vec).len()) {

                    if((*vec)[i].size <= cache_remaining && !(*vec)[i].in_use_flag) {

                        let curr_path = ~path::Path((*vec)[i].name);

                        if os::path_exists(curr_path) {

                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats for cache")
                            };

                            if(fileInfo.size <= cache_remaining) {

                                match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {

                                        //NEED TO ADD CHECK IF IT HAS SSI
                                        //PERHAPS EXCLUDE ALL SSI FROM CACHE?
                                        //ADD TO IF: size < remaining, !in use, !ssi?

                                        (*vec)[i].data = file_data.to_owned();
                                        (*vec)[i].size = fileInfo.size;
                                        (*vec)[i].hash = md4::md4_str(file_data);
                                        (*vec)[i].in_use_flag = true;

                                        cache_remaining = cache_remaining - fileInfo.size;
                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }
                                }
                            }
                        }
                    }
                    else if((*vec)[i].size <= cache_remaining && (*vec)[i].in_use_flag) {
                        cache_remaining = cache_remaining - (*vec)[i].size;
                    }
                    else if((*vec)[i].size > cache_remaining) {
                        (*vec)[i].in_use_flag = false;
                        (*vec)[i].data = ~[];
                    }

                }
            }

            timer::sleep(CACHE_MANAGER_A_RATE);
        }
    }

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                //Check if file is in cache
                //Will do so using RWArc
                let mut serve_from_cache: bool = false;

                do shared_cache_list.write |vec| {

                    let mut found: bool = false;

                    for i in range(0, (*vec).len()) {

                        if( (*vec)[i].name == tf.filepath.to_str() && (*vec)[i].in_use_flag) {
                            serve_from_cache = true;
                            found = true;

                            println(fmt!("===== SERVING FROM CACHE: %?", tf.filepath.to_str()));

                            tf.stream.write((*vec)[i].data);

                            (*vec)[i].count += 1;
                        }
                        else if( (*vec)[i].name == tf.filepath.to_str() && !(*vec)[i].in_use_flag) {
                            (*vec)[i].count += 1;
                            found = true;
                        }
                    }

                    //If it isn't found, we will create a blank entry and enter basic info, and add the
                    //data and md4 later
                    if(!found) {

                        println(fmt!("===== ADDING ITEM %?", tf.filepath.to_str()));

                        let new_cache_item: cache_item = cache_item{name: tf.filepath.to_str(), in_use_flag: false,
                            ssi_flag: false, hash: ~"", data: ~[], count: 1, size: tf.fileSize};

                        (*vec).push(new_cache_item);

                    }
                }

                if(!serve_from_cache) {

                    match io::read_whole_file(tf.filepath) { // killed if file size is larger than memory size.
                        Ok(file_data) => {
                            //println(fmt!("begin serving file [%?]", tf.filepath));

                            tf.stream.write(file_data);
                            //println(fmt!("finish file [%?]", tf.filepath));

                            println(fmt!("===== SERVING FROM DISK: %?", tf.filepath.to_str()));

                        }
                        Err(err) => {
                            println("ERROR IN SEND");
                            println(err);
                        }
                    }
                }
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {

                    //Since we are using a priority queue, we will use pop()
                    let tf = (*vec).pop();
                    //println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    loop {
        let stream = acceptor.accept();
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        let child_arc = shared_visit.clone();
        do spawn {

            let mut actual_count:uint = 0;

            //We will use the cloned RWARC
            do child_arc.write |count_vec| {

                let prev_count = (*count_vec).pop();
                let new_count: uint = prev_count + 1;

                actual_count = new_count;

                (*count_vec).push(new_count);
            }

            let stream = stream.take();

            match stream {
                Some(s) => {

                    let mut stream = s;

                    let mut buf = [0, ..500];
                    stream.read(buf);
                    let request_str = str::from_utf8(buf);

                    let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
                    if req_group.len() > 2 {
                        let path = req_group[1];
                        //println(fmt!("Request for path: \n%?", path));

                        let file_path = ~os::getcwd().push(path.replace("/../", ""));
                        if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                            //println(fmt!("Request received:\n%s", request_str));
                            let response: ~str = fmt!(
                                "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                                 \r\n", actual_count);

                            stream.write(response.as_bytes());
                        }
                        else {
                            // Requests scheduling

                            let mut streamPriority: int = 0;

                            //Retrieving the requesting IP address
                            let ipStr: ~str = match (stream).peer_name() {
                                Some(pr) => pr.ip.to_str(),
                                None => ~"0.0.0.0"
                            };

                            //Split the IP address by '.' so that we can compare
                            let ipSplit: ~[~str] = ipStr.split_iter('.').filter(|&x| x != "")
                                 .map(|x| x.to_owned()).collect();

                            //Assign priority based on geography or if localhost
                            if ( (ipSplit[0] == ~"127" && ipSplit[1] == ~"0") || (ipSplit[0] == ~"128" && ipSplit[1] == ~"143")
                                || (ipSplit[0] == ~"137" && ipSplit[1] == ~"54") ) {

                                streamPriority = 1;
                            }

                            //Get filetype in order to determine HTTP header type
                            let fileType = match file_path.filetype() {
                                Some(s) => s,
                                None => &""
                            };

                            //In order to optimize for the benchmark, we will send the HTTP header quickly before adding to the queue
                            let httpHeader: ~str = match fileType {
                                ".html" | ".htm" | ".php" => ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n",
                                _ => ~"HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n"
                            };

                            stream.write(httpHeader.as_bytes());
                            stream.flush();

                            //Retrieve file info for additional latency fixes
                            let fileInfo = match std::rt::io::file::stat(file_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats")
                            };

                            let msg: sched_msg = sched_msg{stream: Some(stream), filepath: file_path.clone(), topPriority: streamPriority, fileSize: fileInfo.size};
                            let (sm_port, sm_chan) = std::comm::stream();
                            sm_chan.send(msg);

                            do child_add_vec.write |vec| {
                                let msg = sm_port.recv();
                                (*vec).push(msg); // enqueue new request.
                                //println("add to queue");
                            }
                            child_chan.send(""); //notify the new arriving request.
                            //println(fmt!("get file request: %?", file_path));
                        }
                    }
                    println!("connection terminates")

                },
                None => ()
            }
        }
    }
}<|endoftext|>


<commit_before>use rustc::hir::def_id::DefId;
use rustc::ty::layout::Layout;
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, Ty};
use rustc::mir;
use syntax::codemap::Span;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext, monomorphize_field_ty, StackPopCleanup};
use lvalue::{Lvalue, LvalueExtra};
use memory::{Pointer, FunctionDefinition};
use value::PrimVal;
use value::Value;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {

    /// Creates stack frames for all drop impls. See `drop` for the actual content.
    pub fn eval_drop_impls(&mut self, drops: Vec<(DefId, Value, &'tcx Substs<'tcx>)>, span: Span) -> EvalResult<'tcx> {
        // add them to the stack in reverse order, because the impl that needs to run the last
        // is the one that needs to be at the bottom of the stack
        for (drop_def_id, self_arg, substs) in drops.into_iter().rev() {
            let mir = self.load_mir(drop_def_id)?;
            trace!("substs for drop glue: {:?}", substs);
            self.push_stack_frame(
                drop_def_id,
                span,
                mir,
                substs,
                Lvalue::from_ptr(Pointer::zst_ptr()),
                StackPopCleanup::None,
                Vec::new(),
            )?;
            let mut arg_locals = self.frame().mir.args_iter();
            let first = arg_locals.next().expect("drop impl has self arg");
            assert!(arg_locals.next().is_none(), "drop impl should have only one arg");
            let dest = self.eval_lvalue(&mir::Lvalue::Local(first))?;
            let ty = self.frame().mir.local_decls[first].ty;
            self.write_value(self_arg, dest, ty)?;
        }
        Ok(())
    }

    /// push DefIds of drop impls and their argument on the given vector
    pub fn drop(
        &mut self,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx> {
        if !self.type_needs_drop(ty) {
            debug!("no need to drop {:?}", ty);
            return Ok(());
        }
        trace!("-need to drop {:?} at {:?}", ty, lval);

        match ty.sty {
            // special case `Box` to deallocate the inner allocation
            ty::TyAdt(ref def, _) if def.is_box() => {
                let contents_ty = ty.boxed_ty();
                let val = self.read_lvalue(lval);
                // we are going through the read_value path, because that already does all the
                // checks for the trait object types. We'd only be repeating ourselves here.
                let val = self.follow_by_ref_value(val, ty)?;
                trace!("box dealloc on {:?}", val);
                match val {
                    Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
                    Value::ByVal(ptr) => {
                        assert!(self.type_is_sized(contents_ty));
                        let contents_ptr = ptr.to_ptr()?;
                        self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
                    },
                    Value::ByValPair(prim_ptr, extra) => {
                        let ptr = prim_ptr.to_ptr()?;
                        let extra = match self.tcx.struct_tail(contents_ty).sty {
                            ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?),
                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?),
                            _ => bug!("invalid fat pointer type: {}", ty),
                        };
                        self.drop(Lvalue::Ptr { ptr, extra }, contents_ty, drop)?;
                    },
                }
                let box_free_fn = self.tcx.lang_items.box_free_fn().expect("no box_free lang item");
                let substs = self.tcx.intern_substs(&[Kind::from(contents_ty)]);
                // this is somewhat hacky, but hey, there's no representation difference between
                // pointers and references, so
                // #[lang = "box_free"] unsafe fn box_free<T>(ptr: *mut T)
                // is the same as
                // fn drop(&mut self) if Self is Box<T>
                drop.push((box_free_fn, val, substs));
            },

            ty::TyAdt(adt_def, substs) => {
                // FIXME: some structs are represented as ByValPair
                let lval = self.force_allocation(lval)?;
                let adt_ptr = match lval {
                    Lvalue::Ptr { ptr, .. } => ptr,
                    _ => bug!("force allocation can only yield Lvalue::Ptr"),
                };
                // run drop impl before the fields' drop impls
                if let Some(drop_def_id) = adt_def.destructor() {
                    drop.push((drop_def_id, Value::ByVal(PrimVal::Ptr(adt_ptr)), substs));
                }
                let layout = self.type_layout(ty)?;
                let fields = match *layout {
                    Layout::Univariant { ref variant, .. } => {
                        adt_def.struct_variant().fields.iter().zip(&variant.offsets)
                    },
                    Layout::General { ref variants, .. } => {
                        let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
                        match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u128_unchecked()) {
                            // start at offset 1, to skip over the discriminant
                            Some(i) => adt_def.variants[i].fields.iter().zip(&variants[i].offsets[1..]),
                            None => return Err(EvalError::InvalidDiscriminant),
                        }
                    },
                    Layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            adt_def.variants[discr as usize].fields.iter().zip(&nonnull.offsets)
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::RawNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            assert_eq!(adt_def.variants[discr as usize].fields.len(), 1);
                            let field_ty = &adt_def.variants[discr as usize].fields[0];
                            let field_ty = monomorphize_field_ty(self.tcx, field_ty, substs);
                            // FIXME: once read_discriminant_value works with lvalue, don't force
                            // alloc in the RawNullablePointer case
                            self.drop(lval, field_ty, drop)?;
                            return Ok(());
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::CEnum { .. } => return Ok(()),
                    _ => bug!("{:?} is not an adt layout", layout),
                };
                let tcx = self.tcx;
                self.drop_fields(
                    fields.map(|(ty, &offset)| (monomorphize_field_ty(tcx, ty, substs), offset)),
                    lval,
                    drop,
                )?;
            },
            ty::TyTuple(fields, _) => {
                let offsets = match *self.type_layout(ty)? {
                    Layout::Univariant { ref variant, .. } => &variant.offsets,
                    _ => bug!("tuples must be univariant"),
                };
                self.drop_fields(fields.iter().cloned().zip(offsets.iter().cloned()), lval, drop)?;
            },
            ty::TyDynamic(..) => {
                let (ptr, vtable) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => (ptr, vtable),
                    _ => bug!("expected an lvalue with a vtable"),
                };
                let drop_fn = self.memory.read_ptr(vtable)?;
                // some values don't need to call a drop impl, so the value is null
                if drop_fn != Pointer::from_int(0) {
                    let FunctionDefinition {def_id, substs, sig, ..} = self.memory.get_fn(drop_fn.alloc_id)?.expect_drop_glue()?;
                    let real_ty = match sig.inputs()[0].sty {
                        ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs),
                        _ => bug!("first argument of Drop::drop must be &mut T"),
                    };
                    self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
                } else {
                    // just a sanity check
                    assert_eq!(drop_fn.offset, 0);
                }
            },
            ty::TySlice(elem_ty) => {
                let (ptr, len) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len),
                    _ => bug!("expected an lvalue with a length"),
                };
                let size = self.type_size(elem_ty)?.expect("slice element must be sized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..len {
                    self.drop(Lvalue::from_ptr(ptr.offset(i * size)), elem_ty, drop)?;
                }
            },
            ty::TyArray(elem_ty, len) => {
                let lval = self.force_allocation(lval)?;
                let (ptr, extra) = match lval {
                    Lvalue::Ptr { ptr, extra } => (ptr, extra),
                    _ => bug!("expected an lvalue with optional extra data"),
                };
                let size = self.type_size(elem_ty)?.expect("array element cannot be unsized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..(len as u64) {
                    self.drop(Lvalue::Ptr { ptr: ptr.offset(i * size), extra }, elem_ty, drop)?;
                }
            },
            // FIXME: what about TyClosure and TyAnon?
            // other types do not need to process drop
            _ => {},
        }

        Ok(())
    }

    fn drop_fields<I>(
        &mut self,
        mut fields: I,
        lval: Lvalue<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx>
        where I: Iterator<Item = (Ty<'tcx>, ty::layout::Size)>,
    {
        // FIXME: some aggregates may be represented by Value::ByValPair
        let (adt_ptr, extra) = self.force_allocation(lval)?.to_ptr_and_extra();
        // manual iteration, because we need to be careful about the last field if it is unsized
        while let Some((field_ty, offset)) = fields.next() {
            let ptr = adt_ptr.offset(offset.bytes());
            if self.type_is_sized(field_ty) {
                self.drop(Lvalue::from_ptr(ptr), field_ty, drop)?;
            } else {
                self.drop(Lvalue::Ptr { ptr, extra }, field_ty, drop)?;
                break; // if it is not sized, then this is the last field anyway
            }
        }
        assert!(fields.next().is_none());
        Ok(())
    }

    fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
        self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
    }
}
<commit_msg>add some comments for clarification<commit_after>use rustc::hir::def_id::DefId;
use rustc::ty::layout::Layout;
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, Ty};
use rustc::mir;
use syntax::codemap::Span;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext, monomorphize_field_ty, StackPopCleanup};
use lvalue::{Lvalue, LvalueExtra};
use memory::{Pointer, FunctionDefinition};
use value::PrimVal;
use value::Value;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {

    /// Creates stack frames for all drop impls. See `drop` for the actual content.
    pub fn eval_drop_impls(&mut self, drops: Vec<(DefId, Value, &'tcx Substs<'tcx>)>, span: Span) -> EvalResult<'tcx> {
        // add them to the stack in reverse order, because the impl that needs to run the last
        // is the one that needs to be at the bottom of the stack
        for (drop_def_id, self_arg, substs) in drops.into_iter().rev() {
            let mir = self.load_mir(drop_def_id)?;
            trace!("substs for drop glue: {:?}", substs);
            self.push_stack_frame(
                drop_def_id,
                span,
                mir,
                substs,
                Lvalue::from_ptr(Pointer::zst_ptr()),
                StackPopCleanup::None,
                Vec::new(),
            )?;
            let mut arg_locals = self.frame().mir.args_iter();
            let first = arg_locals.next().expect("drop impl has self arg");
            assert!(arg_locals.next().is_none(), "drop impl should have only one arg");
            let dest = self.eval_lvalue(&mir::Lvalue::Local(first))?;
            let ty = self.frame().mir.local_decls[first].ty;
            self.write_value(self_arg, dest, ty)?;
        }
        Ok(())
    }

    /// push DefIds of drop impls and their argument on the given vector
    pub fn drop(
        &mut self,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx> {
        if !self.type_needs_drop(ty) {
            debug!("no need to drop {:?}", ty);
            return Ok(());
        }
        trace!("-need to drop {:?} at {:?}", ty, lval);

        match ty.sty {
            // special case `Box` to deallocate the inner allocation
            ty::TyAdt(ref def, _) if def.is_box() => {
                let contents_ty = ty.boxed_ty();
                let val = self.read_lvalue(lval);
                // we are going through the read_value path, because that already does all the
                // checks for the trait object types. We'd only be repeating ourselves here.
                let val = self.follow_by_ref_value(val, ty)?;
                trace!("box dealloc on {:?}", val);
                match val {
                    Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
                    Value::ByVal(ptr) => {
                        assert!(self.type_is_sized(contents_ty));
                        let contents_ptr = ptr.to_ptr()?;
                        self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
                    },
                    Value::ByValPair(prim_ptr, extra) => {
                        let ptr = prim_ptr.to_ptr()?;
                        let extra = match self.tcx.struct_tail(contents_ty).sty {
                            ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?),
                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?),
                            _ => bug!("invalid fat pointer type: {}", ty),
                        };
                        self.drop(Lvalue::Ptr { ptr, extra }, contents_ty, drop)?;
                    },
                }
                // We cannot use Box's destructor, because it is a no-op and only exists to reduce
                // the number of hacks required in the compiler around the Box type.
                let box_free_fn = self.tcx.lang_items.box_free_fn().expect("no box_free lang item");
                let substs = self.tcx.intern_substs(&[Kind::from(contents_ty)]);
                // this is somewhat hacky, but hey, there's no representation difference between
                // pointers, `Box`es and references, so
                // #[lang = "box_free"] unsafe fn box_free<T>(ptr: *mut T)
                // is the same as
                // fn drop(&mut self) if Self is Box<T>
                drop.push((box_free_fn, val, substs));
            },

            ty::TyAdt(adt_def, substs) => {
                // FIXME: some structs are represented as ByValPair
                let lval = self.force_allocation(lval)?;
                let adt_ptr = match lval {
                    Lvalue::Ptr { ptr, .. } => ptr,
                    _ => bug!("force allocation can only yield Lvalue::Ptr"),
                };
                // run drop impl before the fields' drop impls
                if let Some(drop_def_id) = adt_def.destructor() {
                    drop.push((drop_def_id, Value::ByVal(PrimVal::Ptr(adt_ptr)), substs));
                }
                let layout = self.type_layout(ty)?;
                let fields = match *layout {
                    Layout::Univariant { ref variant, .. } => {
                        adt_def.struct_variant().fields.iter().zip(&variant.offsets)
                    },
                    Layout::General { ref variants, .. } => {
                        let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
                        match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u128_unchecked()) {
                            // start at offset 1, to skip over the discriminant
                            Some(i) => adt_def.variants[i].fields.iter().zip(&variants[i].offsets[1..]),
                            None => return Err(EvalError::InvalidDiscriminant),
                        }
                    },
                    Layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            adt_def.variants[discr as usize].fields.iter().zip(&nonnull.offsets)
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::RawNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            assert_eq!(adt_def.variants[discr as usize].fields.len(), 1);
                            let field_ty = &adt_def.variants[discr as usize].fields[0];
                            let field_ty = monomorphize_field_ty(self.tcx, field_ty, substs);
                            // FIXME: once read_discriminant_value works with lvalue, don't force
                            // alloc in the RawNullablePointer case
                            self.drop(lval, field_ty, drop)?;
                            return Ok(());
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::CEnum { .. } => return Ok(()),
                    _ => bug!("{:?} is not an adt layout", layout),
                };
                let tcx = self.tcx;
                self.drop_fields(
                    fields.map(|(ty, &offset)| (monomorphize_field_ty(tcx, ty, substs), offset)),
                    lval,
                    drop,
                )?;
            },
            ty::TyTuple(fields, _) => {
                let offsets = match *self.type_layout(ty)? {
                    Layout::Univariant { ref variant, .. } => &variant.offsets,
                    _ => bug!("tuples must be univariant"),
                };
                self.drop_fields(fields.iter().cloned().zip(offsets.iter().cloned()), lval, drop)?;
            },
            ty::TyDynamic(..) => {
                let (ptr, vtable) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => (ptr, vtable),
                    _ => bug!("expected an lvalue with a vtable"),
                };
                let drop_fn = self.memory.read_ptr(vtable)?;
                // some values don't need to call a drop impl, so the value is null
                if drop_fn != Pointer::from_int(0) {
                    // FIXME: change the `DropGlue` variant of `Function` to only contain `real_ty`
                    let FunctionDefinition {substs, sig, ..} = self.memory.get_fn(drop_fn.alloc_id)?.expect_drop_glue()?;
                    // The real type is taken from the self argument in `fn drop(&mut self)`
                    let real_ty = match sig.inputs()[0].sty {
                        ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs),
                        _ => bug!("first argument of Drop::drop must be &mut T"),
                    };
                    self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
                } else {
                    // just a sanity check
                    assert_eq!(drop_fn.offset, 0);
                }
            },
            ty::TySlice(elem_ty) => {
                let (ptr, len) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len),
                    _ => bug!("expected an lvalue with a length"),
                };
                let size = self.type_size(elem_ty)?.expect("slice element must be sized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..len {
                    self.drop(Lvalue::from_ptr(ptr.offset(i * size)), elem_ty, drop)?;
                }
            },
            ty::TyArray(elem_ty, len) => {
                let lval = self.force_allocation(lval)?;
                let (ptr, extra) = match lval {
                    Lvalue::Ptr { ptr, extra } => (ptr, extra),
                    _ => bug!("expected an lvalue with optional extra data"),
                };
                let size = self.type_size(elem_ty)?.expect("array element cannot be unsized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..(len as u64) {
                    self.drop(Lvalue::Ptr { ptr: ptr.offset(i * size), extra }, elem_ty, drop)?;
                }
            },
            // FIXME: what about TyClosure and TyAnon?
            // other types do not need to process drop
            _ => {},
        }

        Ok(())
    }

    fn drop_fields<I>(
        &mut self,
        mut fields: I,
        lval: Lvalue<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx>
        where I: Iterator<Item = (Ty<'tcx>, ty::layout::Size)>,
    {
        // FIXME: some aggregates may be represented by Value::ByValPair
        let (adt_ptr, extra) = self.force_allocation(lval)?.to_ptr_and_extra();
        // manual iteration, because we need to be careful about the last field if it is unsized
        while let Some((field_ty, offset)) = fields.next() {
            let ptr = adt_ptr.offset(offset.bytes());
            if self.type_is_sized(field_ty) {
                self.drop(Lvalue::from_ptr(ptr), field_ty, drop)?;
            } else {
                self.drop(Lvalue::Ptr { ptr, extra }, field_ty, drop)?;
                break; // if it is not sized, then this is the last field anyway
            }
        }
        assert!(fields.next().is_none());
        Ok(())
    }

    fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
        self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
    }
}
<|endoftext|>


<commit_before>//! # RCC Module
//!
//! This module configures the Reset and Clock Control at 48Mhz
//!
//! ## Example :
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::rcc;
//!
//! rcc::init();
//! ```

use stm32f0x2::{FLASH, RCC};
use cortex_m;
use core::ptr;

use cortex_m::peripheral::{SystClkSource, SYST};

static mut TICKS: u32 = 0;

pub fn init() {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let flash = FLASH.borrow(cs);
        let systick = SYST.borrow(cs);

        flash.acr.write(|w| w.latency()._1wait_state());
        // Select HSI as main system clock
        rcc.cr.modify(|_, w| w.hsion().set_bit());
        // Waiting HSI enabled
        while rcc.cr.read().hsirdy().bit_is_clear() {}
        // Set HSI Calibration trimming - 8MHz
        rcc.cr.write(|w| w.hsitrim().bits(15));

        // To be sure : Disable PLL
        rcc.cr.modify(|_, w| w.pllon().clear_bit());
        // Waiting PLL Off
        while rcc.cr.read().pllrdy().bit_is_set() {}
        // Configure PLL source clock predivider to 1
        rcc.cfgr2.write(|w| w.prediv().div1());
        // Configure PLL source clock to HSI (8MHz) and multiplier to 6
        rcc.cfgr.write(|w| w.pllsrc().hsi().pllmul().mul6());
        // PLL On
        rcc.cr.modify(|_, w| w.pllon().set_bit());
        // Waiting PLL On
        while rcc.cr.read().pllrdy().bit_is_clear() {}
        // Set AHB & APB divider to 1 -> 48MHz
        rcc.cfgr.modify(|_, w| w.hpre().div1().ppre().div1());
        // Select PLL output as system clock
        rcc.cfgr.modify(|_, w| w.sw().pll());
        // Waiting system clock ready
        while rcc.cfgr.read().sws().bits() != 2 {}
        // Configure Systick source and base time 1ms
        systick.set_clock_source(SystClkSource::Core);
        systick.set_reload((48000000 / 1000) - 1);
        systick.enable_counter();
        systick.enable_interrupt();
    });
}

pub fn ms_delay(delay: u32) {
    let start = systick();
    while (systick() - start) < delay {}
}

fn systick() -> u32 {
    return unsafe { ptr::read_volatile(&TICKS) };
}

exception!(SYS_TICK, tick);

fn tick() {
    unsafe {
        TICKS += 1;
    }
}
<commit_msg>make systick public<commit_after>//! # RCC Module
//!
//! This module configures the Reset and Clock Control at 48Mhz
//!
//! ## Example :
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::rcc;
//!
//! rcc::init();
//! ```

use stm32f0x2::{FLASH, RCC};
use cortex_m;
use core::ptr;

use cortex_m::peripheral::{SystClkSource, SYST};

static mut TICKS: u32 = 0;

pub fn init() {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let flash = FLASH.borrow(cs);
        let systick = SYST.borrow(cs);

        flash.acr.write(|w| w.latency()._1wait_state());
        // Select HSI as main system clock
        rcc.cr.modify(|_, w| w.hsion().set_bit());
        // Waiting HSI enabled
        while rcc.cr.read().hsirdy().bit_is_clear() {}
        // Set HSI Calibration trimming - 8MHz
        rcc.cr.write(|w| w.hsitrim().bits(15));

        // To be sure : Disable PLL
        rcc.cr.modify(|_, w| w.pllon().clear_bit());
        // Waiting PLL Off
        while rcc.cr.read().pllrdy().bit_is_set() {}
        // Configure PLL source clock predivider to 1
        rcc.cfgr2.write(|w| w.prediv().div1());
        // Configure PLL source clock to HSI (8MHz) and multiplier to 6
        rcc.cfgr.write(|w| w.pllsrc().hsi().pllmul().mul6());
        // PLL On
        rcc.cr.modify(|_, w| w.pllon().set_bit());
        // Waiting PLL On
        while rcc.cr.read().pllrdy().bit_is_clear() {}
        // Set AHB & APB divider to 1 -> 48MHz
        rcc.cfgr.modify(|_, w| w.hpre().div1().ppre().div1());
        // Select PLL output as system clock
        rcc.cfgr.modify(|_, w| w.sw().pll());
        // Waiting system clock ready
        while rcc.cfgr.read().sws().bits() != 2 {}
        // Configure Systick source and base time 1ms
        systick.set_clock_source(SystClkSource::Core);
        systick.set_reload((48000000 / 1000) - 1);
        systick.enable_counter();
        systick.enable_interrupt();
    });
}

pub fn ms_delay(delay: u32) {
    let start = systick();
    while (systick() - start) < delay {}
}

pub fn systick() -> u32 {
    return unsafe { ptr::read_volatile(&TICKS) };
}

exception!(SYS_TICK, tick);

fn tick() {
    unsafe {
        TICKS += 1;
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;

use futures::executor::block_on;
use futures::future::poll_fn;
use futures::task::{AtomicWaker, Poll};

#[test]
fn basic() {
    let atomic_waker = Arc::new(AtomicWaker::new());
    let atomic_waker_copy = atomic_waker.clone();

    let returned_pending = Arc::new(AtomicUsize::new(0));
    let returned_pending_copy = returned_pending.clone();

    let woken = Arc::new(AtomicUsize::new(0));
    let woken_copy = woken.clone();

    let t = thread::spawn(move || {
        let mut pending_count = 0;

        block_on(poll_fn(move |cx| {
            if woken_copy.load(Ordering::Relaxed) == 1 {
                Poll::Ready(())
            } else {
                // Assert we return pending exactly once
                assert_eq!(0, pending_count);
                pending_count += 1;
                atomic_waker_copy.register(cx.waker());

                returned_pending_copy.store(1, Ordering::Relaxed);

                Poll::Pending
            }
        }))
    });

    while returned_pending.load(Ordering::Relaxed) == 0 {}

    // give spawned thread some time to sleep in `block_on`
    thread::yield_now();

    woken.store(1, Ordering::Relaxed);
    atomic_waker.wake();

    t.join().unwrap();
}
<commit_msg>futures: tests/atomic_waker.rs: Guard against failures w/o executor<commit_after>#[cfg(feature = "executor")]
#[test]
fn basic() {
    use std::sync::atomic::AtomicUsize;
    use std::sync::atomic::Ordering;
    use std::sync::Arc;
    use std::thread;

    use futures::executor::block_on;
    use futures::future::poll_fn;
    use futures::task::{AtomicWaker, Poll};

    let atomic_waker = Arc::new(AtomicWaker::new());
    let atomic_waker_copy = atomic_waker.clone();

    let returned_pending = Arc::new(AtomicUsize::new(0));
    let returned_pending_copy = returned_pending.clone();

    let woken = Arc::new(AtomicUsize::new(0));
    let woken_copy = woken.clone();

    let t = thread::spawn(move || {
        let mut pending_count = 0;

        block_on(poll_fn(move |cx| {
            if woken_copy.load(Ordering::Relaxed) == 1 {
                Poll::Ready(())
            } else {
                // Assert we return pending exactly once
                assert_eq!(0, pending_count);
                pending_count += 1;
                atomic_waker_copy.register(cx.waker());

                returned_pending_copy.store(1, Ordering::Relaxed);

                Poll::Pending
            }
        }))
    });

    while returned_pending.load(Ordering::Relaxed) == 0 {}

    // give spawned thread some time to sleep in `block_on`
    thread::yield_now();

    woken.store(1, Ordering::Relaxed);
    atomic_waker.wake();

    t.join().unwrap();
}
<|endoftext|>


<commit_before>use crate::data_types::SolrReferenceSummary;

use regex::Regex;

use std::collections::HashMap;

use once_cell::unsync::Lazy;

use crate::web::config::ServerConfig;
use crate::api::search_types::*;
use crate::api::search_utils::{do_solr_request, clean_words};

lazy_static! {
    static ref CLEAN_WORDS_RE: Regex = Regex::new(r"([\w\d\-]+)").unwrap();
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub highlighting: HashMap<SolrMatchId, SolrMatchHighlight>,
    pub response: SolrRefResponse,
}

fn make_refs_url(config: &ServerConfig, q: &str, query_field_names: &[&str])
                 -> Option<String>
{
    let joined_query_fields = query_field_names.join(",");
    let mut refs_url =
        format!("{}/refs/select?wt=json&hl=on&hl.fl={},publication_year&q=",
                &config.solr_url,
                &joined_query_fields);

    let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
    let id_re = Regex::new(id_re_string).unwrap();

    if let Some(captures) = id_re.captures(q) {
        let prefix =
            if let Some(prefix_capture) = captures.name("prefix") {
                prefix_capture.as_str()
            } else {
                "PMID"
            };
        let accession = captures.name("rest").unwrap().as_str();
        refs_url += "id:";
        refs_url += prefix;
        refs_url += r"\:";
        refs_url += accession;
    } else {
        let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
        let lower_q = substring(&q.to_lowercase(), 200);

        let gene_uniquename_re =
            Lazy::new(|| {
                let lower_gene_re = config.gene_uniquename_re.to_lowercase();
                Regex::new(&lower_gene_re).unwrap()
            });

        if gene_uniquename_re.is_match(&lower_q) {
            refs_url += & query_field_names
                .iter()
                .map(|field_name| {
                    format!("{}:(\"{}\")", field_name, lower_q)
                })
                .collect::<Vec<String>>()
                .join(" OR ");
        } else {
            let clean_words: Vec<String> = clean_words(&lower_q);

            if clean_words.is_empty() {
                return None
            }

            let clean_words_length = clean_words.len();

            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                query_field_names
                .iter()
                .map(|field_name| {
                    let weight = if *field_name == "title" {
                        2.0
                    } else {
                        0.5
                    };
                    format!("{}:({})^{}", field_name, clean_words_for_url, weight)
                })
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }
    }

    Some(refs_url)
}

fn matches_from_container(container: SolrRefResponseContainer) -> Vec<SolrReferenceSummary> {
    let mut response_container: SolrRefResponseContainer = container;
    let mut hl_by_id = response_container.highlighting;
    let matches: Vec<SolrReferenceSummary> = response_container.response.docs
        .drain(0..)
        .map(|mut doc: SolrReferenceSummary| {
            doc.highlighting = hl_by_id.remove(doc.id.as_str())
                .unwrap_or_else(HashMap::new);
            doc
        }).collect();
    matches
}

pub fn search_refs(config: &ServerConfig, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
    let query_field_names =
      ["title", "citation", "authors", "pubmed_abstract", "authors_abbrev"];
    let maybe_url = make_refs_url(config, q, &query_field_names);
    if let Some(url) = maybe_url {
        let res = do_solr_request(&url)?;

        match serde_json::from_reader(res) {
            Ok(container) => Ok(matches_from_container(container)),
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        Ok(vec![])
    }
}
<commit_msg>Increase weight of authors field in refs lookup<commit_after>use crate::data_types::SolrReferenceSummary;

use regex::Regex;

use std::collections::HashMap;

use once_cell::unsync::Lazy;

use crate::web::config::ServerConfig;
use crate::api::search_types::*;
use crate::api::search_utils::{do_solr_request, clean_words};

lazy_static! {
    static ref CLEAN_WORDS_RE: Regex = Regex::new(r"([\w\d\-]+)").unwrap();
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub highlighting: HashMap<SolrMatchId, SolrMatchHighlight>,
    pub response: SolrRefResponse,
}

fn make_refs_url(config: &ServerConfig, q: &str, query_field_names: &[&str])
                 -> Option<String>
{
    let joined_query_fields = query_field_names.join(",");
    let mut refs_url =
        format!("{}/refs/select?wt=json&hl=on&hl.fl={},publication_year&q=",
                &config.solr_url,
                &joined_query_fields);

    let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
    let id_re = Regex::new(id_re_string).unwrap();

    if let Some(captures) = id_re.captures(q) {
        let prefix =
            if let Some(prefix_capture) = captures.name("prefix") {
                prefix_capture.as_str()
            } else {
                "PMID"
            };
        let accession = captures.name("rest").unwrap().as_str();
        refs_url += "id:";
        refs_url += prefix;
        refs_url += r"\:";
        refs_url += accession;
    } else {
        let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
        let lower_q = substring(&q.to_lowercase(), 200);

        let gene_uniquename_re =
            Lazy::new(|| {
                let lower_gene_re = config.gene_uniquename_re.to_lowercase();
                Regex::new(&lower_gene_re).unwrap()
            });

        if gene_uniquename_re.is_match(&lower_q) {
            refs_url += & query_field_names
                .iter()
                .map(|field_name| {
                    format!("{}:(\"{}\")", field_name, lower_q)
                })
                .collect::<Vec<String>>()
                .join(" OR ");
        } else {
            let clean_words: Vec<String> = clean_words(&lower_q);

            if clean_words.is_empty() {
                return None
            }

            let clean_words_length = clean_words.len();

            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                query_field_names
                .iter()
                .map(|field_name| {
                    let weight = if *field_name == "title" || *field_name == "authors" {
                        2.0
                    } else {
                        0.5
                    };
                    format!("{}:({})^{}", field_name, clean_words_for_url, weight)
                })
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }
    }

    Some(refs_url)
}

fn matches_from_container(container: SolrRefResponseContainer) -> Vec<SolrReferenceSummary> {
    let mut response_container: SolrRefResponseContainer = container;
    let mut hl_by_id = response_container.highlighting;
    let matches: Vec<SolrReferenceSummary> = response_container.response.docs
        .drain(0..)
        .map(|mut doc: SolrReferenceSummary| {
            doc.highlighting = hl_by_id.remove(doc.id.as_str())
                .unwrap_or_else(HashMap::new);
            doc
        }).collect();
    matches
}

pub fn search_refs(config: &ServerConfig, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
    let query_field_names =
      ["title", "citation", "authors", "pubmed_abstract", "authors_abbrev"];
    let maybe_url = make_refs_url(config, q, &query_field_names);
    if let Some(url) = maybe_url {
        let res = do_solr_request(&url)?;

        match serde_json::from_reader(res) {
            Ok(container) => Ok(matches_from_container(container)),
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        Ok(vec![])
    }
}
<|endoftext|>


<commit_before>use regex::Regex;

use ::bot::{Bot, Node, RoomEvent};

use super::backend::Backend;

pub struct ShowKarma<'a> {
    vote_db: Backend,
    children: Vec<&'a str>,
}

impl<'a> ShowKarma<'a> {
    pub fn new() -> Self {
        Self {
            vote_db: Backend::new(),
            children: Vec::new(),
        }
    }
}

impl<'a> Node<'a> for ShowKarma<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        Some(&self.children)
    }

    fn register_child(&mut self, name: &'a str) {
        self.children.push(name);
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        let revent = event.raw_event;
        if revent.type_ == "m.room.message" &&
            revent.content["msgtype"] == "m.text" {
            let body = revent.content["body"].as_str().unwrap();

            let check_re = Regex::new(r"^karma (.+)").unwrap();

            let mut finds = 0;
            for cap in check_re.captures_iter(body) {
                finds += 1;
                let query = cap[1].trim();
                if let Some(k) = self.vote_db.get_upvotes(query) {
                    let positive = (k.total_up as f32/(k.total_up+k.total_down) as f32)*100.0;
                    let total = k.total_up - k.total_down;
                    let response = format!("{} has {} karma (+{}/-{}) {:.2}% like it",
                        query, total, k.total_up, k.total_down, positive
                    );
                    bot.reply(&event, &response);
                }
            }

            if finds == 0 {
                self.propagate_event(bot, event);
            }
        }
    }
}
<commit_msg>Improve karma stats message display<commit_after>use regex::Regex;

use ::bot::{Bot, Node, RoomEvent};

use super::backend::Backend;

pub struct ShowKarma<'a> {
    vote_db: Backend,
    children: Vec<&'a str>,
}

impl<'a> ShowKarma<'a> {
    pub fn new() -> Self {
        Self {
            vote_db: Backend::new(),
            children: Vec::new(),
        }
    }
}

impl<'a> Node<'a> for ShowKarma<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        Some(&self.children)
    }

    fn register_child(&mut self, name: &'a str) {
        self.children.push(name);
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        let revent = event.raw_event;
        if revent.type_ == "m.room.message" &&
            revent.content["msgtype"] == "m.text" {
            let body = revent.content["body"].as_str().unwrap();

            let check_re = Regex::new(r"^karma (.+)").unwrap();

            let mut finds = 0;
            for cap in check_re.captures_iter(body) {
                finds += 1;
                let query = cap[1].trim();
                if let Some(k) = self.vote_db.get_upvotes(query) {
                    let positive = (k.total_up as f32/(k.total_up+k.total_down) as f32)*100.0;
                    let total = k.total_up - k.total_down;
                    let response = format!("Karma for '{}': Net karma: {} (+{}/-{}; {:.1}% like it)",
                        query, total, k.total_up, k.total_down, positive
                    );
                    bot.reply(&event, &response);
                } else {
                    let response = format!("Karma for '{}': Net karma: 0 (+0/-0 0% like it)", query);
                    bot.reply(&event, &response);
                }
            }

            if finds == 0 {
                self.propagate_event(bot, event);
            }
        }
    }
}
<|endoftext|>