<commit_before>//! Low-level bindings to libm

#![cfg(target_os = "linux")]

extern crate linux_api;

use linux_api::{c_double, c_float,
                c_long, c_longlong};

#[link(name = "m")] //For -lm
extern {

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn nearbyint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn nearbyintf(x: c_float) -> c_float;

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn rint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn rintf(x: c_float) -> c_float;

    ///Rounds a c_double to the nearest c_long
    pub fn lrint(x: c_double) -> c_long;

    ///Rounds a c_float to the nearest c_long
    pub fn lrintf(x: c_float) -> c_long;

    ///Rounds a c_double to the nearest c_longlong
    pub fn llrint(x: c_double) -> c_longlong;

    ///Rounds a c_float to the nearest c_longlong
    pub fn llrintf(x: c_float) -> c_longlong;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainder(numer: c_double, denom: c_double) -> c_double;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainderf(number: c_float, denom: c_float) -> c_float;

}

#[cfg(test)]
#[allow(unused_assignments)] // Unsafe functions
mod test {

    extern crate linux_api;

    use linux_api::{c_long, c_longlong, c_float, c_double};

    use super::*;

    #[test]
    fn test_rint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = rint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_rintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = rintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_nearbyint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = nearbyint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_nearbyintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = nearbyintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_lrint() {

        let value = 2464326.432f64;

        let mut result: c_long = 0;

        unsafe { result = lrint(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_lrintf() {

        let value = 2464326.432f32;

        let mut result: c_long = 0;

        unsafe { result = lrintf(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_llrint() {

        let value = 46873283884.432f64;

        let mut result: c_longlong = 0;

        unsafe { result = llrint(value); }

        assert_eq!(46873283884, result);

    }

    #[test]
    fn test_llrintf() {

        let value = 4687328.9732f32;

        let mut result: c_longlong = 0;

        unsafe { result = llrintf(value); }

        assert_eq!(4687329, result);

    }

    #[test]
    fn test_remainder() {
        let number: c_double = 18.5;
        let denominator: c_double = 4.2;

        unsafe {
            assert!(remainder(number, denominator).abs_sub(1.7) <= 0.0000001);
        }
    }

    #[test]
    fn test_remainderf() {
        let number: c_float = 5.3;
        let denominator: c_float = 2.0;

        unsafe {
            assert!(remainderf(number, denominator).abs_sub(0.7) <= 0.0000001);
        }
    }

}
<commit_msg>Add a list of unused functions<commit_after>//! Low-level bindings to libm

#![cfg(target_os = "linux")]

extern crate linux_api;

use linux_api::{c_double, c_float,
                c_long, c_longlong};

#[link(name = "m")] //For -lm
extern {

    //cos
    //sin
    //tan
    //acos
    //asin
    //atan
    //atan2

    //cosh
    //sinh
    //tanh
    //acosh
    //asinh
    //atanh

    //exp
    //frexp
    //ldexp
    //log
    //log10
    //modf
    //exp2
    //expm1
    //ilogb
    //log1p
    //log2
    //logb
    //scalbn
    //scalbln

    //pow
    //sqrt
    //cbrt
    //hopot

    //erf
    //erfc
    //tgamma
    //lgamma

    //ceil
    //floor
    //fmod
    //trunc
    //round
    //lround
    //llround

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn rint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn rintf(x: c_float) -> c_float;

    ///Rounds a c_double to the nearest c_long
    pub fn lrint(x: c_double) -> c_long;

    ///Rounds a c_float to the nearest c_long
    pub fn lrintf(x: c_float) -> c_long;

    ///Rounds a c_double to the nearest c_longlong
    pub fn llrint(x: c_double) -> c_longlong;

    ///Rounds a c_float to the nearest c_longlong
    pub fn llrintf(x: c_float) -> c_longlong;

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn nearbyint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn nearbyintf(x: c_float) -> c_float;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainder(numer: c_double, denom: c_double) -> c_double;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainderf(number: c_float, denom: c_float) -> c_float;

    //remquo

    //copysign
    //nan
    //nextafter
    //nexttoward

    //fdim
    //fmax
    //fmin

    //fabs
    //abs
    //fma

}

#[cfg(test)]
#[allow(unused_assignments)] // Unsafe functions
mod test {

    extern crate linux_api;

    use linux_api::{c_long, c_longlong, c_float, c_double};

    use super::*;

    #[test]
    fn test_rint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = rint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_rintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = rintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_nearbyint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = nearbyint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_nearbyintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = nearbyintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_lrint() {

        let value = 2464326.432f64;

        let mut result: c_long = 0;

        unsafe { result = lrint(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_lrintf() {

        let value = 2464326.432f32;

        let mut result: c_long = 0;

        unsafe { result = lrintf(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_llrint() {

        let value = 46873283884.432f64;

        let mut result: c_longlong = 0;

        unsafe { result = llrint(value); }

        assert_eq!(46873283884, result);

    }

    #[test]
    fn test_llrintf() {

        let value = 4687328.9732f32;

        let mut result: c_longlong = 0;

        unsafe { result = llrintf(value); }

        assert_eq!(4687329, result);

    }

    #[test]
    fn test_remainder() {
        let number: c_double = 18.5;
        let denominator: c_double = 4.2;

        unsafe {
            assert!(remainder(number, denominator).abs_sub(1.7) <= 0.0000001);
        }
    }

    #[test]
    fn test_remainderf() {
        let number: c_float = 5.3;
        let denominator: c_float = 2.0;

        unsafe {
            assert!(remainderf(number, denominator).abs_sub(0.7) <= 0.0000001);
        }
    }

}
<|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";
//static mut visitor_count: uint = 0;

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 visitor_count : uint = 0;
    let shared_visitor_count = arc::RWArc::new(visitor_count);

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

    // 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));
                        // 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.
                }
            }
        }
    }

    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() {
        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 (port2, chan2) = std::comm::stream();
        chan2.send(shared_visitor_count.clone());
        do spawn {
            let visitor_count = port2.recv();
            visitor_count.write(|count| {
                *count += 1;
            });

            let mut stream = stream.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) {
                    visitor_count.read(|val| {
                        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", *val);

                        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);

                    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")
        }
    }
}
<commit_msg>IP preferencing and srpt first should be working<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::*;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";
//static mut visitor_count: uint = 0;

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

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 visitor_count : uint = 0;
    let shared_visitor_count = arc::RWArc::new(visitor_count);

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

    // 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));
                        // 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.
                }
            }
        }
    }

    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() {
        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 (port2, chan2) = std::comm::stream();
        chan2.send(shared_visitor_count.clone());
        do spawn {
            let visitor_count = port2.recv();
            visitor_count.write(|count| {
                *count += 1;
            });

            let mut stream = stream.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) {
                    visitor_count.read(|val| {
                        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", *val);

                        stream.write(response.as_bytes());
                    });
                }
                else {
                    // Requests scheduling
                    let mut file_size = 0;
                    let reader : Result<@io::Reader, ~str> = io::file_reader(file_path);
                    match reader {
                        Ok(reader) => {
                            reader.seek(0, io::SeekEnd);
                            file_size = reader.tell();
                        },
                        Err(msg) => {
                            println(msg);
                        },
                    }

                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), file_size: file_size};
                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    let ip_str = ip.to_str().clone();
                    let mut is_ip_preferred = false;

                    if ip_str.slice(0, 8) == "128.143." || ip_str.slice(0, 7) == "137.54." || ip_str.slice(0, 8) == "192.168." {
                        is_ip_preferred = true;
                    }

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        if is_ip_preferred {
                            (*vec).insert(0, msg); // enqueue new preferred request.
                        }
                        else {
                            let mut insert_pos = 0;
                            for queued_msg in vec.iter() {
                                if msg.file_size > queued_msg.file_size {
                                    insert_pos += 1;
                                }
                                else {
                                    break;
                                }
                            }
                            (*vec).insert(insert_pos, 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")
        }
    }
}
<|endoftext|>


<commit_before>use super::{Duration, Instant, SystemTime, UNIX_EPOCH};

macro_rules! assert_almost_eq {
    ($a:expr, $b:expr) => {{
        let (a, b) = ($a, $b);
        if a != b {
            let (a, b) = if a > b { (a, b) } else { (b, a) };
            assert!(a - Duration::from_micros(1) <= b, "{:?} is not almost equal to {:?}", a, b);
        }
    }};
}

#[test]
fn instant_monotonic() {
    let a = Instant::now();
    loop {
        let b = Instant::now();
        assert!(b >= a);
        if b > a {
            break;
        }
    }
}

#[test]
fn instant_monotonic_concurrent() -> crate::thread::Result<()> {
    let threads: Vec<_> = (0..8)
        .map(|_| {
            crate::thread::spawn(|| {
                let mut old = Instant::now();
                for _ in 0..5_000_000 {
                    let new = Instant::now();
                    assert!(new >= old);
                    old = new;
                }
            })
        })
        .collect();
    for t in threads {
        t.join()?;
    }
    Ok(())
}

#[test]
fn instant_elapsed() {
    let a = Instant::now();
    a.elapsed();
}

#[test]
fn instant_math() {
    let a = Instant::now();
    let b = Instant::now();
    println!("a: {:?}", a);
    println!("b: {:?}", b);
    let dur = b.duration_since(a);
    println!("dur: {:?}", dur);
    assert_almost_eq!(b - dur, a);
    assert_almost_eq!(a + dur, b);

    let second = Duration::SECOND;
    assert_almost_eq!(a - second + second, a);
    assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);

    // checked_add_duration will not panic on overflow
    let mut maybe_t = Some(Instant::now());
    let max_duration = Duration::from_secs(u64::MAX);
    // in case `Instant` can store `>= now + max_duration`.
    for _ in 0..2 {
        maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
    }
    assert_eq!(maybe_t, None);

    // checked_add_duration calculates the right time and will work for another year
    let year = Duration::from_secs(60 * 60 * 24 * 365);
    assert_eq!(a + year, a.checked_add(year).unwrap());
}

#[test]
fn instant_math_is_associative() {
    let now = Instant::now();
    let offset = Duration::from_millis(5);
    // Changing the order of instant math shouldn't change the results,
    // especially when the expression reduces to X + identity.
    assert_eq!((now + offset) - now, (now - now) + offset);
}

#[test]
#[should_panic]
fn instant_duration_since_panic() {
    let a = Instant::now();
    (a - Duration::SECOND).duration_since(a);
}

#[test]
fn instant_checked_duration_since_nopanic() {
    let now = Instant::now();
    let earlier = now - Duration::SECOND;
    let later = now + Duration::SECOND;
    assert_eq!(earlier.checked_duration_since(now), None);
    assert_eq!(later.checked_duration_since(now), Some(Duration::SECOND));
    assert_eq!(now.checked_duration_since(now), Some(Duration::ZERO));
}

#[test]
fn instant_saturating_duration_since_nopanic() {
    let a = Instant::now();
    let ret = (a - Duration::SECOND).saturating_duration_since(a);
    assert_eq!(ret, Duration::ZERO);
}

#[test]
fn system_time_math() {
    let a = SystemTime::now();
    let b = SystemTime::now();
    match b.duration_since(a) {
        Ok(Duration::ZERO) => {
            assert_almost_eq!(a, b);
        }
        Ok(dur) => {
            assert!(b > a);
            assert_almost_eq!(b - dur, a);
            assert_almost_eq!(a + dur, b);
        }
        Err(dur) => {
            let dur = dur.duration();
            assert!(a > b);
            assert_almost_eq!(b + dur, a);
            assert_almost_eq!(a - dur, b);
        }
    }

    let second = Duration::SECOND;
    assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
    assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second);

    assert_almost_eq!(a - second + second, a);
    assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);

