<commit_before>use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::PathBuf;
use std::str;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex, Once};
use std::thread;
use std::fs;

use bufstream::BufStream;
use cargo_registry::User;
use curl::http;
use rustc_serialize::json;

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    accept: TcpListener,
    quit: Sender<()>,
    rx: Receiver<()>,
    iorx: Sink,
}

pub struct GhUser {
    pub login: &'static str,
    pub init: Once,
}

struct Sink(Arc<Mutex<Vec<u8>>>);

impl Write for Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

impl Drop for Bomb {
    fn drop(&mut self) {
        t!(self.quit.send(()));
        drop(TcpStream::connect(&t!(self.accept.local_addr())));
        let res = self.rx.recv();
        let stderr = str::from_utf8(&self.iorx.0.lock().unwrap()).unwrap()
                         .to_string();
        match res {
            Err(..) if !thread::panicking() => {
                panic!("server subtask failed: {}", stderr)
            }
            _ => {
                if stderr.len() > 0 {
                    println!("server subtask failed: {}", stderr)
                }
            }
        }
    }
}

fn cache_file(name: &str) -> PathBuf {
    PathBuf::from(file!()).parent().unwrap().join("http-data").join(name)
}

pub fn proxy() -> (String, Bomb) {
    let me = thread::current().name().unwrap().to_string();
    let record = env::var("RECORD").is_ok();

    let a = t!(TcpListener::bind("127.0.0.1:0"));
    let ret = format!("http://{}", t!(a.local_addr()));
    let (tx, rx) = channel();

    let data = cache_file(&me.replace("::", "_"));
    let record = record && !data.exists();
    let a2 = t!(a.try_clone());

    let sink = Arc::new(Mutex::new(Vec::new()));
    let mut sink2 = Sink(sink.clone());

    let (quittx, quitrx) = channel();

    thread::spawn(move|| {
        let mut file = None;
        for socket in a.incoming() {
            if quitrx.try_recv().is_ok() { break }
            let socket = t!(socket);

            if file.is_none() {
                let io = t!(if record {
                    File::create(&data)
                } else {
                    File::open(&data)
                });
                file = Some(BufStream::new(io));
            }

            if record {
                record_http(socket, file.as_mut().unwrap());
            } else {
                replay_http(socket, file.as_mut().unwrap(), &mut sink2);
            }
        }
        if !record {
            if let Some(mut f) = file {
                let mut s = String::new();
                t!(f.read_line(&mut s));
                assert_eq!(s, "");
            }
        }
        tx.send(()).unwrap();
    });

    (ret, Bomb { accept: a2, rx: rx, iorx: Sink(sink), quit: quittx })
}

fn record_http(mut socket: TcpStream, data: &mut BufStream<File>) {
    let mut request = Vec::new();
    let http_response = send((&mut socket).tee(&mut request));

    let mut response = Vec::new();
    respond(http_response, socket.broadcast(&mut response));

    t!(write!(data, "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n",
              request.len(),
              str::from_utf8(&request).unwrap(),
              response.len(),
              str::from_utf8(&response).unwrap()));

    fn send<R: Read>(rdr: R) -> http::Response {
        let mut socket = BufReader::new(rdr);
        let method;
        let url;
        let mut headers = HashMap::new();
        {
            let mut lines = (&mut socket).lines();
            let line = t!(lines.next().unwrap());
            let mut parts = line.split(' ');
            method = parts.next().unwrap().to_string();
            url = parts.next().unwrap().replace("http://", "https://");

            for line in lines {
                let line = t!(line);
                if line.len() < 3 { break }
                let mut parts = line.splitn(2, ':');
                headers.insert(parts.next().unwrap().to_string(),
                               parts.next().unwrap()[1..].to_string());
            }
        }

        let mut handle = http::handle();
        let mut req = match &method[..] {
            "PUT" => handle.put(url, &mut socket),
            "POST" => handle.post(url, &mut socket),
            "DELETE" => handle.delete(url),
            "GET" => handle.get(url),
            _ => panic!("unknown method: {}", method),
        };
        for (k, v) in headers.iter() {
            let v = v.trim();
            match &k[..] {
                "Content-Length" => req = req.content_length(v.parse().unwrap()),
                "Content-Type" => req = req.content_type(v),
                "Transfer-Encoding" => {}
                k => req = req.header(k, v),
            }
        }
        t!(req.exec())
    }

    fn respond<W: Write>(response: http::Response, mut socket: W) {
        t!(socket.write_all(format!("HTTP/1.1 {}\r\n",
                                    response.get_code()).as_bytes()));
        for (k, v) in response.get_headers().iter() {
            if *k == "transfer-encoding" { continue }
            for v in v.iter() {
                t!(socket.write_all(k.as_bytes()));
                t!(socket.write_all(b": "));
                t!(socket.write_all(v.as_bytes()));
                t!(socket.write_all(b"\r\n"));
            }
        }
        t!(socket.write_all(b"\r\n"));
        t!(socket.write_all(response.get_body()));
    }
}

fn replay_http(socket: TcpStream, data: &mut BufStream<File>,
               stdout: &mut Write) {
    let mut writer = socket.try_clone().unwrap();
    let socket = BufReader::new(socket);

    let mut request = String::new();
    t!(data.read_line(&mut request));
    let mut request = request.split(' ');
    assert_eq!(request.next().unwrap(), "===REQUEST");
    let request_size = request.next().unwrap().trim().parse().unwrap();

    let mut expected = Vec::new();
    t!(data.take(request_size).read_to_end(&mut expected));
    let mut expected_lines = <[_]>::split(&expected[..], |b| *b == b'\n')
                                     .map(|s| str::from_utf8(s).unwrap())
                                     .map(|s| format!("{}", s));
    let mut actual_lines = socket.lines().map(|s| s.unwrap());

    // validate the headers
    let mut expected: HashSet<String> = expected_lines.by_ref()
                                                      .take_while(|l| l.len() > 2)
                                                      .collect();
    let mut found = HashSet::new();
    t!(writeln!(stdout, "expecting: {:?}", expected));
    for line in actual_lines.by_ref().take_while(|l| l.len() > 2) {
        t!(writeln!(stdout, "received: {}", line.trim()));
        if !found.insert(line.clone()) { continue }
        if expected.remove(&line) { continue }
        if line.starts_with("Date:") { continue }
        if line.starts_with("Authorization:") { continue }
        panic!("unexpected header: {}", line);
    }
    for line in expected.iter() {
        if line.starts_with("Date:") { continue }
        if line.starts_with("Authorization:") { continue }
        panic!("didn't receive header: {}", line);
    }

    // TODO: validate the body

    data.read_line(&mut String::new()).unwrap();
    let mut response = String::new();
    data.read_line(&mut response).unwrap();
    let mut response = response.split(' ');
    assert_eq!(response.next().unwrap(), "===RESPONSE");
    let response_size = response.next().unwrap().trim().parse().unwrap();
    let mut response = Vec::new();
    data.take(response_size).read_to_end(&mut response).unwrap();
    let lines = <[_]>::split(&response[..], |b| *b == b'\n')
                        .map(|s| str::from_utf8(s).unwrap());
    for line in lines {
        if line.starts_with("Date:") { continue }
        writer.write_all(line.as_bytes()).unwrap();
        writer.write_all(b"\r\n").unwrap();
    }
    data.read_line(&mut String::new()).unwrap();
}

impl GhUser {
    pub fn user(&'static self) -> User {
        self.init.call_once(|| self.init());
        let mut u = ::user(self.login);
        u.gh_access_token = self.token();
        return u
    }

    fn filename(&self) -> PathBuf { cache_file(&format!("gh-{}", self.login)) }

    fn token(&self) -> String {
        let mut token = String::new();
        File::open(&self.filename()).unwrap().read_to_string(&mut token).unwrap();
        return token
    }

    fn init(&self) {
        if fs::metadata(&self.filename()).is_ok() { return }

        let password = ::env(&format!("GH_PASS_{}",
                                      self.login.replace("-", "_")));
        #[derive(RustcEncodable)]
        struct Authorization {
            scopes: Vec<String>,
            note: String,
            client_id: String,
            client_secret: String,
        }
        let mut handle = http::handle();
        let url = format!("https://{}:{}@api.github.com/authorizations",
                          self.login, password);
        let body = json::encode(&Authorization {
            scopes: vec!["read:org".to_string()],
            note: "crates.io test".to_string(),
            client_id: ::env("GH_CLIENT_ID"),
            client_secret: ::env("GH_CLIENT_SECRET"),
        }).unwrap();
        let resp = handle.post(&url[..], &body[..])
                         .header("User-Agent", "hello!")
                         .exec().unwrap();
        if resp.get_code() < 200 || resp.get_code() >= 300 {
            panic!("failed to get a 200 {}", resp);
        }

        #[derive(RustcDecodable)]
        struct Response { token: String }
        let resp: Response = json::decode(str::from_utf8(resp.get_body())
                                              .unwrap()).unwrap();
        File::create(&self.filename()).unwrap()
             .write_all(&resp.token.as_bytes()).unwrap();
    }
}
<commit_msg>Update with changes to lines()<commit_after>use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::PathBuf;
use std::str;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex, Once};
use std::thread;
use std::fs;

use bufstream::BufStream;
use cargo_registry::User;
use curl::http;
use rustc_serialize::json;

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    accept: TcpListener,
    quit: Sender<()>,
    rx: Receiver<()>,
    iorx: Sink,
}

pub struct GhUser {
    pub login: &'static str,
    pub init: Once,
}

struct Sink(Arc<Mutex<Vec<u8>>>);

impl Write for Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

impl Drop for Bomb {
    fn drop(&mut self) {
        t!(self.quit.send(()));
        drop(TcpStream::connect(&t!(self.accept.local_addr())));
        let res = self.rx.recv();
        let stderr = str::from_utf8(&self.iorx.0.lock().unwrap()).unwrap()
                         .to_string();
        match res {
            Err(..) if !thread::panicking() => {
                panic!("server subtask failed: {}", stderr)
            }
            _ => {
                if stderr.len() > 0 {
                    println!("server subtask failed: {}", stderr)
                }
            }
        }
    }
}