    let one_second_from_epoch = UNIX_EPOCH + Duration::SECOND;
    let one_second_from_epoch2 =
        UNIX_EPOCH + Duration::from_millis(500) + Duration::from_millis(500);
    assert_eq!(one_second_from_epoch, one_second_from_epoch2);

    // checked_add_duration will not panic on overflow
    let mut maybe_t = Some(SystemTime::UNIX_EPOCH);
    let max_duration = Duration::from_secs(u64::MAX);
    // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`.
    for _ in 0..2 {
        maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
    }
    assert_eq!(maybe_t, None);

    // checked_add_duration calculates the right time and will work for another year
    let year = Duration::from_secs(60 * 60 * 24 * 365);
    assert_eq!(a + year, a.checked_add(year).unwrap());
}

#[test]
fn system_time_elapsed() {
    let a = SystemTime::now();
    drop(a.elapsed());
}

#[test]
fn since_epoch() {
    let ts = SystemTime::now();
    let a = ts.duration_since(UNIX_EPOCH + Duration::SECOND).unwrap();
    let b = ts.duration_since(UNIX_EPOCH).unwrap();
    assert!(b > a);
    assert_eq!(b - a, Duration::SECOND);

    let thirty_years = Duration::SECOND * 60 * 60 * 24 * 365 * 30;

    // Right now for CI this test is run in an emulator, and apparently the
    // aarch64 emulator's sense of time is that we're still living in the
    // 70s. This is also true for riscv (also qemu)
    //
    // Otherwise let's assume that we're all running computers later than
    // 2000.
    if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") {
        assert!(a > thirty_years);
    }

    // let's assume that we're all running computers earlier than 2090.
    // Should give us ~70 years to fix this!
    let hundred_twenty_years = thirty_years * 4;
    assert!(a < hundred_twenty_years);
}
<commit_msg>add benchmarks for 1, 2, 4, 8, 16 threads<commit_after>use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
use test::{black_box, Bencher};

macro_rules! assert_almost_eq {
    ($a:expr, $b:expr) => {{
        let (a, b) = ($a, $b);
        if a != b {
            let (a, b) = if a > b { (a, b) } else { (b, a) };
            assert!(a - Duration::from_micros(1) <= b, "{:?} is not almost equal to {:?}", a, b);
        }
    }};
}

#[test]
fn instant_monotonic() {
    let a = Instant::now();
    loop {
        let b = Instant::now();
        assert!(b >= a);
        if b > a {
            break;
        }
    }
}

#[test]
fn instant_monotonic_concurrent() -> crate::thread::Result<()> {
    let threads: Vec<_> = (0..8)
        .map(|_| {
            crate::thread::spawn(|| {
                let mut old = Instant::now();
                for _ in 0..5_000_000 {
                    let new = Instant::now();
                    assert!(new >= old);
                    old = new;
                }
            })
        })
        .collect();
    for t in threads {
        t.join()?;
    }
    Ok(())
}

#[test]
fn instant_elapsed() {
    let a = Instant::now();
    a.elapsed();
}

#[test]
fn instant_math() {
    let a = Instant::now();
    let b = Instant::now();
    println!("a: {:?}", a);
    println!("b: {:?}", b);
    let dur = b.duration_since(a);
    println!("dur: {:?}", dur);
    assert_almost_eq!(b - dur, a);
    assert_almost_eq!(a + dur, b);

    let second = Duration::SECOND;
    assert_almost_eq!(a - second + second, a);
    assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);

    // checked_add_duration will not panic on overflow
    let mut maybe_t = Some(Instant::now());
    let max_duration = Duration::from_secs(u64::MAX);
    // in case `Instant` can store `>= now + max_duration`.
    for _ in 0..2 {
        maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
    }
    assert_eq!(maybe_t, None);

    // checked_add_duration calculates the right time and will work for another year
    let year = Duration::from_secs(60 * 60 * 24 * 365);
    assert_eq!(a + year, a.checked_add(year).unwrap());
}

#[test]
fn instant_math_is_associative() {
    let now = Instant::now();
    let offset = Duration::from_millis(5);
    // Changing the order of instant math shouldn't change the results,
    // especially when the expression reduces to X + identity.
    assert_eq!((now + offset) - now, (now - now) + offset);
}

#[test]
#[should_panic]
fn instant_duration_since_panic() {
    let a = Instant::now();
    (a - Duration::SECOND).duration_since(a);
}

#[test]
fn instant_checked_duration_since_nopanic() {
    let now = Instant::now();
    let earlier = now - Duration::SECOND;
    let later = now + Duration::SECOND;
    assert_eq!(earlier.checked_duration_since(now), None);
    assert_eq!(later.checked_duration_since(now), Some(Duration::SECOND));
    assert_eq!(now.checked_duration_since(now), Some(Duration::ZERO));
}

#[test]
fn instant_saturating_duration_since_nopanic() {
    let a = Instant::now();
    let ret = (a - Duration::SECOND).saturating_duration_since(a);
    assert_eq!(ret, Duration::ZERO);
}

#[test]
fn system_time_math() {
    let a = SystemTime::now();
    let b = SystemTime::now();
    match b.duration_since(a) {
        Ok(Duration::ZERO) => {
            assert_almost_eq!(a, b);
        }
        Ok(dur) => {
            assert!(b > a);
            assert_almost_eq!(b - dur, a);
            assert_almost_eq!(a + dur, b);
        }
        Err(dur) => {
            let dur = dur.duration();
            assert!(a > b);
            assert_almost_eq!(b + dur, a);
            assert_almost_eq!(a - dur, b);
        }
    }

    let second = Duration::SECOND;
    assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
    assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second);

    assert_almost_eq!(a - second + second, a);
    assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);

    let one_second_from_epoch = UNIX_EPOCH + Duration::SECOND;
    let one_second_from_epoch2 =
        UNIX_EPOCH + Duration::from_millis(500) + Duration::from_millis(500);
    assert_eq!(one_second_from_epoch, one_second_from_epoch2);

    // checked_add_duration will not panic on overflow
    let mut maybe_t = Some(SystemTime::UNIX_EPOCH);
    let max_duration = Duration::from_secs(u64::MAX);
    // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`.
    for _ in 0..2 {
        maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
    }
    assert_eq!(maybe_t, None);

    // checked_add_duration calculates the right time and will work for another year
    let year = Duration::from_secs(60 * 60 * 24 * 365);
    assert_eq!(a + year, a.checked_add(year).unwrap());
}

#[test]
fn system_time_elapsed() {
    let a = SystemTime::now();
    drop(a.elapsed());
}

#[test]
fn since_epoch() {
    let ts = SystemTime::now();
    let a = ts.duration_since(UNIX_EPOCH + Duration::SECOND).unwrap();
    let b = ts.duration_since(UNIX_EPOCH).unwrap();
    assert!(b > a);
    assert_eq!(b - a, Duration::SECOND);

    let thirty_years = Duration::SECOND * 60 * 60 * 24 * 365 * 30;

    // Right now for CI this test is run in an emulator, and apparently the
    // aarch64 emulator's sense of time is that we're still living in the
    // 70s. This is also true for riscv (also qemu)
    //
    // Otherwise let's assume that we're all running computers later than
    // 2000.
    if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") {
        assert!(a > thirty_years);
    }

    // let's assume that we're all running computers earlier than 2090.
    // Should give us ~70 years to fix this!
    let hundred_twenty_years = thirty_years * 4;
    assert!(a < hundred_twenty_years);
}

macro_rules! bench_instant_threaded {
    ($bench_name:ident, $thread_count:expr) => {
        #[bench]
        fn $bench_name(b: &mut Bencher) -> crate::thread::Result<()> {
            use crate::sync::atomic::{AtomicBool, Ordering};
            use crate::sync::Arc;

            let running = Arc::new(AtomicBool::new(true));

            let threads: Vec<_> = (0..$thread_count)
                .map(|_| {
                    let flag = Arc::clone(&running);
                    crate::thread::spawn(move || {
                        while flag.load(Ordering::Relaxed) {
                            black_box(Instant::now());
                        }
                    })
                })
                .collect();

            b.iter(|| {
                let a = Instant::now();
                let b = Instant::now();
                assert!(b >= a);
            });

            running.store(false, Ordering::Relaxed);

            for t in threads {
                t.join()?;
            }
            Ok(())
        }
    };
}

bench_instant_threaded!(instant_contention_01_threads, 0);
bench_instant_threaded!(instant_contention_02_threads, 1);
bench_instant_threaded!(instant_contention_04_threads, 3);
bench_instant_threaded!(instant_contention_08_threads, 7);
bench_instant_threaded!(instant_contention_16_threads, 15);
<|endoftext|>


<commit_before>//! Printer for displaying crate as a graoh.

use petgraph::{
    graph::NodeIndex,
    visit::{IntoNodeReferences, NodeRef},
};
use ra_ap_hir as hir;
use ra_ap_ide::RootDatabase;

use crate::{
    format::{kind::FormattedKind, visibility::FormattedVisibility},
    graph::{Edge, Graph, Node, NodeKind},
    theme::{color_palette, colors, Rgb},
};

const INDENTATION: &str = "    ";

#[derive(Clone, Debug)]
pub struct Options {
    pub layout: String,
    pub full_paths: bool,
}

pub struct Printer<'a> {
    options: Options,
    member_krate: hir::Crate,
    db: &'a RootDatabase,
}

impl<'a> Printer<'a> {
    pub fn new(options: Options, member_krate: hir::Crate, db: &'a RootDatabase) -> Self {
        Self {
            options,
            member_krate,
            db,
        }
    }

    pub fn print(&self, graph: &Graph, start_node_idx: NodeIndex) -> Result<(), anyhow::Error> {
        let root_node = &graph[start_node_idx];
        let crate_name = root_node.name();
        let layout_name = &self.options.layout[..];

        println!("digraph {{");

        println!();

        indoc::printdoc!(
            r#"
            {i}graph [
            {i}    label="{label}",
            {i}    labelloc=t,

            {i}    pad=0.4,

            {i}    // Consider rendering the graph using a different layout algorithm, such as:
            {i}    // [dot, neato, twopi, circo, fdp, sfdp]
            {i}    layout={layout},
            {i}    overlap=false,
            {i}    splines="line",
            {i}    rankdir=LR,

            {i}    fontname="Helvetica",
            {i}    fontsize="36",
            {i}];
            "#,
            i = INDENTATION,
            label = crate_name,
            layout = layout_name,
        );

        println!();

        indoc::printdoc!(
            r#"
            {i}node [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}    shape="record",
            {i}    style="filled",
            {i}];
            "#,
            i = INDENTATION,
        );

        println!();

        indoc::printdoc!(
            r#"
            {i}edge [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}];
            "#,
            i = INDENTATION,
        );

        println!();

        self.print_nodes(graph, start_node_idx);

        println!();

        self.print_edges(graph);

        println!();

        println!("}}");

        Ok(())
    }

    fn print_nodes(&self, graph: &Graph, start_node_idx: NodeIndex) {
        for node_ref in graph.node_references() {
            let node: &Node = node_ref.weight();
            let node_idx: NodeIndex = node_ref.id();

            let id = node_idx.index();
            let kind = node.kind(self.db);

            let is_focused = node_idx == start_node_idx;

            let label = self.node_label(node);
            let attributes = self.node_attributes(node, is_focused);

            println!(
                r#"{i}{id} [label="{label}"{attributes}]; // "{kind}" node"#,
                i = INDENTATION,
                id = id,
                label = label,
                attributes = attributes,
                kind = kind,
            );
        }
    }

    fn print_edges(&self, graph: &Graph) {
        for edge_idx in graph.edge_indices() {
            let edge = &graph[edge_idx];
            let (source, target) = graph
                .edge_endpoints(edge_idx)
                .map(|(source, target)| (source.index(), target.index()))
                .unwrap();

            let kind = edge.kind();

            let label = self.edge_label(edge);
            let attributes = self.edge_attributes(edge);

            println!(
                r#"{i}{source} -> {target} [label="{label}"{attributes}]; // "{kind}" edge"#,
                i = INDENTATION,
                source = source,
                target = target,
                label = label,
                attributes = attributes,
                kind = kind,
            );
        }
    }

    fn node_label(&self, node: &Node) -> String {
        let header = self.node_header(node);
        let body = self.node_body(node);

        format!("{}|{}", header, body)
    }

    fn node_header(&self, node: &Node) -> String {
        let module_def = match node.hir {
            Some(module_def) => module_def,
            None => return "orphan module".to_owned(),
        };

        let is_external = node.krate != Some(self.member_krate);
        let node_kind = node.kind(self.db);

        match node_kind {
            NodeKind::Crate => {
                if is_external {
                    "extern crate".to_owned()
                } else {
                    "crate".to_owned()
                }
            }
            _ => {
                let visibility = if is_external {
                    "extern".to_owned()
                } else {
                    FormattedVisibility::new(module_def, self.db).to_string()
                };
                let kind = match node_kind {
                    NodeKind::Crate => FormattedKind::Crate,
                    _ => FormattedKind::new(module_def),
                };
                format!("{} {}", visibility, kind)
            }
        }
    }

    fn node_body(&self, node: &Node) -> String {
        let path = &node.path[..];

        // If we explicitly want full paths, return it unaltered:
        if self.options.full_paths {
            return path.to_owned();
        }

        // Otherwise try to drop the crate-name from the path:
        if let Some(index) = path.find("::") {
            // `index + 2` works here, since wee know ':' to be of single-byte width:
            path[(index + 2)..].to_owned()
        } else {
            path.to_owned()
        }
    }

    fn node_attributes(&self, node: &Node, is_focused: bool) -> String {
        let fill_color = match is_focused {
            true => self.node_highlight_color(node),
            false => self.node_color(node),
        };
        format!(r#", fillcolor="{}""#, fill_color)
    }

    fn node_color(&self, node: &Node) -> String {
        let colors = colors();
        let color_palette = color_palette();

        let is_external = node.krate != Some(self.member_krate);

        let rgb = if is_external {
            color_palette.blue
        } else {
            match node.hir {
                Some(module_def) => match FormattedVisibility::new(module_def, self.db) {
                    FormattedVisibility::Crate => colors.visibility.pub_crate,
                    FormattedVisibility::Module(_) => colors.visibility.pub_module,
                    FormattedVisibility::Private => colors.visibility.pub_private,
                    FormattedVisibility::Public => colors.visibility.pub_global,
                    FormattedVisibility::Super => colors.visibility.pub_super,
                },
                None => colors.orphan,
            }
        };

        self.hex_color(rgb)
    }

    fn node_highlight_color(&self, _node: &Node) -> String {
        let color_palette = color_palette();

        self.hex_color(color_palette.cyan)
    }

    fn edge_label(&self, edge: &Edge) -> String {
        match edge {
            Edge::UsesA => "uses".to_owned(),
            Edge::HasA => "has".to_owned(),
        }
    }

    fn edge_attributes(&self, edge: &Edge) -> String {
        match edge {
            Edge::UsesA => r#", color="gray", style="dashed""#.to_string(),
            Edge::HasA => r#", color="black", style="solid""#.to_string(),
        }
    }

    fn hex_color(&self, rgb: Rgb) -> String {
        let Rgb { r, g, b, .. } = rgb;
        format!("#{:02x}{:02x}{:02x}", r, g, b)
    }
}
<commit_msg>Replaced integer node/edge ids in dot graphs with fully qualified paths for easier manual processing / searching / editing of dot output<commit_after>//! Printer for displaying crate as a graoh.

use petgraph::{
    graph::NodeIndex,
    visit::{IntoNodeReferences, NodeRef},
};
use ra_ap_hir as hir;
use ra_ap_ide::RootDatabase;