fn cache_file(name: &str) -> PathBuf {
    PathBuf::from(file!()).parent().unwrap().join("http-data").join(name)
}

pub fn proxy() -> (String, Bomb) {
    let me = thread::current().name().unwrap().to_string();
    let record = env::var("RECORD").is_ok();

    let a = t!(TcpListener::bind("127.0.0.1:0"));
    let ret = format!("http://{}", t!(a.local_addr()));
    let (tx, rx) = channel();

    let data = cache_file(&me.replace("::", "_"));
    let record = record && !data.exists();
    let a2 = t!(a.try_clone());

    let sink = Arc::new(Mutex::new(Vec::new()));
    let mut sink2 = Sink(sink.clone());

    let (quittx, quitrx) = channel();

    thread::spawn(move|| {
        let mut file = None;
        for socket in a.incoming() {
            if quitrx.try_recv().is_ok() { break }
            let socket = t!(socket);

            if file.is_none() {
                let io = t!(if record {
                    File::create(&data)
                } else {
                    File::open(&data)
                });
                file = Some(BufStream::new(io));
            }

            if record {
                record_http(socket, file.as_mut().unwrap());
            } else {
                replay_http(socket, file.as_mut().unwrap(), &mut sink2);
            }
        }
        if !record {
            if let Some(mut f) = file {
                let mut s = String::new();
                t!(f.read_line(&mut s));
                assert_eq!(s, "");
            }
        }
        tx.send(()).unwrap();
    });

    (ret, Bomb { accept: a2, rx: rx, iorx: Sink(sink), quit: quittx })
}

fn record_http(mut socket: TcpStream, data: &mut BufStream<File>) {
    let mut request = Vec::new();
    let http_response = send((&mut socket).tee(&mut request));

    let mut response = Vec::new();
    respond(http_response, socket.broadcast(&mut response));

    t!(write!(data, "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n",
              request.len(),
              str::from_utf8(&request).unwrap(),
              response.len(),
              str::from_utf8(&response).unwrap()));

    fn send<R: Read>(rdr: R) -> http::Response {
        let mut socket = BufReader::new(rdr);
        let method;
        let url;
        let mut headers = HashMap::new();
        {
            let mut lines = (&mut socket).lines();
            let line = t!(lines.next().unwrap());
            let mut parts = line.split(' ');
            method = parts.next().unwrap().to_string();
            url = parts.next().unwrap().replace("http://", "https://");

            for line in lines {
                let line = t!(line);
                if line.len() < 3 { break }
                let mut parts = line.splitn(2, ':');
                headers.insert(parts.next().unwrap().to_string(),
                               parts.next().unwrap()[1..].to_string());
            }
        }

        let mut handle = http::handle();
        let mut req = match &method[..] {
            "PUT" => handle.put(url, &mut socket),
            "POST" => handle.post(url, &mut socket),
            "DELETE" => handle.delete(url),
            "GET" => handle.get(url),
            _ => panic!("unknown method: {}", method),
        };
        for (k, v) in headers.iter() {
            let v = v.trim();
            match &k[..] {
                "Content-Length" => req = req.content_length(v.parse().unwrap()),
                "Content-Type" => req = req.content_type(v),
                "Transfer-Encoding" => {}
                k => req = req.header(k, v),
            }
        }
        t!(req.exec())
    }

    fn respond<W: Write>(response: http::Response, mut socket: W) {
        t!(socket.write_all(format!("HTTP/1.1 {}\r\n",
                                    response.get_code()).as_bytes()));
        for (k, v) in response.get_headers().iter() {
            if *k == "transfer-encoding" { continue }
            for v in v.iter() {
                t!(socket.write_all(k.as_bytes()));
                t!(socket.write_all(b": "));
                t!(socket.write_all(v.as_bytes()));
                t!(socket.write_all(b"\r\n"));
            }
        }
        t!(socket.write_all(b"\r\n"));
        t!(socket.write_all(response.get_body()));
    }
}

fn replay_http(socket: TcpStream, data: &mut BufStream<File>,
               stdout: &mut Write) {
    let mut writer = socket.try_clone().unwrap();
    let socket = BufReader::new(socket);

    let mut request = String::new();
    t!(data.read_line(&mut request));
    let mut request = request.split(' ');
    assert_eq!(request.next().unwrap(), "===REQUEST");
    let request_size = request.next().unwrap().trim().parse().unwrap();

    let mut expected = String::new();
    t!(data.take(request_size).read_to_string(&mut expected));
    let mut expected_lines = expected.lines().map(|s| s.to_string());
    let mut actual_lines = socket.lines().map(|s| s.unwrap());

    // validate the headers
    let mut expected: HashSet<String> = expected_lines.by_ref()
                                                      .take_while(|l| l.len() > 2)
                                                      .collect();
    let mut found = HashSet::new();
    t!(writeln!(stdout, "expecting: {:?}", expected));
    for line in actual_lines.by_ref().take_while(|l| l.len() > 2) {
        t!(writeln!(stdout, "received: {}", line.trim()));
        if !found.insert(line.clone()) { continue }
        if expected.remove(&line) { continue }
        if line.starts_with("Date:") { continue }
        if line.starts_with("Authorization:") { continue }
        panic!("unexpected header: {}", line);
    }
    for line in expected.iter() {
        if line.starts_with("Date:") { continue }
        if line.starts_with("Authorization:") { continue }
        panic!("didn't receive header: {}", line);
    }

    // TODO: validate the body

    data.read_line(&mut String::new()).unwrap();
    let mut response = String::new();
    data.read_line(&mut response).unwrap();
    let mut response = response.split(' ');
    assert_eq!(response.next().unwrap(), "===RESPONSE");
    let response_size = response.next().unwrap().trim().parse().unwrap();
    let mut response = Vec::new();
    data.take(response_size).read_to_end(&mut response).unwrap();
    let lines = <[_]>::split(&response[..], |b| *b == b'\n')
                        .map(|s| str::from_utf8(s).unwrap());
    for line in lines {
        if line.starts_with("Date:") { continue }
        writer.write_all(line.as_bytes()).unwrap();
        writer.write_all(b"\r\n").unwrap();
    }
    data.read_line(&mut String::new()).unwrap();
}

impl GhUser {
    pub fn user(&'static self) -> User {
        self.init.call_once(|| self.init());
        let mut u = ::user(self.login);
        u.gh_access_token = self.token();
        return u
    }

    fn filename(&self) -> PathBuf { cache_file(&format!("gh-{}", self.login)) }

    fn token(&self) -> String {
        let mut token = String::new();
        File::open(&self.filename()).unwrap().read_to_string(&mut token).unwrap();
        return token
    }