use crate::{
    format::{kind::FormattedKind, visibility::FormattedVisibility},
    graph::{Edge, Graph, Node, NodeKind},
    theme::{color_palette, colors, Rgb},
};

const INDENTATION: &str = "    ";

#[derive(Clone, Debug)]
pub struct Options {
    pub layout: String,
    pub full_paths: bool,
}

pub struct Printer<'a> {
    options: Options,
    member_krate: hir::Crate,
    db: &'a RootDatabase,
}

impl<'a> Printer<'a> {
    pub fn new(options: Options, member_krate: hir::Crate, db: &'a RootDatabase) -> Self {
        Self {
            options,
            member_krate,
            db,
        }
    }

    pub fn print(&self, graph: &Graph, start_node_idx: NodeIndex) -> Result<(), anyhow::Error> {
        let root_node = &graph[start_node_idx];
        let crate_name = root_node.name();
        let layout_name = &self.options.layout[..];

        println!("digraph {{");

        println!();

        indoc::printdoc!(
            r#"
            {i}graph [
            {i}    label={label:?},
            {i}    labelloc=t,

            {i}    pad=0.4,

            {i}    // Consider rendering the graph using a different layout algorithm, such as:
            {i}    // [dot, neato, twopi, circo, fdp, sfdp]
            {i}    layout={layout},
            {i}    overlap=false,
            {i}    splines="line",
            {i}    rankdir=LR,

            {i}    fontname="Helvetica",
            {i}    fontsize="36",
            {i}];
            "#,
            i = INDENTATION,
            label = crate_name,
            layout = layout_name,
        );

        println!();

        indoc::printdoc!(
            r#"
            {i}node [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}    shape="record",
            {i}    style="filled",
            {i}];
            "#,
            i = INDENTATION,
        );

        println!();

        indoc::printdoc!(
            r#"
            {i}edge [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}];
            "#,
            i = INDENTATION,
        );

        println!();

        self.print_nodes(graph, start_node_idx);

        println!();

        self.print_edges(graph);

        println!();

        println!("}}");

        Ok(())
    }

    fn print_nodes(&self, graph: &Graph, start_node_idx: NodeIndex) {
        for node_ref in graph.node_references() {
            let node: &Node = node_ref.weight();
            let node_idx: NodeIndex = node_ref.id();

            let id = &node.path[..];
            let kind = node.kind(self.db);

            let is_focused = node_idx == start_node_idx;

            let label = self.node_label(node);
            let attributes = self.node_attributes(node, is_focused);

            println!(
                r#"{i}{id:?} [label={label:?}{attributes}]; // {kind:?} node"#,
                i = INDENTATION,
                id = id,
                label = label,
                attributes = attributes,
                kind = kind,
            );
        }
    }

    fn print_edges(&self, graph: &Graph) {
        for edge_idx in graph.edge_indices() {
            let edge = &graph[edge_idx];
            let (source_idx, target_idx) = graph.edge_endpoints(edge_idx).unwrap();

            let source_id = &graph[source_idx].path[..];
            let target_id = &graph[target_idx].path[..];

            let kind = edge.kind();

            let label = self.edge_label(edge);
            let attributes = self.edge_attributes(edge);

            println!(
                r#"{i}{source:?} -> {target:?} [label={label:?}{attributes}]; // {kind:?} edge"#,
                i = INDENTATION,
                source = source_id,
                target = target_id,
                label = label,
                attributes = attributes,
                kind = kind,
            );
        }
    }

    fn node_label(&self, node: &Node) -> String {
        let header = self.node_header(node);
        let body = self.node_body(node);

        format!("{}|{}", header, body)
    }

    fn node_header(&self, node: &Node) -> String {
        let module_def = match node.hir {
            Some(module_def) => module_def,
            None => return "orphan module".to_owned(),
        };

        let is_external = node.krate != Some(self.member_krate);
        let node_kind = node.kind(self.db);

        match node_kind {
            NodeKind::Crate => {
                if is_external {
                    "extern crate".to_owned()
                } else {
                    "crate".to_owned()
                }
            }
            _ => {
                let visibility = if is_external {
                    "extern".to_owned()
                } else {
                    FormattedVisibility::new(module_def, self.db).to_string()
                };
                let kind = match node_kind {
                    NodeKind::Crate => FormattedKind::Crate,
                    _ => FormattedKind::new(module_def),
                };
                format!("{} {}", visibility, kind)
            }
        }
    }

    fn node_body(&self, node: &Node) -> String {
        let path = &node.path[..];

        // If we explicitly want full paths, return it unaltered:
        if self.options.full_paths {
            return path.to_owned();
        }

        // Otherwise try to drop the crate-name from the path:
        if let Some(index) = path.find("::") {
            // `index + 2` works here, since wee know ':' to be of single-byte width:
            path[(index + 2)..].to_owned()
        } else {
            path.to_owned()
        }
    }

    fn node_attributes(&self, node: &Node, is_focused: bool) -> String {
        let fill_color = match is_focused {
            true => self.node_highlight_color(node),
            false => self.node_color(node),
        };
        format!(r#", fillcolor={:?}"#, fill_color)
    }

    fn node_color(&self, node: &Node) -> String {
        let colors = colors();
        let color_palette = color_palette();

        let is_external = node.krate != Some(self.member_krate);

        let rgb = if is_external {
            color_palette.blue
        } else {
            match node.hir {
                Some(module_def) => match FormattedVisibility::new(module_def, self.db) {
                    FormattedVisibility::Crate => colors.visibility.pub_crate,
                    FormattedVisibility::Module(_) => colors.visibility.pub_module,
                    FormattedVisibility::Private => colors.visibility.pub_private,
                    FormattedVisibility::Public => colors.visibility.pub_global,
                    FormattedVisibility::Super => colors.visibility.pub_super,
                },
                None => colors.orphan,
            }
        };

        self.hex_color(rgb)
    }

    fn node_highlight_color(&self, _node: &Node) -> String {
        let color_palette = color_palette();

        self.hex_color(color_palette.cyan)
    }

    fn edge_label(&self, edge: &Edge) -> String {
        match edge {
            Edge::UsesA => "uses".to_owned(),
            Edge::HasA => "has".to_owned(),
        }
    }

    fn edge_attributes(&self, edge: &Edge) -> String {
        match edge {
            Edge::UsesA => r#", color="gray", style="dashed""#.to_string(),
            Edge::HasA => r#", color="black", style="solid""#.to_string(),
        }
    }

    fn hex_color(&self, rgb: Rgb) -> String {
        let Rgb { r, g, b, .. } = rgb;
        format!("#{:02x}{:02x}{:02x}", r, g, b)
    }
}
<|endoftext|>


<commit_before><commit_msg>:pencil: use is_null instead of ptr compare<commit_after><|endoftext|>


<commit_before>//! Extensions for `Builder` structure required for item rendering.

use itertools::Itertools;
use test_utils::mark;

use crate::{item::Builder, CompletionContext};

pub(super) enum Params {
    Named(Vec<String>),
    Anonymous(usize),
}

impl Params {
    pub(super) fn len(&self) -> usize {
        match self {
            Params::Named(xs) => xs.len(),
            Params::Anonymous(len) => *len,
        }
    }

    pub(super) fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl Builder {
    pub(super) fn should_add_parems(&self, ctx: &CompletionContext) -> bool {
        if !ctx.config.add_call_parenthesis {
            return false;
        }
        if ctx.use_item_syntax.is_some() {
            mark::hit!(no_parens_in_use_item);
            return false;
        }
        if ctx.is_pattern_call {
            mark::hit!(dont_duplicate_pattern_parens);
            return false;
        }
        if ctx.is_call {
            return false;
        }

        // Don't add parentheses if the expected type is some function reference.
        if let Some(ty) = &ctx.expected_type {
            if ty.is_fn() {
                mark::hit!(no_call_parens_if_fn_ptr_needed);
                return false;
            }
        }

        // Nothing prevents us from adding parentheses
        true
    }

    pub(super) fn add_call_parens(
        mut self,
        ctx: &CompletionContext,
        name: String,
        params: Params,
    ) -> Builder {
        if !self.should_add_parems(ctx) {
            return self;
        }

        let cap = match ctx.config.snippet_cap {
            Some(it) => it,
            None => return self,
        };
        // If not an import, add parenthesis automatically.
        mark::hit!(inserts_parens_for_function_calls);

        let (snippet, label) = if params.is_empty() {
            (format!("{}()$0", name), format!("{}()", name))
        } else {
            self = self.trigger_call_info();
            let snippet = match (ctx.config.add_call_argument_snippets, params) {
                (true, Params::Named(params)) => {
                    let function_params_snippet =
                        params.iter().enumerate().format_with(", ", |(index, param_name), f| {
                            f(&format_args!("${{{}:{}}}", index + 1, param_name))
                        });
                    format!("{}({})$0", name, function_params_snippet)
                }
                _ => {
                    mark::hit!(suppress_arg_snippets);
                    format!("{}($0)", name)
                }
            };

            (snippet, format!("{}(…)", name))
        };
        self.lookup_by(name).label(label).insert_snippet(cap, snippet)
    }
}
<commit_msg>Fix typo<commit_after>//! Extensions for `Builder` structure required for item rendering.

use itertools::Itertools;
use test_utils::mark;

use crate::{item::Builder, CompletionContext};

pub(super) enum Params {
    Named(Vec<String>),
    Anonymous(usize),
}

impl Params {
    pub(super) fn len(&self) -> usize {
        match self {
            Params::Named(xs) => xs.len(),
            Params::Anonymous(len) => *len,
        }
    }

    pub(super) fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl Builder {
    fn should_add_parens(&self, ctx: &CompletionContext) -> bool {
        if !ctx.config.add_call_parenthesis {
            return false;
        }
        if ctx.use_item_syntax.is_some() {
            mark::hit!(no_parens_in_use_item);
            return false;
        }
        if ctx.is_pattern_call {
            mark::hit!(dont_duplicate_pattern_parens);
            return false;
        }
        if ctx.is_call {
            return false;
        }

        // Don't add parentheses if the expected type is some function reference.
        if let Some(ty) = &ctx.expected_type {
            if ty.is_fn() {
                mark::hit!(no_call_parens_if_fn_ptr_needed);
                return false;
            }
        }

        // Nothing prevents us from adding parentheses
        true
    }

    pub(super) fn add_call_parens(
        mut self,
        ctx: &CompletionContext,
        name: String,
        params: Params,
    ) -> Builder {
        if !self.should_add_parens(ctx) {
            return self;
        }

        let cap = match ctx.config.snippet_cap {
            Some(it) => it,
            None => return self,
        };
        // If not an import, add parenthesis automatically.
        mark::hit!(inserts_parens_for_function_calls);

        let (snippet, label) = if params.is_empty() {
            (format!("{}()$0", name), format!("{}()", name))
        } else {
            self = self.trigger_call_info();
            let snippet = match (ctx.config.add_call_argument_snippets, params) {
                (true, Params::Named(params)) => {
                    let function_params_snippet =
                        params.iter().enumerate().format_with(", ", |(index, param_name), f| {
                            f(&format_args!("${{{}:{}}}", index + 1, param_name))
                        });
                    format!("{}({})$0", name, function_params_snippet)
                }
                _ => {
                    mark::hit!(suppress_arg_snippets);
                    format!("{}($0)", name)
                }
            };

            (snippet, format!("{}(…)", name))
        };
        self.lookup_by(name).label(label).insert_snippet(cap, snippet)
    }
}
<|endoftext|>


<commit_before>//! See [`CargoWorkspace`].

use std::path::PathBuf;
use std::{convert::TryInto, ops, process::Command, sync::Arc};

use anyhow::{Context, Result};
use base_db::Edition;
use cargo_metadata::{CargoOpt, MetadataCommand};
use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use serde::Deserialize;
use serde_json::from_value;

use crate::{build_data::BuildDataConfig, utf8_stdout};

/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
///
/// We use absolute paths here, `cargo metadata` guarantees to always produce
/// abs paths.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct CargoWorkspace {
    packages: Arena<PackageData>,
    targets: Arena<TargetData>,
    workspace_root: AbsPathBuf,
    build_data_config: BuildDataConfig,
}

impl ops::Index<Package> for CargoWorkspace {
    type Output = PackageData;
    fn index(&self, index: Package) -> &PackageData {
        &self.packages[index]
    }
}

impl ops::Index<Target> for CargoWorkspace {
    type Output = TargetData;
    fn index(&self, index: Target) -> &TargetData {
        &self.targets[index]
    }
}

/// Describes how to set the rustc source directory.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RustcSource {
    /// Explicit path for the rustc source directory.
    Path(AbsPathBuf),
    /// Try to automatically detect where the rustc source directory is.
    Discover,
}

#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct CargoConfig {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,

    /// rustc target
    pub target: Option<String>,

    /// Don't load sysroot crates (`std`, `core` & friends). Might be useful
    /// when debugging isolated issues.
    pub no_sysroot: bool,

    /// rustc private crate source
    pub rustc_source: Option<RustcSource>,
}

pub type Package = Idx<PackageData>;

pub type Target = Idx<TargetData>;

/// Information associated with a cargo crate
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PackageData {
    /// Version given in the `Cargo.toml`
    pub version: String,
    /// Name as given in the `Cargo.toml`
    pub name: String,
    /// Path containing the `Cargo.toml`
    pub manifest: AbsPathBuf,
    /// Targets provided by the crate (lib, bin, example, test, ...)
    pub targets: Vec<Target>,
    /// Is this package a member of the current workspace
    pub is_member: bool,
    /// List of packages this package depends on
    pub dependencies: Vec<PackageDependency>,
    /// Rust edition for this package
    pub edition: Edition,
    /// Features provided by the crate, mapped to the features required by that feature.
    pub features: FxHashMap<String, Vec<String>>,
    /// List of features enabled on this package
    pub active_features: Vec<String>,
    // String representation of package id
    pub id: String,
    // The contents of [package.metadata.rust-analyzer]
    pub metadata: RustAnalyzerPackageMetaData,
}

#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
pub struct RustAnalyzerPackageMetaData {
    pub rustc_private: bool,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
    pub kind: DepKind,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum DepKind {
    /// Available to the library, binary, and dev targets in the package (but not the build script).
    Normal,
    /// Available only to test and bench targets (and the library target, when built with `cfg(test)`).
    Dev,
    /// Available only to the build script target.
    Build,
}

impl DepKind {
    fn new(list: &[cargo_metadata::DepKindInfo]) -> Self {
        for info in list {
            match info.kind {
                cargo_metadata::DependencyKind::Normal => return Self::Normal,
                cargo_metadata::DependencyKind::Development => return Self::Dev,
                cargo_metadata::DependencyKind::Build => return Self::Build,
                cargo_metadata::DependencyKind::Unknown => continue,
            }
        }

        Self::Normal
    }
}

/// Information associated with a package's target
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TargetData {
    /// Package that provided this target
    pub package: Package,
    /// Name as given in the `Cargo.toml` or generated from the file name
    pub name: String,
    /// Path to the main source file of the target
    pub root: AbsPathBuf,
    /// Kind of target
    pub kind: TargetKind,
    /// Is this target a proc-macro
    pub is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    BuildScript,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "custom-build" => TargetKind::BuildScript,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl PackageData {
    pub fn root(&self) -> &AbsPath {
        self.manifest.parent().unwrap()
    }
}

#[derive(Deserialize, Default)]
// Deserialise helper for the cargo metadata
struct PackageMetadata {
    #[serde(rename = "rust-analyzer")]
    rust_analyzer: Option<RustAnalyzerPackageMetaData>,
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &AbsPath,
        config: &CargoConfig,
        progress: &dyn Fn(String),
    ) -> Result<CargoWorkspace> {
        let mut meta = MetadataCommand::new();
        meta.cargo_path(toolchain::cargo());
        meta.manifest_path(cargo_toml.to_path_buf());
        if config.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else {
            if config.no_default_features {
                // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
                // https://github.com/oli-obk/cargo_metadata/issues/79
                meta.features(CargoOpt::NoDefaultFeatures);
            }
            if !config.features.is_empty() {
                meta.features(CargoOpt::SomeFeatures(config.features.clone()));
            }
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent.to_path_buf());
        }
        let target = if let Some(target) = &config.target {
            Some(target.clone())
        } else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) {
            stdout
        } else {
            rustc_discover_host_triple(cargo_toml)
        };
        if let Some(target) = target {
            meta.other_options(vec![String::from("--filter-platform"), target]);
        }

        // FIXME: Currently MetadataCommand is not based on parse_stream,
        // So we just report it as a whole
        progress("metadata".to_string());
        let mut meta = meta.exec().with_context(|| {
            let cwd: Option<AbsPathBuf> =
                std::env::current_dir().ok().and_then(|p| p.try_into().ok());

            let workdir = cargo_toml
                .parent()
                .map(|p| p.to_path_buf())
                .or(cwd)
                .map(|dir| dir.to_string_lossy().to_string())
                .unwrap_or_else(|| "<failed to get path>".into());

            format!(
                "Failed to run `cargo metadata --manifest-path {}` in `{}`",
                cargo_toml.display(),
                workdir
            )
        })?;

        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
        for meta_pkg in &meta.packages {
            let cargo_metadata::Package {
                id, edition, name, manifest_path, version, metadata, ..
            } = meta_pkg;
            let meta = from_value::<PackageMetadata>(metadata.clone()).unwrap_or_default();
            let is_member = ws_members.contains(&id);
            let edition = edition
                .parse::<Edition>()
                .with_context(|| format!("Failed to parse edition {}", edition))?;

            let pkg = packages.alloc(PackageData {
                id: id.repr.clone(),
                name: name.clone(),
                version: version.to_string(),
                manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)),
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: meta_pkg.features.clone().into_iter().collect(),
                active_features: Vec::new(),
                metadata: meta.rust_analyzer.unwrap_or_default(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in &meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    package: pkg,
                    name: meta_tgt.name.clone(),
                    root: AbsPathBuf::assert(PathBuf::from(&meta_tgt.src_path)),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for mut node in resolve.nodes {
            let source = match pkg_by_id.get(&node.id) {
                Some(&src) => src,
                // FIXME: replace this and a similar branch below with `.unwrap`, once
                // https://github.com/rust-lang/cargo/issues/7841
                // is fixed and hits stable (around 1.43-is probably?).
                None => {
                    log::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
                    continue;
                }
            };
            node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
            for dep_node in node.deps {
                let pkg = match pkg_by_id.get(&dep_node.pkg) {
                    Some(&pkg) => pkg,
                    None => {
                        log::error!(
                            "Dep node id do not match in cargo metadata, ignoring {}",
                            dep_node.pkg
                        );
                        continue;
                    }
                };
                let dep = PackageDependency {
                    name: dep_node.name,
                    pkg,
                    kind: DepKind::new(&dep_node.dep_kinds),
                };
                packages[source].dependencies.push(dep);
            }
            packages[source].active_features.extend(node.features);
        }

        let workspace_root =
            AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string()));
        let build_data_config = BuildDataConfig::new(
            cargo_toml.to_path_buf(),
            config.clone(),
            Arc::new(meta.packages.clone()),
        );