    fn init(&self) {
        if fs::metadata(&self.filename()).is_ok() { return }

        let password = ::env(&format!("GH_PASS_{}",
                                      self.login.replace("-", "_")));
        #[derive(RustcEncodable)]
        struct Authorization {
            scopes: Vec<String>,
            note: String,
            client_id: String,
            client_secret: String,
        }
        let mut handle = http::handle();
        let url = format!("https://{}:{}@api.github.com/authorizations",
                          self.login, password);
        let body = json::encode(&Authorization {
            scopes: vec!["read:org".to_string()],
            note: "crates.io test".to_string(),
            client_id: ::env("GH_CLIENT_ID"),
            client_secret: ::env("GH_CLIENT_SECRET"),
        }).unwrap();
        let resp = handle.post(&url[..], &body[..])
                         .header("User-Agent", "hello!")
                         .exec().unwrap();
        if resp.get_code() < 200 || resp.get_code() >= 300 {
            panic!("failed to get a 200 {}", resp);
        }

        #[derive(RustcDecodable)]
        struct Response { token: String }
        let resp: Response = json::decode(str::from_utf8(resp.get_body())
                                              .unwrap()).unwrap();
        File::create(&self.filename()).unwrap()
             .write_all(&resp.token.as_bytes()).unwrap();
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Fangxu Hu <framlog@gmail.com>
// (c) Sylvestre Ledru <sylvestre@debian.org>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
// spell-checker:ignore itotal iused iavail ipcent pcent
mod table;

#[cfg(unix)]
use uucore::fsext::statfs_fn;
use uucore::fsext::{read_fs_list, FsUsage, MountInfo};
use uucore::{error::UResult, format_usage};

use clap::{crate_version, App, AppSettings, Arg, ArgMatches};

use std::collections::HashSet;
#[cfg(unix)]
use std::ffi::CString;
use std::iter::FromIterator;
#[cfg(unix)]
use std::mem;

#[cfg(windows)]
use std::path::Path;

use crate::table::{DisplayRow, Header, Row};

static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
                      or all file systems by default.";
const USAGE: &str = "{} [OPTION]... [FILE]...";

static OPT_ALL: &str = "all";
static OPT_BLOCKSIZE: &str = "blocksize";
static OPT_DIRECT: &str = "direct";
static OPT_TOTAL: &str = "total";
static OPT_HUMAN_READABLE: &str = "human-readable";
static OPT_HUMAN_READABLE_2: &str = "human-readable-2";
static OPT_INODES: &str = "inodes";
static OPT_KILO: &str = "kilo";
static OPT_LOCAL: &str = "local";
static OPT_NO_SYNC: &str = "no-sync";
static OPT_OUTPUT: &str = "output";
static OPT_PATHS: &str = "paths";
static OPT_PORTABILITY: &str = "portability";
static OPT_SYNC: &str = "sync";
static OPT_TYPE: &str = "type";
static OPT_PRINT_TYPE: &str = "print-type";
static OPT_EXCLUDE_TYPE: &str = "exclude-type";
static OUTPUT_FIELD_LIST: [&str; 12] = [
    "source", "fstype", "itotal", "iused", "iavail", "ipcent", "size", "used", "avail", "pcent",
    "file", "target",
];

/// Store names of file systems as a selector.
/// Note: `exclude` takes priority over `include`.
#[derive(Default)]
struct FsSelector {
    include: HashSet<String>,
    exclude: HashSet<String>,
}

/// A block size to use in condensing the display of a large number of bytes.
///
/// The [`BlockSize::Bytes`] variant represents a static block
/// size. The [`BlockSize::HumanReadableDecimal`] and
/// [`BlockSize::HumanReadableBinary`] variants represent dynamic
/// block sizes: as the number of bytes increases, the divisor
/// increases as well (for example, from 1 to 1,000 to 1,000,000 and
/// so on in the case of [`BlockSize::HumanReadableDecimal`]).
///
/// The default variant is `Bytes(1024)`.
enum BlockSize {
    /// A fixed number of bytes.
    ///
    /// The number must be positive.
    Bytes(u64),

    /// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
    ///
    /// This variant represents powers of 1,000. Contrast with
    /// [`BlockSize::HumanReadableBinary`], which represents powers of
    /// 1,024.
    HumanReadableDecimal,

    /// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
    ///
    /// This variant represents powers of 1,024. Contrast with
    /// [`BlockSize::HumanReadableDecimal`], which represents powers
    /// of 1,000.
    HumanReadableBinary,
}

impl Default for BlockSize {
    fn default() -> Self {
        Self::Bytes(1024)
    }
}

impl From<&ArgMatches> for BlockSize {
    fn from(matches: &ArgMatches) -> Self {
        if matches.is_present(OPT_HUMAN_READABLE) {
            Self::HumanReadableBinary
        } else if matches.is_present(OPT_HUMAN_READABLE_2) {
            Self::HumanReadableDecimal
        } else {
            Self::default()
        }
    }
}

#[derive(Default)]
struct Options {
    show_local_fs: bool,
    show_all_fs: bool,
    show_listed_fs: bool,
    show_fs_type: bool,
    show_inode_instead: bool,
    block_size: BlockSize,
    fs_selector: FsSelector,
}

impl Options {
    /// Convert command-line arguments into [`Options`].
    fn from(matches: &ArgMatches) -> Self {
        Self {
            show_local_fs: matches.is_present(OPT_LOCAL),
            show_all_fs: matches.is_present(OPT_ALL),
            show_listed_fs: false,
            show_fs_type: matches.is_present(OPT_PRINT_TYPE),
            show_inode_instead: matches.is_present(OPT_INODES),
            block_size: BlockSize::from(matches),
            fs_selector: FsSelector::from(matches),
        }
    }
}

#[derive(Debug, Clone)]
struct Filesystem {
    mount_info: MountInfo,
    usage: FsUsage,
}

impl FsSelector {
    /// Convert command-line arguments into a [`FsSelector`].
    ///
    /// This function reads the include and exclude sets from
    /// [`ArgMatches`] and returns the corresponding [`FsSelector`]
    /// instance.
    fn from(matches: &ArgMatches) -> Self {
        let include = HashSet::from_iter(matches.values_of_lossy(OPT_TYPE).unwrap_or_default());
        let exclude = HashSet::from_iter(
            matches
                .values_of_lossy(OPT_EXCLUDE_TYPE)
                .unwrap_or_default(),
        );
        Self { include, exclude }
    }

    fn should_select(&self, fs_type: &str) -> bool {
        if self.exclude.contains(fs_type) {
            return false;
        }
        self.include.is_empty() || self.include.contains(fs_type)
    }
}

impl Filesystem {
    // TODO: resolve uuid in `mount_info.dev_name` if exists
    fn new(mount_info: MountInfo) -> Option<Self> {
        let _stat_path = if !mount_info.mount_dir.is_empty() {
            mount_info.mount_dir.clone()
        } else {
            #[cfg(unix)]
            {
                mount_info.dev_name.clone()
            }
            #[cfg(windows)]
            {
                // On windows, we expect the volume id
                mount_info.dev_id.clone()
            }
        };
        #[cfg(unix)]
        unsafe {
            let path = CString::new(_stat_path).unwrap();
            let mut statvfs = mem::zeroed();
            if statfs_fn(path.as_ptr(), &mut statvfs) < 0 {
                None
            } else {
                Some(Self {
                    mount_info,
                    usage: FsUsage::new(statvfs),
                })
            }
        }
        #[cfg(windows)]
        Some(Self {
            mount_info,
            usage: FsUsage::new(Path::new(&_stat_path)),
        })
    }
}

/// Whether to display the mount info given the inclusion settings.
fn is_included(mi: &MountInfo, paths: &[String], opt: &Options) -> bool {
    // Don't show remote filesystems if `--local` has been given.
    if mi.remote && opt.show_local_fs {
        return false;
    }

    // Don't show pseudo filesystems unless `--all` has been given.
    if mi.dummy && !opt.show_all_fs && !opt.show_listed_fs {
        return false;
    }

    // Don't show filesystems if they have been explicitly excluded.
    if !opt.fs_selector.should_select(&mi.fs_type) {
        return false;
    }

    // Don't show filesystems other than the ones specified on the
    // command line, if any.
    if !paths.is_empty() && !paths.contains(&mi.mount_dir) {
        return false;
    }

    true
}

/// Whether the mount info in `m2` should be prioritized over `m1`.
///
/// The "lt" in the function name is in analogy to the
/// [`std::cmp::PartialOrd::lt`].
fn mount_info_lt(m1: &MountInfo, m2: &MountInfo) -> bool {
    // let "real" devices with '/' in the name win.
    if m1.dev_name.starts_with('/') && !m2.dev_name.starts_with('/') {
        return false;
    }

    let m1_nearer_root = m1.mount_dir.len() < m2.mount_dir.len();
    // With bind mounts, prefer items nearer the root of the source
    let m2_below_root = !m1.mount_root.is_empty()
        && !m2.mount_root.is_empty()
        && m1.mount_root.len() > m2.mount_root.len();
    // let points towards the root of the device win.
    if m1_nearer_root && !m2_below_root {
        return false;
    }

    // let an entry over-mounted on a new device win, but only when
    // matching an existing mnt point, to avoid problematic
    // replacement when given inaccurate mount lists, seen with some
    // chroot environments for example.
    if m1.dev_name != m2.dev_name && m1.mount_dir == m2.mount_dir {
        return false;
    }

    true
}

/// Whether to prioritize given mount info over all others on the same device.
///
/// This function decides whether the mount info `mi` is better than
/// all others in `previous` that mount the same device as `mi`.
fn is_best(previous: &[MountInfo], mi: &MountInfo) -> bool {
    for seen in previous {
        if seen.dev_id == mi.dev_id && mount_info_lt(mi, seen) {
            return false;
        }
    }
    true
}

/// Keep only the specified subset of [`MountInfo`] instances.
///
/// If `paths` is non-empty, this function excludes any [`MountInfo`]
/// that is not mounted at the specified path.
///
/// The `opt` argument specifies a variety of ways of excluding
/// [`MountInfo`] instances; see [`Options`] for more information.
///
/// Finally, if there are duplicate entries, the one with the shorter
/// path is kept.
fn filter_mount_list(vmi: Vec<MountInfo>, paths: &[String], opt: &Options) -> Vec<MountInfo> {
    let mut result = vec![];
    for mi in vmi {
        // TODO The running time of the `is_best()` function is linear
        // in the length of `result`. That makes the running time of
        // this loop quadratic in the length of `vmi`. This could be
        // improved by a more efficient implementation of `is_best()`,
        // but `vmi` is probably not very long in practice.
        if is_included(&mi, paths, opt) && is_best(&result, &mi) {
            result.push(mi);
        }
    }
    result
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let paths: Vec<String> = matches
        .values_of(OPT_PATHS)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    #[cfg(windows)]
    {
        if matches.is_present(OPT_INODES) {
            println!("{}: doesn't support -i option", uucore::util_name());
            return Ok(());
        }
    }

    let opt = Options::from(&matches);

    let mounts = read_fs_list();
    let data: Vec<Row> = filter_mount_list(mounts, &paths, &opt)
        .into_iter()
        .filter_map(Filesystem::new)
        .filter(|fs| fs.usage.blocks != 0 || opt.show_all_fs || opt.show_listed_fs)
        .map(Into::into)
        .collect();
    println!("{}", Header::new(&opt));
    for row in data {
        println!("{}", DisplayRow::new(row, &opt));
    }

    Ok(())
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .setting(AppSettings::InferLongArgs)
        .arg(
            Arg::new(OPT_ALL)
                .short('a')
                .long("all")
                .help("include dummy file systems"),
        )
        .arg(
            Arg::new(OPT_BLOCKSIZE)
                .short('B')
                .long("block-size")
                .takes_value(true)
                .help(
                    "scale sizes by SIZE before printing them; e.g.\
                     '-BM' prints sizes in units of 1,048,576 bytes",
                ),
        )
        .arg(
            Arg::new(OPT_DIRECT)
                .long("direct")
                .help("show statistics for a file instead of mount point"),
        )
        .arg(
            Arg::new(OPT_TOTAL)
                .long("total")
                .help("produce a grand total"),
        )
        .arg(
            Arg::new(OPT_HUMAN_READABLE)
                .short('h')
                .long("human-readable")
                .conflicts_with(OPT_HUMAN_READABLE_2)
                .help("print sizes in human readable format (e.g., 1K 234M 2G)"),
        )
        .arg(
            Arg::new(OPT_HUMAN_READABLE_2)
                .short('H')
                .long("si")
                .conflicts_with(OPT_HUMAN_READABLE)
                .help("likewise, but use powers of 1000 not 1024"),
        )
        .arg(
            Arg::new(OPT_INODES)
                .short('i')
                .long("inodes")
                .help("list inode information instead of block usage"),
        )
        .arg(Arg::new(OPT_KILO).short('k').help("like --block-size=1K"))
        .arg(
            Arg::new(OPT_LOCAL)
                .short('l')
                .long("local")
                .help("limit listing to local file systems"),
        )
        .arg(
            Arg::new(OPT_NO_SYNC)
                .long("no-sync")
                .conflicts_with(OPT_SYNC)
                .help("do not invoke sync before getting usage info (default)"),
        )
        .arg(
            Arg::new(OPT_OUTPUT)
                .long("output")
                .takes_value(true)
                .use_delimiter(true)
                .possible_values(OUTPUT_FIELD_LIST)
                .default_missing_values(&OUTPUT_FIELD_LIST)
                .default_values(&["source", "size", "used", "avail", "pcent", "target"])
                .conflicts_with_all(&[OPT_INODES, OPT_PORTABILITY, OPT_PRINT_TYPE])
                .help(
                    "use the output format defined by FIELD_LIST,\
                     or print all fields if FIELD_LIST is omitted.",
                ),
        )
        .arg(
            Arg::new(OPT_PORTABILITY)
                .short('P')
                .long("portability")
                .help("use the POSIX output format"),
        )
        .arg(
            Arg::new(OPT_SYNC)
                .long("sync")
                .conflicts_with(OPT_NO_SYNC)
                .help("invoke sync before getting usage info"),
        )
        .arg(
            Arg::new(OPT_TYPE)
                .short('t')
                .long("type")
                .allow_invalid_utf8(true)
                .takes_value(true)
                .multiple_occurrences(true)
                .help("limit listing to file systems of type TYPE"),
        )
        .arg(
            Arg::new(OPT_PRINT_TYPE)
                .short('T')
                .long("print-type")
                .help("print file system type"),
        )
        .arg(
            Arg::new(OPT_EXCLUDE_TYPE)
                .short('x')
                .long("exclude-type")
                .takes_value(true)
                .use_delimiter(true)
                .help("limit listing to file systems not of type TYPE"),
        )
        .arg(Arg::new(OPT_PATHS).multiple_occurrences(true))
}
<commit_msg>df: use safe wrapper function for statfs() func.<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Fangxu Hu <framlog@gmail.com>
// (c) Sylvestre Ledru <sylvestre@debian.org>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
// spell-checker:ignore itotal iused iavail ipcent pcent
mod table;

#[cfg(unix)]
use uucore::fsext::statfs;
use uucore::fsext::{read_fs_list, FsUsage, MountInfo};
use uucore::{error::UResult, format_usage};

use clap::{crate_version, App, AppSettings, Arg, ArgMatches};

use std::collections::HashSet;
use std::iter::FromIterator;

#[cfg(windows)]
use std::path::Path;

use crate::table::{DisplayRow, Header, Row};

static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
                      or all file systems by default.";
const USAGE: &str = "{} [OPTION]... [FILE]...";

static OPT_ALL: &str = "all";
static OPT_BLOCKSIZE: &str = "blocksize";
static OPT_DIRECT: &str = "direct";
static OPT_TOTAL: &str = "total";
static OPT_HUMAN_READABLE: &str = "human-readable";
static OPT_HUMAN_READABLE_2: &str = "human-readable-2";
static OPT_INODES: &str = "inodes";
static OPT_KILO: &str = "kilo";
static OPT_LOCAL: &str = "local";
static OPT_NO_SYNC: &str = "no-sync";
static OPT_OUTPUT: &str = "output";
static OPT_PATHS: &str = "paths";
static OPT_PORTABILITY: &str = "portability";
static OPT_SYNC: &str = "sync";
static OPT_TYPE: &str = "type";
static OPT_PRINT_TYPE: &str = "print-type";
static OPT_EXCLUDE_TYPE: &str = "exclude-type";
static OUTPUT_FIELD_LIST: [&str; 12] = [
    "source", "fstype", "itotal", "iused", "iavail", "ipcent", "size", "used", "avail", "pcent",
    "file", "target",
];

/// Store names of file systems as a selector.
/// Note: `exclude` takes priority over `include`.
#[derive(Default)]
struct FsSelector {
    include: HashSet<String>,
    exclude: HashSet<String>,
}

/// A block size to use in condensing the display of a large number of bytes.
///
/// The [`BlockSize::Bytes`] variant represents a static block
/// size. The [`BlockSize::HumanReadableDecimal`] and
/// [`BlockSize::HumanReadableBinary`] variants represent dynamic
/// block sizes: as the number of bytes increases, the divisor
/// increases as well (for example, from 1 to 1,000 to 1,000,000 and
/// so on in the case of [`BlockSize::HumanReadableDecimal`]).
///
/// The default variant is `Bytes(1024)`.
enum BlockSize {
    /// A fixed number of bytes.
    ///
    /// The number must be positive.
    Bytes(u64),

    /// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
    ///
    /// This variant represents powers of 1,000. Contrast with
    /// [`BlockSize::HumanReadableBinary`], which represents powers of
    /// 1,024.
    HumanReadableDecimal,

    /// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
    ///
    /// This variant represents powers of 1,024. Contrast with
    /// [`BlockSize::HumanReadableDecimal`], which represents powers
    /// of 1,000.
    HumanReadableBinary,
}

impl Default for BlockSize {
    fn default() -> Self {
        Self::Bytes(1024)
    }
}

impl From<&ArgMatches> for BlockSize {
    fn from(matches: &ArgMatches) -> Self {
        if matches.is_present(OPT_HUMAN_READABLE) {
            Self::HumanReadableBinary
        } else if matches.is_present(OPT_HUMAN_READABLE_2) {
            Self::HumanReadableDecimal
        } else {
            Self::default()
        }
    }
}

#[derive(Default)]
struct Options {
    show_local_fs: bool,
    show_all_fs: bool,
    show_listed_fs: bool,
    show_fs_type: bool,
    show_inode_instead: bool,
    block_size: BlockSize,
    fs_selector: FsSelector,
}

impl Options {
    /// Convert command-line arguments into [`Options`].
    fn from(matches: &ArgMatches) -> Self {
        Self {
            show_local_fs: matches.is_present(OPT_LOCAL),
            show_all_fs: matches.is_present(OPT_ALL),
            show_listed_fs: false,
            show_fs_type: matches.is_present(OPT_PRINT_TYPE),
            show_inode_instead: matches.is_present(OPT_INODES),
            block_size: BlockSize::from(matches),
            fs_selector: FsSelector::from(matches),
        }
    }
}

#[derive(Debug, Clone)]
struct Filesystem {
    mount_info: MountInfo,
    usage: FsUsage,
}

impl FsSelector {
    /// Convert command-line arguments into a [`FsSelector`].
    ///
    /// This function reads the include and exclude sets from
    /// [`ArgMatches`] and returns the corresponding [`FsSelector`]
    /// instance.
    fn from(matches: &ArgMatches) -> Self {
        let include = HashSet::from_iter(matches.values_of_lossy(OPT_TYPE).unwrap_or_default());
        let exclude = HashSet::from_iter(
            matches
                .values_of_lossy(OPT_EXCLUDE_TYPE)
                .unwrap_or_default(),
        );
        Self { include, exclude }
    }

    fn should_select(&self, fs_type: &str) -> bool {
        if self.exclude.contains(fs_type) {
            return false;
        }
        self.include.is_empty() || self.include.contains(fs_type)
    }
}

impl Filesystem {
    // TODO: resolve uuid in `mount_info.dev_name` if exists
    fn new(mount_info: MountInfo) -> Option<Self> {
        let _stat_path = if !mount_info.mount_dir.is_empty() {
            mount_info.mount_dir.clone()
        } else {
            #[cfg(unix)]
            {
                mount_info.dev_name.clone()
            }
            #[cfg(windows)]
            {
                // On windows, we expect the volume id
                mount_info.dev_id.clone()
            }
        };
        #[cfg(unix)]
        let usage = FsUsage::new(statfs(_stat_path).ok()?);
        #[cfg(windows)]
        let usage = FsUsage::new(Path::new(&_stat_path));
        Some(Self { mount_info, usage })
    }
}

/// Whether to display the mount info given the inclusion settings.
fn is_included(mi: &MountInfo, paths: &[String], opt: &Options) -> bool {
    // Don't show remote filesystems if `--local` has been given.
    if mi.remote && opt.show_local_fs {
        return false;
    }

    // Don't show pseudo filesystems unless `--all` has been given.
    if mi.dummy && !opt.show_all_fs && !opt.show_listed_fs {
        return false;
    }

    // Don't show filesystems if they have been explicitly excluded.
    if !opt.fs_selector.should_select(&mi.fs_type) {
        return false;
    }

    // Don't show filesystems other than the ones specified on the
    // command line, if any.
    if !paths.is_empty() && !paths.contains(&mi.mount_dir) {
        return false;
    }

    true
}

/// Whether the mount info in `m2` should be prioritized over `m1`.
///
/// The "lt" in the function name is in analogy to the
/// [`std::cmp::PartialOrd::lt`].
fn mount_info_lt(m1: &MountInfo, m2: &MountInfo) -> bool {
    // let "real" devices with '/' in the name win.
    if m1.dev_name.starts_with('/') && !m2.dev_name.starts_with('/') {
        return false;
    }

    let m1_nearer_root = m1.mount_dir.len() < m2.mount_dir.len();
    // With bind mounts, prefer items nearer the root of the source
    let m2_below_root = !m1.mount_root.is_empty()
        && !m2.mount_root.is_empty()
        && m1.mount_root.len() > m2.mount_root.len();
    // let points towards the root of the device win.
    if m1_nearer_root && !m2_below_root {
        return false;
    }

    // let an entry over-mounted on a new device win, but only when
    // matching an existing mnt point, to avoid problematic
    // replacement when given inaccurate mount lists, seen with some
    // chroot environments for example.
    if m1.dev_name != m2.dev_name && m1.mount_dir == m2.mount_dir {
        return false;
    }

    true
}

/// Whether to prioritize given mount info over all others on the same device.
///
/// This function decides whether the mount info `mi` is better than
/// all others in `previous` that mount the same device as `mi`.
fn is_best(previous: &[MountInfo], mi: &MountInfo) -> bool {
    for seen in previous {
        if seen.dev_id == mi.dev_id && mount_info_lt(mi, seen) {
            return false;
        }
    }
    true
}

/// Keep only the specified subset of [`MountInfo`] instances.
///
/// If `paths` is non-empty, this function excludes any [`MountInfo`]
/// that is not mounted at the specified path.
///
/// The `opt` argument specifies a variety of ways of excluding
/// [`MountInfo`] instances; see [`Options`] for more information.
///
/// Finally, if there are duplicate entries, the one with the shorter
/// path is kept.
fn filter_mount_list(vmi: Vec<MountInfo>, paths: &[String], opt: &Options) -> Vec<MountInfo> {
    let mut result = vec![];
    for mi in vmi {
        // TODO The running time of the `is_best()` function is linear
        // in the length of `result`. That makes the running time of
        // this loop quadratic in the length of `vmi`. This could be
        // improved by a more efficient implementation of `is_best()`,
        // but `vmi` is probably not very long in practice.
        if is_included(&mi, paths, opt) && is_best(&result, &mi) {
            result.push(mi);
        }
    }
    result
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let paths: Vec<String> = matches
        .values_of(OPT_PATHS)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    #[cfg(windows)]
    {
        if matches.is_present(OPT_INODES) {
            println!("{}: doesn't support -i option", uucore::util_name());
            return Ok(());
        }
    }

    let opt = Options::from(&matches);

    let mounts = read_fs_list();
    let data: Vec<Row> = filter_mount_list(mounts, &paths, &opt)
        .into_iter()
        .filter_map(Filesystem::new)
        .filter(|fs| fs.usage.blocks != 0 || opt.show_all_fs || opt.show_listed_fs)
        .map(Into::into)
        .collect();
    println!("{}", Header::new(&opt));
    for row in data {
        println!("{}", DisplayRow::new(row, &opt));
    }

    Ok(())
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .setting(AppSettings::InferLongArgs)
        .arg(
            Arg::new(OPT_ALL)
                .short('a')
                .long("all")
                .help("include dummy file systems"),
        )
        .arg(
            Arg::new(OPT_BLOCKSIZE)
                .short('B')
                .long("block-size")
                .takes_value(true)
                .help(
                    "scale sizes by SIZE before printing them; e.g.\
                     '-BM' prints sizes in units of 1,048,576 bytes",
                ),
        )
        .arg(
            Arg::new(OPT_DIRECT)
                .long("direct")
                .help("show statistics for a file instead of mount point"),
        )
        .arg(
            Arg::new(OPT_TOTAL)
                .long("total")
                .help("produce a grand total"),
        )
        .arg(
            Arg::new(OPT_HUMAN_READABLE)
                .short('h')
                .long("human-readable")
                .conflicts_with(OPT_HUMAN_READABLE_2)
                .help("print sizes in human readable format (e.g., 1K 234M 2G)"),
        )
        .arg(
            Arg::new(OPT_HUMAN_READABLE_2)
                .short('H')
                .long("si")
                .conflicts_with(OPT_HUMAN_READABLE)
                .help("likewise, but use powers of 1000 not 1024"),
        )
        .arg(
            Arg::new(OPT_INODES)
                .short('i')
                .long("inodes")
                .help("list inode information instead of block usage"),
        )
        .arg(Arg::new(OPT_KILO).short('k').help("like --block-size=1K"))
        .arg(
            Arg::new(OPT_LOCAL)
                .short('l')
                .long("local")
                .help("limit listing to local file systems"),
        )
        .arg(
            Arg::new(OPT_NO_SYNC)
                .long("no-sync")
                .conflicts_with(OPT_SYNC)
                .help("do not invoke sync before getting usage info (default)"),
        )
        .arg(
            Arg::new(OPT_OUTPUT)
                .long("output")
                .takes_value(true)
                .use_delimiter(true)
                .possible_values(OUTPUT_FIELD_LIST)
                .default_missing_values(&OUTPUT_FIELD_LIST)
                .default_values(&["source", "size", "used", "avail", "pcent", "target"])
                .conflicts_with_all(&[OPT_INODES, OPT_PORTABILITY, OPT_PRINT_TYPE])
                .help(
                    "use the output format defined by FIELD_LIST,\
                     or print all fields if FIELD_LIST is omitted.",
                ),
        )
        .arg(
            Arg::new(OPT_PORTABILITY)
                .short('P')
                .long("portability")
                .help("use the POSIX output format"),
        )
        .arg(
            Arg::new(OPT_SYNC)
                .long("sync")
                .conflicts_with(OPT_NO_SYNC)
                .help("invoke sync before getting usage info"),
        )
        .arg(
            Arg::new(OPT_TYPE)
                .short('t')
                .long("type")
                .allow_invalid_utf8(true)
                .takes_value(true)
                .multiple_occurrences(true)
                .help("limit listing to file systems of type TYPE"),
        )
        .arg(
            Arg::new(OPT_PRINT_TYPE)
                .short('T')
                .long("print-type")
                .help("print file system type"),
        )
        .arg(
            Arg::new(OPT_EXCLUDE_TYPE)
                .short('x')
                .long("exclude-type")
                .takes_value(true)
                .use_delimiter(true)
                .help("limit listing to file systems not of type TYPE"),
        )
        .arg(Arg::new(OPT_PATHS).multiple_occurrences(true))
}
<|endoftext|>


<commit_before>//! Provider for the `implied_outlives_bounds` query.
//! Do not call this query directory. See
//! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`].

use rustc_hir as hir;
use rustc_infer::infer::canonical::{self, Canonical};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::source_map::DUMMY_SP;
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound;
use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
use rustc_trait_selection::traits::wf;
use rustc_trait_selection::traits::FulfillmentContext;
use rustc_trait_selection::traits::TraitEngine;
use smallvec::{smallvec, SmallVec};

crate fn provide(p: &mut Providers) {
    *p = Providers { implied_outlives_bounds, ..*p };
}

fn implied_outlives_bounds<'tcx>(
    tcx: TyCtxt<'tcx>,
    goal: CanonicalTyGoal<'tcx>,
) -> Result<
    &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
    NoSolution,
> {
    tcx.infer_ctxt().enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| {
        let (param_env, ty) = key.into_parts();
        compute_implied_outlives_bounds(&infcx, param_env, ty)
    })
}