        Ok(CargoWorkspace { packages, targets, workspace_root, build_data_config })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
        self.packages()
            .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
            .next()
            .copied()
    }

    pub fn workspace_root(&self) -> &AbsPath {
        &self.workspace_root
    }

    pub fn package_flag(&self, package: &PackageData) -> String {
        if self.is_unique(&*package.name) {
            package.name.clone()
        } else {
            format!("{}:{}", package.name, package.version)
        }
    }

    pub(crate) fn build_data_config(&self) -> &BuildDataConfig {
        &self.build_data_config
    }

    fn is_unique(&self, name: &str) -> bool {
        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
    }
}

fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> {
    let mut rustc = Command::new(toolchain::rustc());
    rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
    log::debug!("Discovering host platform by {:?}", rustc);
    match utf8_stdout(rustc) {
        Ok(stdout) => {
            let field = "host: ";
            let target = stdout.lines().find_map(|l| l.strip_prefix(field));
            if let Some(target) = target {
                Some(target.to_string())
            } else {
                // If we fail to resolve the host platform, it's not the end of the world.
                log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
                None
            }
        }
        Err(e) => {
            log::warn!("Failed to discover host platform: {}", e);
            None
        }
    }
}

fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option<String> {
    let mut cargo_config = Command::new(toolchain::cargo());
    cargo_config
        .current_dir(cargo_toml.parent().unwrap())
        .args(&["-Z", "unstable-options", "config", "get", "build.target"])
        .env("RUSTC_BOOTSTRAP", "1");
    // if successful we receive `build.target = "target-triple"`
    log::debug!("Discovering cargo config target by {:?}", cargo_config);
    match utf8_stdout(cargo_config) {
        Ok(stdout) => stdout
            .strip_prefix("build.target = \"")
            .and_then(|stdout| stdout.strip_suffix('"'))
            .map(ToOwned::to_owned),
        Err(_) => None,
    }
}
<commit_msg>Duplicate dependencies that have multiple DepKinds<commit_after>//! See [`CargoWorkspace`].

use std::path::PathBuf;
use std::{convert::TryInto, ops, process::Command, sync::Arc};

use anyhow::{Context, Result};
use base_db::Edition;
use cargo_metadata::{CargoOpt, MetadataCommand};
use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use serde::Deserialize;
use serde_json::from_value;

use crate::{build_data::BuildDataConfig, utf8_stdout};

/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
///
/// We use absolute paths here, `cargo metadata` guarantees to always produce
/// abs paths.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct CargoWorkspace {
    packages: Arena<PackageData>,
    targets: Arena<TargetData>,
    workspace_root: AbsPathBuf,
    build_data_config: BuildDataConfig,
}

impl ops::Index<Package> for CargoWorkspace {
    type Output = PackageData;
    fn index(&self, index: Package) -> &PackageData {
        &self.packages[index]
    }
}

impl ops::Index<Target> for CargoWorkspace {
    type Output = TargetData;
    fn index(&self, index: Target) -> &TargetData {
        &self.targets[index]
    }
}

/// Describes how to set the rustc source directory.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RustcSource {
    /// Explicit path for the rustc source directory.
    Path(AbsPathBuf),
    /// Try to automatically detect where the rustc source directory is.
    Discover,
}

#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct CargoConfig {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,

    /// rustc target
    pub target: Option<String>,

    /// Don't load sysroot crates (`std`, `core` & friends). Might be useful
    /// when debugging isolated issues.
    pub no_sysroot: bool,

    /// rustc private crate source
    pub rustc_source: Option<RustcSource>,
}

pub type Package = Idx<PackageData>;

pub type Target = Idx<TargetData>;

/// Information associated with a cargo crate
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PackageData {
    /// Version given in the `Cargo.toml`
    pub version: String,
    /// Name as given in the `Cargo.toml`
    pub name: String,
    /// Path containing the `Cargo.toml`
    pub manifest: AbsPathBuf,
    /// Targets provided by the crate (lib, bin, example, test, ...)
    pub targets: Vec<Target>,
    /// Is this package a member of the current workspace
    pub is_member: bool,
    /// List of packages this package depends on
    pub dependencies: Vec<PackageDependency>,
    /// Rust edition for this package
    pub edition: Edition,
    /// Features provided by the crate, mapped to the features required by that feature.
    pub features: FxHashMap<String, Vec<String>>,
    /// List of features enabled on this package
    pub active_features: Vec<String>,
    // String representation of package id
    pub id: String,
    // The contents of [package.metadata.rust-analyzer]
    pub metadata: RustAnalyzerPackageMetaData,
}

#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
pub struct RustAnalyzerPackageMetaData {
    pub rustc_private: bool,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
    pub kind: DepKind,
}

#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub enum DepKind {
    /// Available to the library, binary, and dev targets in the package (but not the build script).
    Normal,
    /// Available only to test and bench targets (and the library target, when built with `cfg(test)`).
    Dev,
    /// Available only to the build script target.
    Build,
}

impl DepKind {
    fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> + '_ {
        let mut dep_kinds = Vec::new();
        if list.is_empty() {
            dep_kinds.push(Self::Normal);
        }
        for info in list {
            let kind = match info.kind {
                cargo_metadata::DependencyKind::Normal => Self::Normal,
                cargo_metadata::DependencyKind::Development => Self::Dev,
                cargo_metadata::DependencyKind::Build => Self::Build,
                cargo_metadata::DependencyKind::Unknown => continue,
            };
            dep_kinds.push(kind);
        }
        dep_kinds.sort_unstable();
        dep_kinds.dedup();
        dep_kinds.into_iter()
    }
}

/// Information associated with a package's target
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TargetData {
    /// Package that provided this target
    pub package: Package,
    /// Name as given in the `Cargo.toml` or generated from the file name
    pub name: String,
    /// Path to the main source file of the target
    pub root: AbsPathBuf,
    /// Kind of target
    pub kind: TargetKind,
    /// Is this target a proc-macro
    pub is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    BuildScript,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "custom-build" => TargetKind::BuildScript,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl PackageData {
    pub fn root(&self) -> &AbsPath {
        self.manifest.parent().unwrap()
    }
}

#[derive(Deserialize, Default)]
// Deserialise helper for the cargo metadata
struct PackageMetadata {
    #[serde(rename = "rust-analyzer")]
    rust_analyzer: Option<RustAnalyzerPackageMetaData>,
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &AbsPath,
        config: &CargoConfig,
        progress: &dyn Fn(String),
    ) -> Result<CargoWorkspace> {
        let mut meta = MetadataCommand::new();
        meta.cargo_path(toolchain::cargo());
        meta.manifest_path(cargo_toml.to_path_buf());
        if config.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else {
            if config.no_default_features {
                // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
                // https://github.com/oli-obk/cargo_metadata/issues/79
                meta.features(CargoOpt::NoDefaultFeatures);
            }
            if !config.features.is_empty() {
                meta.features(CargoOpt::SomeFeatures(config.features.clone()));
            }
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent.to_path_buf());
        }
        let target = if let Some(target) = &config.target {
            Some(target.clone())
        } else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) {
            stdout
        } else {
            rustc_discover_host_triple(cargo_toml)
        };
        if let Some(target) = target {
            meta.other_options(vec![String::from("--filter-platform"), target]);
        }

        // FIXME: Currently MetadataCommand is not based on parse_stream,
        // So we just report it as a whole
        progress("metadata".to_string());
        let mut meta = meta.exec().with_context(|| {
            let cwd: Option<AbsPathBuf> =
                std::env::current_dir().ok().and_then(|p| p.try_into().ok());

            let workdir = cargo_toml
                .parent()
                .map(|p| p.to_path_buf())
                .or(cwd)
                .map(|dir| dir.to_string_lossy().to_string())
                .unwrap_or_else(|| "<failed to get path>".into());

            format!(
                "Failed to run `cargo metadata --manifest-path {}` in `{}`",
                cargo_toml.display(),
                workdir
            )
        })?;

        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
        for meta_pkg in &meta.packages {
            let cargo_metadata::Package {
                id, edition, name, manifest_path, version, metadata, ..
            } = meta_pkg;
            let meta = from_value::<PackageMetadata>(metadata.clone()).unwrap_or_default();
            let is_member = ws_members.contains(&id);
            let edition = edition
                .parse::<Edition>()
                .with_context(|| format!("Failed to parse edition {}", edition))?;

            let pkg = packages.alloc(PackageData {
                id: id.repr.clone(),
                name: name.clone(),
                version: version.to_string(),
                manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)),
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: meta_pkg.features.clone().into_iter().collect(),
                active_features: Vec::new(),
                metadata: meta.rust_analyzer.unwrap_or_default(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in &meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    package: pkg,
                    name: meta_tgt.name.clone(),
                    root: AbsPathBuf::assert(PathBuf::from(&meta_tgt.src_path)),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for mut node in resolve.nodes {
            let source = match pkg_by_id.get(&node.id) {
                Some(&src) => src,
                // FIXME: replace this and a similar branch below with `.unwrap`, once
                // https://github.com/rust-lang/cargo/issues/7841
                // is fixed and hits stable (around 1.43-is probably?).
                None => {
                    log::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
                    continue;
                }
            };
            node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
            for (dep_node, kind) in node
                .deps
                .iter()
                .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind)))
            {
                let pkg = match pkg_by_id.get(&dep_node.pkg) {
                    Some(&pkg) => pkg,
                    None => {
                        log::error!(
                            "Dep node id do not match in cargo metadata, ignoring {}",
                            dep_node.pkg
                        );
                        continue;
                    }
                };
                let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind };
                packages[source].dependencies.push(dep);
            }
            packages[source].active_features.extend(node.features);
        }

        let workspace_root =
            AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string()));
        let build_data_config = BuildDataConfig::new(
            cargo_toml.to_path_buf(),
            config.clone(),
            Arc::new(meta.packages.clone()),
        );

        Ok(CargoWorkspace { packages, targets, workspace_root, build_data_config })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
        self.packages()
            .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
            .next()
            .copied()
    }

    pub fn workspace_root(&self) -> &AbsPath {
        &self.workspace_root
    }

    pub fn package_flag(&self, package: &PackageData) -> String {
        if self.is_unique(&*package.name) {
            package.name.clone()
        } else {
            format!("{}:{}", package.name, package.version)
        }
    }

    pub(crate) fn build_data_config(&self) -> &BuildDataConfig {
        &self.build_data_config
    }

    fn is_unique(&self, name: &str) -> bool {
        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
    }
}

fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> {
    let mut rustc = Command::new(toolchain::rustc());
    rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
    log::debug!("Discovering host platform by {:?}", rustc);
    match utf8_stdout(rustc) {
        Ok(stdout) => {
            let field = "host: ";
            let target = stdout.lines().find_map(|l| l.strip_prefix(field));
            if let Some(target) = target {
                Some(target.to_string())
            } else {
                // If we fail to resolve the host platform, it's not the end of the world.
                log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
                None
            }
        }
        Err(e) => {
            log::warn!("Failed to discover host platform: {}", e);
            None
        }
    }
}

fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option<String> {
    let mut cargo_config = Command::new(toolchain::cargo());
    cargo_config
        .current_dir(cargo_toml.parent().unwrap())
        .args(&["-Z", "unstable-options", "config", "get", "build.target"])
        .env("RUSTC_BOOTSTRAP", "1");
    // if successful we receive `build.target = "target-triple"`
    log::debug!("Discovering cargo config target by {:?}", cargo_config);
    match utf8_stdout(cargo_config) {
        Ok(stdout) => stdout
            .strip_prefix("build.target = \"")
            .and_then(|stdout| stdout.strip_suffix('"'))
            .map(ToOwned::to_owned),
        Err(_) => None,
    }
}
<|endoftext|>


<commit_before>use std;
use std::fs::File;
use std::path::Path;
use std::hash::{Hash, Hasher};
use std::collections::{HashMap, HashSet};

use serde_json;

use feed;
use errors::*;

fn get_hash<T: Hash>(t: T) -> u64 {
    let mut hasher = std::collections::hash_map::DefaultHasher::default();
    t.hash(&mut hasher);
    hasher.finish()
}

type FeedID = u64;
type SubscriberID = i64;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Feed {
    pub link: String,
    pub title: String,
    pub error_count: u32,
    pub subscribers: HashSet<SubscriberID>,
    hash_list: HashSet<u64>,
}

#[derive(Debug)]
pub struct Database {
    path: String,
    feeds: HashMap<FeedID, Feed>,
    subscribers: HashMap<SubscriberID, HashSet<FeedID>>,
}

fn gen_item_hash(item: &feed::Item) -> u64 {
    item.id
        .as_ref()
        .map(|id| get_hash(&id))
        .unwrap_or_else(|| {
            let title = item.title.as_ref().map(|s| s.as_str()).unwrap_or_default();
            let link = item.link.as_ref().map(|s| s.as_str()).unwrap_or_default();
            get_hash(format!("{}{}", title, link))
        })
}

impl Database {
    pub fn create(path: &str) -> Result<Database> {
        let feeds: HashMap<FeedID, Feed> = HashMap::new();
        let subscribers: HashMap<SubscriberID, HashSet<FeedID>> = HashMap::new();
        let mut result = Database {
            path: path.to_owned(),
            feeds: feeds,
            subscribers: subscribers,
        };

        result.save()?;

        Ok(result)
    }

    pub fn open(path: &str) -> Result<Database> {
        let p = Path::new(path);
        if p.exists() {
            let f = File::open(path).chain_err(|| ErrorKind::DatabaseOpen(path.to_owned()))?;
            let feeds_list: Vec<Feed> =
                serde_json::from_reader(&f).chain_err(|| ErrorKind::DatabaseFormat)?;

            let mut feeds: HashMap<FeedID, Feed> = HashMap::with_capacity(feeds_list.len());
            let mut subscribers: HashMap<SubscriberID, HashSet<FeedID>> = HashMap::new();

            for feed in feeds_list {
                let feed_id = get_hash(&feed.link);
                for subscriber in &feed.subscribers {
                    let subscribed_feeds = subscribers.entry(subscriber.to_owned())
                        .or_insert_with(|| HashSet::new());
                    subscribed_feeds.insert(feed_id);
                }
                feeds.insert(feed_id, feed);
            }

            Ok(Database {
                path: path.to_owned(),
                feeds: feeds,
                subscribers: subscribers,
            })
        } else {
            Database::create(path)
        }
    }

    pub fn get_all_feeds(&self) -> Vec<Feed> {
        self.feeds.iter().map(|(_, v)| v.clone()).collect()
    }

    pub fn get_subscribed_feeds(&self, subscriber: SubscriberID) -> Option<Vec<&Feed>> {
        self.subscribers.get(&subscriber).map(|feeds| {
            feeds.iter()
                .map(|feed_id| &self.feeds[feed_id])
                .collect()
        })
    }

    pub fn inc_error_count(&mut self, rss_link: &str) -> u32 {
        let feed_id = get_hash(rss_link);
        self.feeds
            .get_mut(&feed_id)
            .map(|feed| {
                feed.error_count += 1;
                feed.error_count
            })
            .unwrap_or_default()
    }

    pub fn is_subscribed(&self, subscriber: SubscriberID, rss_link: &str) -> bool {
        self.subscribers
            .get(&subscriber)
            .map(|feeds| feeds.contains(&get_hash(rss_link)))
            .unwrap_or(false)
    }

    pub fn subscribe(&mut self,
                     subscriber: SubscriberID,
                     rss_link: &str,
                     rss: &feed::RSS)
                     -> Result<()> {
        let feed_id = get_hash(rss_link);
        {
            let subscribed_feeds =
                self.subscribers.entry(subscriber).or_insert_with(|| HashSet::new());
            if !subscribed_feeds.insert(feed_id) {
                return Err(ErrorKind::AlreadySubscribed.into());
            }
        }
        {
            let feed = self.feeds.entry(feed_id).or_insert_with(|| {
                Feed {
                    link: rss_link.to_owned(),
                    title: rss.title.to_owned(),
                    error_count: 0,
                    hash_list: rss.items.iter().map(gen_item_hash).collect(),
                    subscribers: HashSet::new(),
                }
            });
            feed.subscribers.insert(subscriber);
        }
        self.save()
    }

    pub fn unsubscribe(&mut self, subscriber: SubscriberID, rss_link: &str) -> Result<Feed> {
        let feed_id = get_hash(rss_link);

        {
            let mut clear_subscriber = false;
            self.subscribers
                .get_mut(&subscriber)
                .map(|subscribed_feeds| if !subscribed_feeds.remove(&feed_id) {
                    Err::<(), Error>(ErrorKind::NotSubscribed.into())
                } else {
                    clear_subscriber = subscribed_feeds.len() == 0;
                    Ok(())
                })
                .unwrap_or(Err(ErrorKind::NotSubscribed.into()))?;
            if clear_subscriber {
                self.subscribers.remove(&subscriber);
            }
        }
        let result;
        {
            let mut clear_feed = false;
            result = self.feeds
                .get_mut(&feed_id)
                .map(|feed| if !feed.subscribers.remove(&subscriber) {
                    Err::<Feed, Error>(ErrorKind::NotSubscribed.into())
                } else {
                    clear_feed = feed.subscribers.len() == 0;
                    Ok(feed.clone())
                })
                .unwrap_or(Err(ErrorKind::NotSubscribed.into()))?;
            if clear_feed {
                self.feeds.remove(&feed_id);
            }
        }
        self.save()?;
        Ok(result)
    }