fn compute_implied_outlives_bounds<'tcx>(
    infcx: &InferCtxt<'_, 'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    ty: Ty<'tcx>,
) -> Fallible<Vec<OutlivesBound<'tcx>>> {
    let tcx = infcx.tcx;

    // Sometimes when we ask what it takes for T: WF, we get back that
    // U: WF is required; in that case, we push U onto this stack and
    // process it next. Currently (at least) these resulting
    // predicates are always guaranteed to be a subset of the original
    // type, so we need not fear non-termination.
    let mut wf_args = vec![ty.into()];

    let mut implied_bounds = vec![];

    let mut fulfill_cx = FulfillmentContext::new();

    while let Some(arg) = wf_args.pop() {
        // Compute the obligations for `arg` to be well-formed. If `arg` is
        // an unresolved inference variable, just substituted an empty set
        // -- because the return type here is going to be things we *add*
        // to the environment, it's always ok for this set to be smaller
        // than the ultimate set. (Note: normally there won't be
        // unresolved inference variables here anyway, but there might be
        // during typeck under some circumstances.)
        let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
            .unwrap_or_default();

        // N.B., all of these predicates *ought* to be easily proven
        // true. In fact, their correctness is (mostly) implied by
        // other parts of the program. However, in #42552, we had
        // an annoying scenario where:
        //
        // - Some `T::Foo` gets normalized, resulting in a
        //   variable `_1` and a `T: Trait<Foo=_1>` constraint
        //   (not sure why it couldn't immediately get
        //   solved). This result of `_1` got cached.
        // - These obligations were dropped on the floor here,
        //   rather than being registered.
        // - Then later we would get a request to normalize
        //   `T::Foo` which would result in `_1` being used from
        //   the cache, but hence without the `T: Trait<Foo=_1>`
        //   constraint. As a result, `_1` never gets resolved,
        //   and we get an ICE (in dropck).
        //
        // Therefore, we register any predicates involving
        // inference variables. We restrict ourselves to those
        // involving inference variables both for efficiency and
        // to avoids duplicate errors that otherwise show up.
        fulfill_cx.register_predicate_obligations(
            infcx,
            obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
        );

        // From the full set of obligations, just filter down to the
        // region relationships.
        implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
            assert!(!obligation.has_escaping_bound_vars());
            let binder = obligation.predicate.bound_atom();
            if binder.skip_binder().has_escaping_bound_vars() {
                vec![]
            } else {
                match binder.skip_binder() {
                    ty::PredicateAtom::Trait(..)
                    | ty::PredicateAtom::Subtype(..)
                    | ty::PredicateAtom::Projection(..)
                    | ty::PredicateAtom::ClosureKind(..)
                    | ty::PredicateAtom::ObjectSafe(..)
                    | ty::PredicateAtom::ConstEvaluatable(..)
                    | ty::PredicateAtom::ConstEquate(..)
                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![],
                    ty::PredicateAtom::WellFormed(arg) => {
                        wf_args.push(arg);
                        vec![]
                    }

                    ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
                        vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
                    }

                    ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
                        let ty_a = infcx.resolve_vars_if_possible(ty_a);
                        let mut components = smallvec![];
                        tcx.push_outlives_components(ty_a, &mut components);
                        implied_bounds_from_components(r_b, components)
                    }
                }
            }
        }));
    }

    // Ensure that those obligations that we had to solve
    // get solved *here*.
    match fulfill_cx.select_all_or_error(infcx) {
        Ok(()) => Ok(implied_bounds),
        Err(_) => Err(NoSolution),
    }
}