    pub fn update<'a>(&mut self, rss_link: &str, items: Vec<feed::Item>) -> Vec<feed::Item> {
        let feed_id = get_hash(rss_link);
        let mut result = Vec::new();
        let mut new_hash_list = HashSet::new();
        let items_len = items.len();
        for item in items {
            let hash = gen_item_hash(&item);
            new_hash_list.insert(hash);
            if !self.feeds[&feed_id].hash_list.contains(&hash) {
                result.push(item);
            }
        }
        if !result.is_empty() {
            let max_size = items_len * 2;
            let feed = self.feeds.get_mut(&feed_id).unwrap();
            for old_hash in &feed.hash_list {
                new_hash_list.insert(*old_hash);
                if new_hash_list.len() >= max_size {
                    break;
                }
            }
            feed.hash_list = new_hash_list;
        }
        self.save().unwrap_or_default();
        result
    }

    pub fn update_title(&mut self, rss_link: &str, new_title: &str) {
        let feed_id = get_hash(rss_link);
        self.feeds.get_mut(&feed_id).unwrap().title = new_title.to_owned();
        self.save().unwrap_or_default();
    }

    fn save(&mut self) -> Result<()> {
        let feeds_list: Vec<&Feed> = self.feeds.iter().map(|(_id, feed)| feed).collect();
        let mut file =
            File::create(&self.path).chain_err(|| ErrorKind::DatabaseSave(self.path.to_owned()))?;
        serde_json::to_writer(&mut file, &feeds_list)
            .chain_err(|| ErrorKind::DatabaseSave(self.path.to_owned()))
    }
}
<commit_msg>reset error_count when fetch successful<commit_after>use std;
use std::fs::File;
use std::path::Path;
use std::hash::{Hash, Hasher};
use std::collections::{HashMap, HashSet};

use serde_json;

use feed;
use errors::*;

fn get_hash<T: Hash>(t: T) -> u64 {
    let mut hasher = std::collections::hash_map::DefaultHasher::default();
    t.hash(&mut hasher);
    hasher.finish()
}

type FeedID = u64;
type SubscriberID = i64;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Feed {
    pub link: String,
    pub title: String,
    pub error_count: u32,
    pub subscribers: HashSet<SubscriberID>,
    hash_list: HashSet<u64>,
}

#[derive(Debug)]
pub struct Database {
    path: String,
    feeds: HashMap<FeedID, Feed>,
    subscribers: HashMap<SubscriberID, HashSet<FeedID>>,
}

fn gen_item_hash(item: &feed::Item) -> u64 {
    item.id
        .as_ref()
        .map(|id| get_hash(&id))
        .unwrap_or_else(|| {
            let title = item.title.as_ref().map(|s| s.as_str()).unwrap_or_default();
            let link = item.link.as_ref().map(|s| s.as_str()).unwrap_or_default();
            get_hash(format!("{}{}", title, link))
        })
}

impl Database {
    pub fn create(path: &str) -> Result<Database> {
        let feeds: HashMap<FeedID, Feed> = HashMap::new();
        let subscribers: HashMap<SubscriberID, HashSet<FeedID>> = HashMap::new();
        let mut result = Database {
            path: path.to_owned(),
            feeds: feeds,
            subscribers: subscribers,
        };

        result.save()?;

        Ok(result)
    }

    pub fn open(path: &str) -> Result<Database> {
        let p = Path::new(path);
        if p.exists() {
            let f = File::open(path).chain_err(|| ErrorKind::DatabaseOpen(path.to_owned()))?;
            let feeds_list: Vec<Feed> =
                serde_json::from_reader(&f).chain_err(|| ErrorKind::DatabaseFormat)?;

            let mut feeds: HashMap<FeedID, Feed> = HashMap::with_capacity(feeds_list.len());
            let mut subscribers: HashMap<SubscriberID, HashSet<FeedID>> = HashMap::new();

            for feed in feeds_list {
                let feed_id = get_hash(&feed.link);
                for subscriber in &feed.subscribers {
                    let subscribed_feeds = subscribers.entry(subscriber.to_owned())
                        .or_insert_with(|| HashSet::new());
                    subscribed_feeds.insert(feed_id);
                }
                feeds.insert(feed_id, feed);
            }

            Ok(Database {
                path: path.to_owned(),
                feeds: feeds,
                subscribers: subscribers,
            })
        } else {
            Database::create(path)
        }
    }

    pub fn get_all_feeds(&self) -> Vec<Feed> {
        self.feeds.iter().map(|(_, v)| v.clone()).collect()
    }

    pub fn get_subscribed_feeds(&self, subscriber: SubscriberID) -> Option<Vec<&Feed>> {
        self.subscribers.get(&subscriber).map(|feeds| {
            feeds.iter()
                .map(|feed_id| &self.feeds[feed_id])
                .collect()
        })
    }

    pub fn inc_error_count(&mut self, rss_link: &str) -> u32 {
        let feed_id = get_hash(rss_link);
        self.feeds
            .get_mut(&feed_id)
            .map(|feed| {
                feed.error_count += 1;
                feed.error_count
            })
            .unwrap_or_default()
    }

    pub fn is_subscribed(&self, subscriber: SubscriberID, rss_link: &str) -> bool {
        self.subscribers
            .get(&subscriber)
            .map(|feeds| feeds.contains(&get_hash(rss_link)))
            .unwrap_or(false)
    }

    pub fn subscribe(&mut self,
                     subscriber: SubscriberID,
                     rss_link: &str,
                     rss: &feed::RSS)
                     -> Result<()> {
        let feed_id = get_hash(rss_link);
        {
            let subscribed_feeds =
                self.subscribers.entry(subscriber).or_insert_with(|| HashSet::new());
            if !subscribed_feeds.insert(feed_id) {
                return Err(ErrorKind::AlreadySubscribed.into());
            }
        }
        {
            let feed = self.feeds.entry(feed_id).or_insert_with(|| {
                Feed {
                    link: rss_link.to_owned(),
                    title: rss.title.to_owned(),
                    error_count: 0,
                    hash_list: rss.items.iter().map(gen_item_hash).collect(),
                    subscribers: HashSet::new(),
                }
            });
            feed.subscribers.insert(subscriber);
        }
        self.save()
    }

    pub fn unsubscribe(&mut self, subscriber: SubscriberID, rss_link: &str) -> Result<Feed> {
        let feed_id = get_hash(rss_link);

        {
            let mut clear_subscriber = false;
            self.subscribers
                .get_mut(&subscriber)
                .map(|subscribed_feeds| if !subscribed_feeds.remove(&feed_id) {
                    Err::<(), Error>(ErrorKind::NotSubscribed.into())
                } else {
                    clear_subscriber = subscribed_feeds.len() == 0;
                    Ok(())
                })
                .unwrap_or(Err(ErrorKind::NotSubscribed.into()))?;
            if clear_subscriber {
                self.subscribers.remove(&subscriber);
            }
        }
        let result;
        {
            let mut clear_feed = false;
            result = self.feeds
                .get_mut(&feed_id)
                .map(|feed| if !feed.subscribers.remove(&subscriber) {
                    Err::<Feed, Error>(ErrorKind::NotSubscribed.into())
                } else {
                    clear_feed = feed.subscribers.len() == 0;
                    Ok(feed.clone())
                })
                .unwrap_or(Err(ErrorKind::NotSubscribed.into()))?;
            if clear_feed {
                self.feeds.remove(&feed_id);
            }
        }
        self.save()?;
        Ok(result)
    }

    pub fn update<'a>(&mut self, rss_link: &str, items: Vec<feed::Item>) -> Vec<feed::Item> {
        let feed_id = get_hash(rss_link);

        self.feeds.get_mut(&feed_id).unwrap().error_count = 0;

        let mut result = Vec::new();
        let mut new_hash_list = HashSet::new();
        let items_len = items.len();
        for item in items {
            let hash = gen_item_hash(&item);
            new_hash_list.insert(hash);
            if !self.feeds[&feed_id].hash_list.contains(&hash) {
                result.push(item);
            }
        }
        if !result.is_empty() {
            let max_size = items_len * 2;
            let feed = self.feeds.get_mut(&feed_id).unwrap();
            for old_hash in &feed.hash_list {
                new_hash_list.insert(*old_hash);
                if new_hash_list.len() >= max_size {
                    break;
                }
            }
            feed.hash_list = new_hash_list;
        }
        self.save().unwrap_or_default();
        result
    }

    pub fn update_title(&mut self, rss_link: &str, new_title: &str) {
        let feed_id = get_hash(rss_link);
        self.feeds.get_mut(&feed_id).unwrap().title = new_title.to_owned();
        self.save().unwrap_or_default();
    }

    fn save(&mut self) -> Result<()> {
        let feeds_list: Vec<&Feed> = self.feeds.iter().map(|(_id, feed)| feed).collect();
        let mut file =
            File::create(&self.path).chain_err(|| ErrorKind::DatabaseSave(self.path.to_owned()))?;
        serde_json::to_writer(&mut file, &feeds_list)
            .chain_err(|| ErrorKind::DatabaseSave(self.path.to_owned()))
    }
}
<|endoftext|>