/// When we have an implied bound that `T: 'a`, we can further break
/// this down to determine what relationships would have to hold for
/// `T: 'a` to hold. We get to assume that the caller has validated
/// those relationships.
fn implied_bounds_from_components(
    sub_region: ty::Region<'tcx>,
    sup_components: SmallVec<[Component<'tcx>; 4]>,
) -> Vec<OutlivesBound<'tcx>> {
    sup_components
        .into_iter()
        .filter_map(|component| {
            match component {
                Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
                Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
                Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
                Component::EscapingProjection(_) =>
                // If the projection has escaping regions, don't
                // try to infer any implied bounds even for its
                // free components. This is conservative, because
                // the caller will still have to prove that those
                // free components outlive `sub_region`. But the
                // idea is that the WAY that the caller proves
                // that may change in the future and we want to
                // give ourselves room to get smarter here.
                {
                    None
                }
                Component::UnresolvedInferenceVariable(..) => None,
            }
        })
        .collect()
}
<commit_msg>Use no_bound_vars<commit_after>//! Provider for the `implied_outlives_bounds` query.
//! Do not call this query directory. See
//! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`].

use rustc_hir as hir;
use rustc_infer::infer::canonical::{self, Canonical};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::source_map::DUMMY_SP;
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound;
use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
use rustc_trait_selection::traits::wf;
use rustc_trait_selection::traits::FulfillmentContext;
use rustc_trait_selection::traits::TraitEngine;
use smallvec::{smallvec, SmallVec};

crate fn provide(p: &mut Providers) {
    *p = Providers { implied_outlives_bounds, ..*p };
}

fn implied_outlives_bounds<'tcx>(
    tcx: TyCtxt<'tcx>,
    goal: CanonicalTyGoal<'tcx>,
) -> Result<
    &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
    NoSolution,
> {
    tcx.infer_ctxt().enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| {
        let (param_env, ty) = key.into_parts();
        compute_implied_outlives_bounds(&infcx, param_env, ty)
    })
}

fn compute_implied_outlives_bounds<'tcx>(
    infcx: &InferCtxt<'_, 'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    ty: Ty<'tcx>,
) -> Fallible<Vec<OutlivesBound<'tcx>>> {
    let tcx = infcx.tcx;

    // Sometimes when we ask what it takes for T: WF, we get back that
    // U: WF is required; in that case, we push U onto this stack and
    // process it next. Currently (at least) these resulting
    // predicates are always guaranteed to be a subset of the original
    // type, so we need not fear non-termination.
    let mut wf_args = vec![ty.into()];

    let mut implied_bounds = vec![];

    let mut fulfill_cx = FulfillmentContext::new();

    while let Some(arg) = wf_args.pop() {
        // Compute the obligations for `arg` to be well-formed. If `arg` is
        // an unresolved inference variable, just substituted an empty set
        // -- because the return type here is going to be things we *add*
        // to the environment, it's always ok for this set to be smaller
        // than the ultimate set. (Note: normally there won't be
        // unresolved inference variables here anyway, but there might be
        // during typeck under some circumstances.)
        let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
            .unwrap_or_default();

        // N.B., all of these predicates *ought* to be easily proven
        // true. In fact, their correctness is (mostly) implied by
        // other parts of the program. However, in #42552, we had
        // an annoying scenario where:
        //
        // - Some `T::Foo` gets normalized, resulting in a
        //   variable `_1` and a `T: Trait<Foo=_1>` constraint
        //   (not sure why it couldn't immediately get
        //   solved). This result of `_1` got cached.
        // - These obligations were dropped on the floor here,
        //   rather than being registered.
        // - Then later we would get a request to normalize
        //   `T::Foo` which would result in `_1` being used from
        //   the cache, but hence without the `T: Trait<Foo=_1>`
        //   constraint. As a result, `_1` never gets resolved,
        //   and we get an ICE (in dropck).
        //
        // Therefore, we register any predicates involving
        // inference variables. We restrict ourselves to those
        // involving inference variables both for efficiency and
        // to avoids duplicate errors that otherwise show up.
        fulfill_cx.register_predicate_obligations(
            infcx,
            obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
        );

        // From the full set of obligations, just filter down to the
        // region relationships.
        implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
            assert!(!obligation.has_escaping_bound_vars());
            match obligation.predicate.bound_atom().no_bound_vars() {
                None => vec![],
                Some(pred) => match pred {
                    ty::PredicateAtom::Trait(..)
                    | ty::PredicateAtom::Subtype(..)
                    | ty::PredicateAtom::Projection(..)
                    | ty::PredicateAtom::ClosureKind(..)
                    | ty::PredicateAtom::ObjectSafe(..)
                    | ty::PredicateAtom::ConstEvaluatable(..)
                    | ty::PredicateAtom::ConstEquate(..)
                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![],
                    ty::PredicateAtom::WellFormed(arg) => {
                        wf_args.push(arg);
                        vec![]
                    }

                    ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
                        vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
                    }

                    ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
                        let ty_a = infcx.resolve_vars_if_possible(ty_a);
                        let mut components = smallvec![];
                        tcx.push_outlives_components(ty_a, &mut components);
                        implied_bounds_from_components(r_b, components)
                    }
                },
            }
        }));
    }

    // Ensure that those obligations that we had to solve
    // get solved *here*.
    match fulfill_cx.select_all_or_error(infcx) {
        Ok(()) => Ok(implied_bounds),
        Err(_) => Err(NoSolution),
    }
}

/// When we have an implied bound that `T: 'a`, we can further break
/// this down to determine what relationships would have to hold for
/// `T: 'a` to hold. We get to assume that the caller has validated
/// those relationships.
fn implied_bounds_from_components(
    sub_region: ty::Region<'tcx>,
    sup_components: SmallVec<[Component<'tcx>; 4]>,
) -> Vec<OutlivesBound<'tcx>> {
    sup_components
        .into_iter()
        .filter_map(|component| {
            match component {
                Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
                Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
                Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
                Component::EscapingProjection(_) =>
                // If the projection has escaping regions, don't
                // try to infer any implied bounds even for its
                // free components. This is conservative, because
                // the caller will still have to prove that those
                // free components outlive `sub_region`. But the
                // idea is that the WAY that the caller proves
                // that may change in the future and we want to
                // give ourselves room to get smarter here.
                {
                    None
                }
                Component::UnresolvedInferenceVariable(..) => None,
            }
        })
        .collect()
}
<|endoftext|>


<commit_before>use std::fmt;

use std::os::raw::c_char;

use super::nif_interface::{ NIF_TERM };

pub fn fmt<'a>(term: NIF_TERM, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    const SIZE: usize = 1024;
    let mut bytes: Vec<u8> = Vec::with_capacity(SIZE);

    let mut n = 0;
    for _ in 0 .. 10 {
        let i = unsafe {
            enif_snprintf!(bytes.as_mut_ptr() as *mut c_char,
                           bytes.capacity(),
                           b"%T\x00" as *const u8 as *const c_char,
                           term)
        };
        if i < 0 {
            // Do not propagate an error, because string formatting is
            // supposed to be infallible.
            break;
        }

        n = i as usize;
        if n >= bytes.capacity() {
            // Bizarrely, enif_snprintf consistently underestimates the
            // amount of memory it will need to write long lists. To try to
            // avoid going around the loop again, double the estimate.
            bytes.reserve_exact(2 * n + 1);
        } else {
            break;
        }
    }

    unsafe {
        bytes.set_len(n);
    }
    f.write_str(&String::from_utf8_lossy(&bytes))
}
<commit_msg>Fix unlikely-to-hit logic bug in Debug support.<commit_after>use std::fmt;

use std::os::raw::c_char;

use super::nif_interface::{ NIF_TERM };

pub fn fmt<'a>(term: NIF_TERM, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    const SIZE: usize = 1024;
    let mut bytes: Vec<u8> = Vec::with_capacity(SIZE);

    let mut n = 0;
    for _ in 0 .. 10 {
        let i = unsafe {
            enif_snprintf!(bytes.as_mut_ptr() as *mut c_char,
                           bytes.capacity(),
                           b"%T\x00" as *const u8 as *const c_char,
                           term)
        };
        if i < 0 {
            // Do not propagate an error, because string formatting is
            // supposed to be infallible.
            break;
        }

        n = i as usize;
        if n >= bytes.capacity() {
            // Bizarrely, enif_snprintf consistently underestimates the
            // amount of memory it will need to write long lists. To try to
            // avoid going around the loop again, double the estimate.
            bytes.reserve_exact(2 * n + 1);

            // Ensure that the `set_len` call below does not expose
            // uninitialized bytes if we give up after 10 attempts.
            n = 0;
        } else {
            break;
        }
    }

    unsafe {
        bytes.set_len(n);
    }
    f.write_str(&String::from_utf8_lossy(&bytes))
}
<|endoftext|>


<commit_before>use glm;

pub trait Interpolate {
    fn interpolate(&self, next: Self, interpolation: f64) -> Self;
}

impl Interpolate for glm::IVec2 {
    fn interpolate(&self, next: glm::IVec2, interpolation: f64) -> glm::IVec2 {
        let delta = next - *self;
        *self + glm::to_ivec2((glm::to_dvec2(delta) * interpolation))
    }
}

pub struct State<T> {
    pub old: T,
    pub current: T,
}

impl<T: Copy + Interpolate> State<T> {
    pub fn new(state: T) -> Self {
        State {
            old: state,
            current: state,
        }
    }

    pub fn update(&mut self, new: T) {
        self.old = self.current;
        self.current = new;
    }

    pub fn interpolated(&self, interpolation: f64) -> T {
        self.old.interpolate(self.current, interpolation)
    }
}
<commit_msg>removed unneeded paren<commit_after>use glm;

pub trait Interpolate {
    fn interpolate(&self, next: Self, interpolation: f64) -> Self;
}

impl Interpolate for glm::IVec2 {
    fn interpolate(&self, next: glm::IVec2, interpolation: f64) -> glm::IVec2 {
        let delta = next - *self;
        *self + glm::to_ivec2(glm::to_dvec2(delta) * interpolation)
    }
}

pub struct State<T> {
    pub old: T,
    pub current: T,
}

impl<T: Copy + Interpolate> State<T> {
    pub fn new(state: T) -> Self {
        State {
            old: state,
            current: state,
        }
    }

    pub fn update(&mut self, new: T) {
        self.old = self.current;
        self.current = new;
    }

    pub fn interpolated(&self, interpolation: f64) -> T {
        self.old.interpolate(self.current, interpolation)
    }
}
<|endoftext|>


<commit_before>#[rustversion::attr(not(nightly), ignore)]
#[test]
fn ui() {
    let t = trybuild::TestCases::new();
    t.compile_fail("tests/ui/*.rs");
}
<commit_msg>Disable ui test on miri<commit_after>#[rustversion::attr(not(nightly), ignore)]
#[cfg_attr(miri, ignore)]
#[test]
fn ui() {
    let t = trybuild::TestCases::new();
    t.compile_fail("tests/ui/*.rs");
}
<|endoftext|>


<commit_before>extern crate id_tree;

use id_tree::NodeIdError;
use id_tree::Node;
use id_tree::TreeBuilder;
use id_tree::Tree;
use id_tree::RemoveBehavior;
use id_tree::MoveBehavior;
use id_tree::InsertBehavior;
use id_tree::SwapBehavior;

#[test]
fn test_old_node_id() {
    let mut tree: Tree<i32> = TreeBuilder::new().build();

    let root_node = Node::new(1);

    let root_id = tree.insert(root_node, InsertBehavior::AsRoot).ok().unwrap();
    let root_id_copy = root_id.clone(); // this is essential to getting the Result::Err()

    let root_node = tree.remove_node(root_id, RemoveBehavior::OrphanChildren);
    assert!(root_node.is_ok());

    let root_node_again = tree.remove_node(root_id_copy, RemoveBehavior::OrphanChildren);
    assert!(root_node_again.is_err());

    let error = root_node_again.err().unwrap();
    assert_eq!(error, NodeIdError::NodeIdNoLongerValid);
}

#[test]
fn test_get_node_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_a = tree_a.get(&root_node_id_a);
    let root_node_b = tree_b.get(&root_node_id_a); //note use of wrong tree

    assert!(root_node_a.is_ok());
    assert!(root_node_b.is_err());
    assert_eq!(root_node_b.err().unwrap(),
               NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_get_mut_node_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_a = tree_a.get_mut(&root_node_id_a);
    let root_node_b = tree_b.get_mut(&root_node_id_a); //note use of wrong tree

    assert!(root_node_a.is_ok());
    assert!(root_node_b.is_err());
    assert_eq!(root_node_b.err().unwrap(),
               NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_remove_node_lift_children_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_id_a = tree_a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();

    // note use of wrong tree
    let root_node_b = tree_b.remove_node(root_node_id_a, RemoveBehavior::LiftChildren);
    assert!(root_node_b.is_err());

    let error = root_node_b.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_remove_node_orphan_children_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_id_a = tree_a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();

    // note use of wrong tree
    let root_node_b = tree_b.remove_node(root_node_id_a, RemoveBehavior::OrphanChildren);
    assert!(root_node_b.is_err());

    let error = root_node_b.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_remove_node_remove_children_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_id_a = tree_a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();

    // note use of wrong tree
    let root_node_b = tree_b.remove_node(root_node_id_a, RemoveBehavior::DropChildren);
    assert!(root_node_b.is_err());

    let error = root_node_b.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_move_node_into_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    // note use of invalid parent
    let result = tree_a.move_node(&root_node_id_a, MoveBehavior::ToParent(&root_node_id_b));
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_move_node_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    // note use of invalid child
    let result = tree_a.move_node(&root_node_id_b, MoveBehavior::ToParent(&root_node_id_a));
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_move_node_to_root_by_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.move_node(&root_node_id_b, MoveBehavior::ToRoot);
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_sort_by_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.sort_children_by(&root_node_id_b, |a, b| a.data().cmp(b.data()));
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_sort_by_data_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.sort_children_by_data(&root_node_id_b);
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_sort_by_key_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.sort_children_by_key(&root_node_id_b, |x| x.data().clone());
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_swap_sub_trees_of_different_trees() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    // note use of invalid child
    let result = tree_a.swap_nodes(&root_node_id_b, &root_node_id_a, SwapBehavior::TakeChildren);
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}
<commit_msg>WiP: add a few more tests<commit_after>extern crate id_tree;

use id_tree::NodeIdError;
use id_tree::Node;
use id_tree::TreeBuilder;
use id_tree::Tree;
use id_tree::RemoveBehavior;
use id_tree::MoveBehavior;
use id_tree::InsertBehavior;
use id_tree::SwapBehavior;

#[test]
fn test_old_node_id() {
    let mut tree: Tree<i32> = TreeBuilder::new().build();

    let root_node = Node::new(1);

    let root_id = tree.insert(root_node, InsertBehavior::AsRoot).ok().unwrap();
    let root_id_copy = root_id.clone(); // this is essential to getting the Result::Err()

    let root_node = tree.remove_node(root_id, RemoveBehavior::OrphanChildren);
    assert!(root_node.is_ok());

    let root_node_again = tree.remove_node(root_id_copy, RemoveBehavior::OrphanChildren);
    assert!(root_node_again.is_err());

    let error = root_node_again.err().unwrap();
    assert_eq!(error, NodeIdError::NodeIdNoLongerValid);
}

#[test]
fn test_get_node_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_a = tree_a.get(&root_node_id_a);
    let root_node_b = tree_b.get(&root_node_id_a); //note use of wrong tree

    assert!(root_node_a.is_ok());
    assert!(root_node_b.is_err());
    assert_eq!(root_node_b.err().unwrap(),
               NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_get_mut_node_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_a = tree_a.get_mut(&root_node_id_a);
    let root_node_b = tree_b.get_mut(&root_node_id_a); //note use of wrong tree

    assert!(root_node_a.is_ok());
    assert!(root_node_b.is_err());
    assert_eq!(root_node_b.err().unwrap(),
               NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_remove_node_lift_children_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_id_a = tree_a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();

    // note use of wrong tree
    let root_node_b = tree_b.remove_node(root_node_id_a, RemoveBehavior::LiftChildren);
    assert!(root_node_b.is_err());

    let error = root_node_b.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_remove_node_orphan_children_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_id_a = tree_a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();

    // note use of wrong tree
    let root_node_b = tree_b.remove_node(root_node_id_a, RemoveBehavior::OrphanChildren);
    assert!(root_node_b.is_err());

    let error = root_node_b.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_remove_node_remove_children_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_id_a = tree_a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();

    // note use of wrong tree
    let root_node_b = tree_b.remove_node(root_node_id_a, RemoveBehavior::DropChildren);
    assert!(root_node_b.is_err());

    let error = root_node_b.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_move_node_into_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    // note use of invalid parent
    let result = tree_a.move_node(&root_node_id_a, MoveBehavior::ToParent(&root_node_id_b));
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_move_node_from_other_tree() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    // note use of invalid child
    let result = tree_a.move_node(&root_node_id_b, MoveBehavior::ToParent(&root_node_id_a));
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_move_node_to_root_by_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.move_node(&root_node_id_b, MoveBehavior::ToRoot);
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_sort_by_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.sort_children_by(&root_node_id_b, |a, b| a.data().cmp(b.data()));
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_sort_by_data_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.sort_children_by_data(&root_node_id_b);
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_sort_by_key_invalid_id() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let _ = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    let result = tree_a.sort_children_by_key(&root_node_id_b, |x| x.data().clone());
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_swap_sub_trees_of_different_trees() {
    let mut tree_a: Tree<i32> = TreeBuilder::new().build();
    let mut tree_b: Tree<i32> = TreeBuilder::new().build();

    let root_node_a = Node::new(1);
    let root_node_id_a = tree_a.insert(root_node_a, InsertBehavior::AsRoot).unwrap();

    let root_node_b = Node::new(1);
    let root_node_id_b = tree_b.insert(root_node_b, InsertBehavior::AsRoot).unwrap();

    // note use of invalid child
    let result = tree_a.swap_nodes(&root_node_id_b, &root_node_id_a, SwapBehavior::TakeChildren);
    assert!(result.is_err());

    let error = result.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_ancestors_different_trees() {
    let mut a = Tree::new();
    let b = Tree::<i32>::new();

    let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();

    // note usage of `b` instead of `a`
    let ancestors = b.ancestors(&root_id);

    assert!(ancestors.is_err());
    let error = ancestors.err().unwrap();
    assert_eq!(error, NodeIdError::InvalidNodeIdForTree);
}

#[test]
fn test_ancestors_old_id() {
    let mut a = Tree::new();

    let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap();
    // `.clone()` required to get this error
    let root_id_clone = root_id.clone();
    let _ = a.remove_node(root_id, RemoveBehavior::DropChildren).unwrap();

    // note usage of cloned `NodeId`
    let ancestors = a.ancestors(&root_id_clone);

    assert!(ancestors.is_err());
    let error = ancestors.err().unwrap();
    assert_eq!(error, NodeIdError::NodeIdNoLongerValid);
}
<|endoftext|>


<commit_before>extern crate cargotest;
extern crate hamcrest;

use cargotest::is_nightly;
use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
fn noop() {
    if !is_nightly() {
        return;
    }

    let client = project("client")
        .file("Cargo.toml", r#"
            [package]
            name = "client"
            version = "0.0.1"
            authors = []

            [dependencies.noop]
            path = "../noop"
        "#)
        .file("src/main.rs", r#"
            #![feature(rustc_macro)]

            #[macro_use]
            extern crate noop;

            #[derive(Noop)]
            struct X;

            fn main() {}
        "#);
    let noop = project("noop")
        .file("Cargo.toml", r#"
            [package]
            name = "noop"
            version = "0.0.1"
            authors = []

            [lib]
            rustc-macro = true
        "#)
        .file("src/lib.rs", r#"
            #![feature(rustc_macro, rustc_macro_lib)]

            extern crate rustc_macro;
            use rustc_macro::TokenStream;

            #[rustc_macro_derive(Noop)]
            pub fn noop(input: TokenStream) -> TokenStream {
                input
            }
        "#);
    noop.build();

    assert_that(client.cargo_process("build"),
                execs().with_status(0));
    assert_that(client.cargo("build"),
                execs().with_status(0));
}

#[test]
fn impl_and_derive() {
    if !is_nightly() {
        return;
    }

    let client = project("client")
        .file("Cargo.toml", r#"
            [package]
            name = "client"
            version = "0.0.1"
            authors = []

            [dependencies.transmogrify]
            path = "../transmogrify"
        "#)
        .file("src/main.rs", r#"
            #![feature(rustc_macro)]

            #[macro_use]
            extern crate transmogrify;

            trait ImplByTransmogrify {
                fn impl_by_transmogrify(&self) -> bool;
            }

            #[derive(Transmogrify)]
            struct X;

            fn main() {
                let x = X::new();
                assert!(x.impl_by_transmogrify());
                println!("{:?}", x);
            }
        "#);
    let transmogrify = project("transmogrify")
        .file("Cargo.toml", r#"
            [package]
            name = "transmogrify"
            version = "0.0.1"
            authors = []

            [lib]
            rustc-macro = true
        "#)
        .file("src/lib.rs", r#"
            #![feature(rustc_macro, rustc_macro_lib)]

            extern crate rustc_macro;
            use rustc_macro::TokenStream;

            #[rustc_macro_derive(Transmogrify)]
            #[doc(hidden)]
            pub fn transmogrify(input: TokenStream) -> TokenStream {
                assert_eq!(input.to_string(), "struct X;\n");

                "
                    impl X {
                        fn new() -> Self {
                            X { success: true }
                        }
                    }

                    impl ImplByTransmogrify for X {
                        fn impl_by_transmogrify(&self) -> bool {
                            true
                        }
                    }

                    #[derive(Debug)]
                    struct X {
                        success: bool,
                    }
                ".parse().unwrap()
            }
        "#);
    transmogrify.build();

    assert_that(client.cargo_process("build"),
                execs().with_status(0));
    assert_that(client.cargo("run"),
                execs().with_status(0).with_stdout("X { success: true }"));
}

#[test]
fn plugin_and_rustc_macro() {
    if !is_nightly() {
        return;
    }

    let questionable = project("questionable")
        .file("Cargo.toml", r#"
            [package]
            name = "questionable"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true
            rustc-macro = true
        "#)
        .file("src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]
            #![feature(rustc_macro, rustc_macro_lib)]

            extern crate rustc_plugin;
            use rustc_plugin::Registry;

            extern crate rustc_macro;
            use rustc_macro::TokenStream;

            #[plugin_registrar]
            pub fn plugin_registrar(reg: &mut Registry) {}

            #[rustc_macro_derive(Questionable)]
            pub fn questionable(input: TokenStream) -> TokenStream {
                input
            }
        "#);

    let msg = "  lib.plugin and lib.rustc-macro cannot both be true";
    assert_that(questionable.cargo_process("build"),
                execs().with_status(101).with_stderr_contains(msg));
}
<commit_msg>Auto merge of #3170 - alexcrichton:ignore-rustc-macro, r=alexcrichton<commit_after>extern crate cargotest;
extern crate hamcrest;

use cargotest::is_nightly;
use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
#[ignore]
fn noop() {
    if !is_nightly() {
        return;
    }

    let client = project("client")
        .file("Cargo.toml", r#"
            [package]
            name = "client"
            version = "0.0.1"
            authors = []

            [dependencies.noop]
            path = "../noop"
        "#)
        .file("src/main.rs", r#"
            #![feature(rustc_macro)]

            #[macro_use]
            extern crate noop;

            #[derive(Noop)]
            struct X;

            fn main() {}
        "#);
    let noop = project("noop")
        .file("Cargo.toml", r#"
            [package]
            name = "noop"
            version = "0.0.1"
            authors = []

            [lib]
            rustc-macro = true
        "#)
        .file("src/lib.rs", r#"
            #![feature(rustc_macro, rustc_macro_lib)]

            extern crate rustc_macro;
            use rustc_macro::TokenStream;

            #[rustc_macro_derive(Noop)]
            pub fn noop(input: TokenStream) -> TokenStream {
                input
            }
        "#);
    noop.build();

    assert_that(client.cargo_process("build"),
                execs().with_status(0));
    assert_that(client.cargo("build"),
                execs().with_status(0));
}

#[test]
#[ignore]
fn impl_and_derive() {
    if !is_nightly() {
        return;
    }

    let client = project("client")
        .file("Cargo.toml", r#"
            [package]
            name = "client"
            version = "0.0.1"
            authors = []

            [dependencies.transmogrify]
            path = "../transmogrify"
        "#)
        .file("src/main.rs", r#"
            #![feature(rustc_macro)]

            #[macro_use]
            extern crate transmogrify;

            trait ImplByTransmogrify {
                fn impl_by_transmogrify(&self) -> bool;
            }

            #[derive(Transmogrify)]
            struct X;

            fn main() {
                let x = X::new();
                assert!(x.impl_by_transmogrify());
                println!("{:?}", x);
            }
        "#);
    let transmogrify = project("transmogrify")
        .file("Cargo.toml", r#"
            [package]
            name = "transmogrify"
            version = "0.0.1"
            authors = []

            [lib]
            rustc-macro = true
        "#)
        .file("src/lib.rs", r#"
            #![feature(rustc_macro, rustc_macro_lib)]

            extern crate rustc_macro;
            use rustc_macro::TokenStream;

            #[rustc_macro_derive(Transmogrify)]
            #[doc(hidden)]
            pub fn transmogrify(input: TokenStream) -> TokenStream {
                assert_eq!(input.to_string(), "struct X;\n");

                "
                    impl X {
                        fn new() -> Self {
                            X { success: true }
                        }
                    }

                    impl ImplByTransmogrify for X {
                        fn impl_by_transmogrify(&self) -> bool {
                            true
                        }
                    }

                    #[derive(Debug)]
                    struct X {
                        success: bool,
                    }
                ".parse().unwrap()
            }
        "#);
    transmogrify.build();

    assert_that(client.cargo_process("build"),
                execs().with_status(0));
    assert_that(client.cargo("run"),
                execs().with_status(0).with_stdout("X { success: true }"));
}

#[test]
#[ignore]
fn plugin_and_rustc_macro() {
    if !is_nightly() {
        return;
    }

    let questionable = project("questionable")
        .file("Cargo.toml", r#"
            [package]
            name = "questionable"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true
            rustc-macro = true
        "#)
        .file("src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]
            #![feature(rustc_macro, rustc_macro_lib)]

            extern crate rustc_plugin;
            use rustc_plugin::Registry;

            extern crate rustc_macro;
            use rustc_macro::TokenStream;

            #[plugin_registrar]
            pub fn plugin_registrar(reg: &mut Registry) {}

            #[rustc_macro_derive(Questionable)]
            pub fn questionable(input: TokenStream) -> TokenStream {
                input
            }
        "#);

    let msg = "  lib.plugin and lib.rustc-macro cannot both be true";
    assert_that(questionable.cargo_process("build"),
                execs().with_status(101).with_stderr_contains(msg));
}
<|endoftext|>


<commit_before>extern mod extra;
use extra::sort;
use std::hashmap::HashMap;

struct School ( HashMap<uint, ~[~str]> );

fn sorted<T: Clone + Ord>(array: &[T]) -> ~[T] {
    let mut res = array.iter().map(|v| v.clone()).to_owned_vec();
    sort::tim_sort(res);
    res
}

impl School {
    pub fn new() -> School {
        School(HashMap::new())
    }

    pub fn add(self, grade: uint, student: &str) -> School {
        let mut m = *self;
        m.mangle(
            grade,
            student,
            |_, x| ~[x.into_owned()],
            |_, xs, x| xs.push(x.into_owned()));
        School(m)
    }

    pub fn sorted(self) -> ~[(uint, ~[~str])] {
        sorted((*self).iter().map(|(&grade, students)| {
            (grade, sorted(students.clone()))
        }).to_owned_vec())
    }

    pub fn grade(self, grade: uint) -> ~[~str] {
        let default: ~[~str] = ~[];
        sorted(*(*self).find(&grade).unwrap_or(&default))
    }
}
<commit_msg>rust grade-school - use a named field in School, clean up grade(uint)<commit_after>extern mod extra;
use extra::sort;
use std::hashmap::HashMap;

struct School {
    priv grades: HashMap<uint, ~[~str]>
}

fn sorted<T: Clone + Ord>(array: &[T]) -> ~[T] {
    let mut res = array.iter().map(|v| v.clone()).to_owned_vec();
    sort::tim_sort(res);
    res
}

impl School {
    pub fn new() -> School {
        School { grades: HashMap::new() }
    }

    pub fn add(self, grade: uint, student: &str) -> School {
        let mut s = self;
        s.grades.mangle(
            grade,
            student,
            |_, x| ~[x.into_owned()],
            |_, xs, x| xs.push(x.into_owned()));
        s
    }

    pub fn sorted(self) -> ~[(uint, ~[~str])] {
        sorted(self.grades.iter().map(|(&grade, students)| {
            (grade, sorted(students.clone()))
        }).to_owned_vec())
    }

    pub fn grade(self, grade: uint) -> ~[~str] {
        self.grades.find(&grade).map(|&v| sorted(v.to_owned())).unwrap_or(~[])
    }
}
<|endoftext|>