<commit_before>use std::{fs, cmp};
use std::path::Path;
use std::io::{self, Read};

use reqwest::{Client as HClient, header};
use serde_json;
use prettytable::Table;

use rpc::message::{CMessage, SMessage};
use rpc::criterion::{Criterion, Value, Operation};
use rpc::resource::{Resource, ResourceKind, SResourceUpdate};

use client::Client;
use error::{Result, ResultExt, ErrorKind};

pub fn add(mut c: Client, url: &str, files: Vec<&str>, dir: Option<&str>) -> Result<()> {
    for file in files {
        add_file(&mut c, url, file, dir)?;
    }
    Ok(())
}

fn add_file(c: &mut Client, url: &str, file: &str, dir: Option<&str>) -> Result<()> {
    let mut torrent = Vec::new();
    let mut f = fs::File::open(file).chain_err(|| ErrorKind::FileIO)?;
    f.read_to_end(&mut torrent).chain_err(|| ErrorKind::FileIO)?;

    let msg = CMessage::UploadTorrent {
        serial: c.next_serial(),
        size: torrent.len() as u64,
        path: dir.as_ref().map(|d| format!("{}", d)),
    };
    let token = if let SMessage::TransferOffer { token, .. } = c.rr(msg)? {
        token
    } else {
        bail!("Failed to receieve transfer offer from synapse!");
    };
    let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
    client
        .post(url)
        .chain_err(|| ErrorKind::HTTP)?
        .header(header::Authorization(header::Bearer { token }))
        .body(torrent)
        .send()
        .chain_err(|| ErrorKind::HTTP)?;

    if let SMessage::OResourcesExtant { .. } = c.recv()? {
    } else {
        bail!("Failed to receieve upload acknowledgement from synapse!");
    };

    Ok(())
}

pub fn del(mut c: Client, torrents: Vec<&str>) -> Result<()> {
    for torrent in torrents {
        del_torrent(&mut c, torrent)?;
    }
    Ok(())
}

fn del_torrent(c: &mut Client, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::RemoveResource {
            serial: c.next_serial(),
            id: resources[0].id().to_owned(),
        };
        c.send(msg)?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

pub fn dl(mut c: Client, url: &str, name: &str) -> Result<()> {
    let resources = search_torrent_name(&mut c, name)?;
    let files = if resources.len() == 1 {
        let msg = CMessage::FilterSubscribe {
            serial: c.next_serial(),
            kind: ResourceKind::File,
            criteria: vec![
                Criterion {
                    field: "torrent_id".to_owned(),
                    op: Operation::Eq,
                    value: Value::S(resources[0].id().to_owned()),
                },
            ],
        };
        if let SMessage::OResourcesExtant { ids, .. } = c.rr(msg)? {
            get_resources(&mut c, ids)?
        } else {
            bail!("Could not get files for torrent!");
        }
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", name);
        return Ok(());
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            name
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
        return Ok(());
    };

    for file in files {
        let msg = CMessage::DownloadFile {
            serial: c.next_serial(),
            id: file.id().to_owned(),
        };
        if let SMessage::TransferOffer { token, .. } = c.rr(msg)? {
            let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
            let mut resp = client
                .get(url)
                .chain_err(|| ErrorKind::HTTP)?
                .header(header::Authorization(header::Bearer { token }))
                .send()
                .chain_err(|| ErrorKind::HTTP)?;
            if let Resource::File(f) = file {
                let p = Path::new(&f.path);
                if let Some(par) = p.parent() {
                    fs::create_dir_all(par).chain_err(|| ErrorKind::FileIO)?;
                }
                let mut f = fs::File::create(p).chain_err(|| ErrorKind::FileIO)?;
                io::copy(&mut resp, &mut f).chain_err(|| ErrorKind::FileIO)?;
            } else {
                bail!("Expected a file resource");
            }
        }
    }
    Ok(())
}

pub fn list(mut c: Client, kind: &str, crit: Vec<Criterion>, output: &str) -> Result<()> {
    let k = match kind {
        "torrent" => ResourceKind::Torrent,
        "tracker" => ResourceKind::Tracker,
        "peer" => ResourceKind::Peer,
        "piece" => ResourceKind::Piece,
        "file" => ResourceKind::File,
        "server" => ResourceKind::Server,
        _ => bail!("Unexpected resource kind {}", kind),
    };
    let results = search(&mut c, k, crit)?;
    if output == "text" {
        let mut table = Table::new();
        match k {
            ResourceKind::Torrent => {
                table.add_row(row!["Name", "Done", "DL", "UL", "DL RT", "UL RT", "Peers"]);
            }
            ResourceKind::Tracker => {
                table.add_row(row!["URL", "Torrent", "Error"]);
            }
            ResourceKind::Peer => {
                table.add_row(row!["IP", "Torrent", "DL RT", "UL RT"]);
            }
            ResourceKind::Piece => {
                table.add_row(row!["Torrent", "DLd", "Avail"]);
            }
            ResourceKind::File => {
                table.add_row(row!["Path", "Torrent", "Done", "Prio", "Avail"]);
            }
            ResourceKind::Server => {
                table.add_row(row!["DL RT", "UL RT"]);
            }
        }

        #[cfg_attr(rustfmt, rustfmt_skip)]
        for res in results {
            match k {
                ResourceKind::Torrent => {
                    let t = res.as_torrent();
                    table.add_row(row![
                        t.name,
                        format!("{:.2}%", t.progress * 100.),
                        fmt_bytes(t.transferred_down as f64),
                        fmt_bytes(t.transferred_up as f64),
                        fmt_bytes(t.rate_down as f64) + "/s",
                        fmt_bytes(t.rate_up as f64) + "/s",
                        t.peers
                    ]);
                }
                ResourceKind::Tracker => {
                    let t = res.as_tracker();
                    table.add_row(row![
                        t.url,
                        t.torrent_id,
                        t.error.as_ref().map(|s| s.as_str()).unwrap_or("")
                    ]);
                }
                ResourceKind::Peer => {
                    let p = res.as_peer();
                    let rd = fmt_bytes(p.rate_down as f64) + "/s";
                    let ru = fmt_bytes(p.rate_up as f64) + "/s";
                    table.add_row(row![p.ip, p.torrent_id, rd, ru]);
                }
                ResourceKind::Piece => {
                    let p = res.as_piece();
                    table.add_row(row![p.torrent_id, p.downloaded, p.available]);
                }
                ResourceKind::File => {
                    let f = res.as_file();
                    table.add_row(row![
                        f.path,
                        f.torrent_id,
                        format!("{:.2}%", f.progress as f64 * 100.),
                        f.priority,
                        format!("{:.2}%", f.availability as f64 * 100.)
                    ]);
                }
                ResourceKind::Server => {
                    let s = res.as_server();
                    let rd = fmt_bytes(s.rate_down as f64) + "/s";
                    let ru = fmt_bytes(s.rate_up as f64) + "/s";
                    table.add_row(row![rd, ru]);
                }
            }
        }
        table.printstd();
    } else {
        println!(
            "{}",
            serde_json::to_string_pretty(&results).chain_err(|| {
                ErrorKind::Serialization
            })?
        );
    }
    Ok(())
}

pub fn pause(mut c: Client, torrents: Vec<&str>) -> Result<()> {
    for torrent in torrents {
        pause_torrent(&mut c, torrent)?;
    }
    Ok(())
}

fn pause_torrent(c: &mut Client, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::PauseTorrent {
            serial: c.next_serial(),
            id: resources[0].id().to_owned(),
        };
        c.send(msg)?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

pub fn resume(mut c: Client, torrents: Vec<&str>) -> Result<()> {
    for torrent in torrents {
        resume_torrent(&mut c, torrent)?;
    }
    Ok(())
}

fn resume_torrent(c: &mut Client, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::ResumeTorrent {
            serial: c.next_serial(),
            id: resources[0].id().to_owned(),
        };
        c.send(msg)?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

fn search_torrent_name(c: &mut Client, name: &str) -> Result<Vec<Resource>> {
    search(
        c,
        ResourceKind::Torrent,
        vec![
            Criterion {
                field: "name".to_owned(),
                op: Operation::ILike,
                value: Value::S(format!("%{}%", name)),
            },
        ],
    )
}

fn search(c: &mut Client, kind: ResourceKind, criteria: Vec<Criterion>) -> Result<Vec<Resource>> {
    let s = c.next_serial();
    let msg = CMessage::FilterSubscribe {
        serial: s,
        kind,
        criteria,
    };
    if let SMessage::OResourcesExtant { ids, .. } = c.rr(msg)? {
        get_resources(c, ids)
    } else {
        bail!("Failed to receive extant resource list!");
    }
}

fn get_resources(c: &mut Client, ids: Vec<String>) -> Result<Vec<Resource>> {
    let msg = CMessage::Subscribe {
        serial: c.next_serial(),
        ids,
    };
    let resources = if let SMessage::UpdateResources { resources } = c.rr(msg)? {
        resources
    } else {
        bail!("Failed to received torrent resource list!");
    };

    let mut results = Vec::new();
    for r in resources {
        if let SResourceUpdate::OResource(res) = r {
            results.push(res);
        } else {
            bail!("Failed to received full resource!");
        }
    }
    Ok(results)
}

fn fmt_bytes(num: f64) -> String {
    let num = num.abs();
    let units = ["B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    if num < 1_f64 {
        return format!("{} {}", num, "B");
    }
    let delimiter = 1024_f64;
    let exponent = cmp::min(
        (num.ln() / delimiter.ln()).floor() as i32,
        (units.len() - 1) as i32,
    );
    let pretty_bytes = format!("{:.2}", num / delimiter.powi(exponent))
        .parse::<f64>()
        .unwrap() * 1_f64;
    let unit = units[exponent as usize];
    format!("{} {}", pretty_bytes, unit)
}
<commit_msg>Update sycli for start field in torrent upload<commit_after>use std::{fs, cmp};
use std::path::Path;
use std::io::{self, Read};

use reqwest::{Client as HClient, header};
use serde_json;
use prettytable::Table;

use rpc::message::{CMessage, SMessage};
use rpc::criterion::{Criterion, Value, Operation};
use rpc::resource::{Resource, ResourceKind, SResourceUpdate};

use client::Client;
use error::{Result, ResultExt, ErrorKind};

pub fn add(mut c: Client, url: &str, files: Vec<&str>, dir: Option<&str>) -> Result<()> {
    for file in files {
        add_file(&mut c, url, file, dir)?;
    }
    Ok(())
}

fn add_file(c: &mut Client, url: &str, file: &str, dir: Option<&str>) -> Result<()> {
    let mut torrent = Vec::new();
    let mut f = fs::File::open(file).chain_err(|| ErrorKind::FileIO)?;
    f.read_to_end(&mut torrent).chain_err(|| ErrorKind::FileIO)?;

    let msg = CMessage::UploadTorrent {
        serial: c.next_serial(),
        size: torrent.len() as u64,
        path: dir.as_ref().map(|d| format!("{}", d)),
        start: true,
    };
    let token = if let SMessage::TransferOffer { token, .. } = c.rr(msg)? {
        token
    } else {
        bail!("Failed to receieve transfer offer from synapse!");
    };
    let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
    client
        .post(url)
        .chain_err(|| ErrorKind::HTTP)?
        .header(header::Authorization(header::Bearer { token }))
        .body(torrent)
        .send()
        .chain_err(|| ErrorKind::HTTP)?;

    if let SMessage::OResourcesExtant { .. } = c.recv()? {
    } else {
        bail!("Failed to receieve upload acknowledgement from synapse!");
    };

    Ok(())
}

pub fn del(mut c: Client, torrents: Vec<&str>) -> Result<()> {
    for torrent in torrents {
        del_torrent(&mut c, torrent)?;
    }
    Ok(())
}

fn del_torrent(c: &mut Client, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::RemoveResource {
            serial: c.next_serial(),
            id: resources[0].id().to_owned(),
        };
        c.send(msg)?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

pub fn dl(mut c: Client, url: &str, name: &str) -> Result<()> {
    let resources = search_torrent_name(&mut c, name)?;
    let files = if resources.len() == 1 {
        let msg = CMessage::FilterSubscribe {
            serial: c.next_serial(),
            kind: ResourceKind::File,
            criteria: vec![
                Criterion {
                    field: "torrent_id".to_owned(),
                    op: Operation::Eq,
                    value: Value::S(resources[0].id().to_owned()),
                },
            ],
        };
        if let SMessage::OResourcesExtant { ids, .. } = c.rr(msg)? {
            get_resources(&mut c, ids)?
        } else {
            bail!("Could not get files for torrent!");
        }
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", name);
        return Ok(());
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            name
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
        return Ok(());
    };

    for file in files {
        let msg = CMessage::DownloadFile {
            serial: c.next_serial(),
            id: file.id().to_owned(),
        };
        if let SMessage::TransferOffer { token, .. } = c.rr(msg)? {
            let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
            let mut resp = client
                .get(url)
                .chain_err(|| ErrorKind::HTTP)?
                .header(header::Authorization(header::Bearer { token }))
                .send()
                .chain_err(|| ErrorKind::HTTP)?;
            if let Resource::File(f) = file {
                let p = Path::new(&f.path);
                if let Some(par) = p.parent() {
                    fs::create_dir_all(par).chain_err(|| ErrorKind::FileIO)?;
                }
                let mut f = fs::File::create(p).chain_err(|| ErrorKind::FileIO)?;
                io::copy(&mut resp, &mut f).chain_err(|| ErrorKind::FileIO)?;
            } else {
                bail!("Expected a file resource");
            }
        }
    }
    Ok(())
}

pub fn list(mut c: Client, kind: &str, crit: Vec<Criterion>, output: &str) -> Result<()> {
    let k = match kind {
        "torrent" => ResourceKind::Torrent,
        "tracker" => ResourceKind::Tracker,
        "peer" => ResourceKind::Peer,
        "piece" => ResourceKind::Piece,
        "file" => ResourceKind::File,
        "server" => ResourceKind::Server,
        _ => bail!("Unexpected resource kind {}", kind),
    };
    let results = search(&mut c, k, crit)?;
    if output == "text" {
        let mut table = Table::new();
        match k {
            ResourceKind::Torrent => {
                table.add_row(row!["Name", "Done", "DL", "UL", "DL RT", "UL RT", "Peers"]);
            }
            ResourceKind::Tracker => {
                table.add_row(row!["URL", "Torrent", "Error"]);
            }
            ResourceKind::Peer => {
                table.add_row(row!["IP", "Torrent", "DL RT", "UL RT"]);
            }
            ResourceKind::Piece => {
                table.add_row(row!["Torrent", "DLd", "Avail"]);
            }
            ResourceKind::File => {
                table.add_row(row!["Path", "Torrent", "Done", "Prio", "Avail"]);
            }
            ResourceKind::Server => {
                table.add_row(row!["DL RT", "UL RT"]);
            }
        }

        #[cfg_attr(rustfmt, rustfmt_skip)]
        for res in results {
            match k {
                ResourceKind::Torrent => {
                    let t = res.as_torrent();
                    table.add_row(row![
                        t.name,
                        format!("{:.2}%", t.progress * 100.),
                        fmt_bytes(t.transferred_down as f64),
                        fmt_bytes(t.transferred_up as f64),
                        fmt_bytes(t.rate_down as f64) + "/s",
                        fmt_bytes(t.rate_up as f64) + "/s",
                        t.peers
                    ]);
                }
                ResourceKind::Tracker => {
                    let t = res.as_tracker();
                    table.add_row(row![
                        t.url,
                        t.torrent_id,
                        t.error.as_ref().map(|s| s.as_str()).unwrap_or("")
                    ]);
                }
                ResourceKind::Peer => {
                    let p = res.as_peer();
                    let rd = fmt_bytes(p.rate_down as f64) + "/s";
                    let ru = fmt_bytes(p.rate_up as f64) + "/s";
                    table.add_row(row![p.ip, p.torrent_id, rd, ru]);
                }
                ResourceKind::Piece => {
                    let p = res.as_piece();
                    table.add_row(row![p.torrent_id, p.downloaded, p.available]);
                }
                ResourceKind::File => {
                    let f = res.as_file();
                    table.add_row(row![
                        f.path,
                        f.torrent_id,
                        format!("{:.2}%", f.progress as f64 * 100.),
                        f.priority,
                        format!("{:.2}%", f.availability as f64 * 100.)
                    ]);
                }
                ResourceKind::Server => {
                    let s = res.as_server();
                    let rd = fmt_bytes(s.rate_down as f64) + "/s";
                    let ru = fmt_bytes(s.rate_up as f64) + "/s";
                    table.add_row(row![rd, ru]);
                }
            }
        }
        table.printstd();
    } else {
        println!(
            "{}",
            serde_json::to_string_pretty(&results).chain_err(|| {
                ErrorKind::Serialization
            })?
        );
    }
    Ok(())
}

pub fn pause(mut c: Client, torrents: Vec<&str>) -> Result<()> {
    for torrent in torrents {
        pause_torrent(&mut c, torrent)?;
    }
    Ok(())
}

fn pause_torrent(c: &mut Client, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::PauseTorrent {
            serial: c.next_serial(),
            id: resources[0].id().to_owned(),
        };
        c.send(msg)?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

pub fn resume(mut c: Client, torrents: Vec<&str>) -> Result<()> {
    for torrent in torrents {
        resume_torrent(&mut c, torrent)?;
    }
    Ok(())
}

fn resume_torrent(c: &mut Client, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::ResumeTorrent {
            serial: c.next_serial(),
            id: resources[0].id().to_owned(),
        };
        c.send(msg)?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

fn search_torrent_name(c: &mut Client, name: &str) -> Result<Vec<Resource>> {
    search(
        c,
        ResourceKind::Torrent,
        vec![
            Criterion {
                field: "name".to_owned(),
                op: Operation::ILike,
                value: Value::S(format!("%{}%", name)),
            },
        ],
    )
}

fn search(c: &mut Client, kind: ResourceKind, criteria: Vec<Criterion>) -> Result<Vec<Resource>> {
    let s = c.next_serial();
    let msg = CMessage::FilterSubscribe {
        serial: s,
        kind,
        criteria,
    };
    if let SMessage::OResourcesExtant { ids, .. } = c.rr(msg)? {
        get_resources(c, ids)
    } else {
        bail!("Failed to receive extant resource list!");
    }
}

fn get_resources(c: &mut Client, ids: Vec<String>) -> Result<Vec<Resource>> {
    let msg = CMessage::Subscribe {
        serial: c.next_serial(),
        ids,
    };
    let resources = if let SMessage::UpdateResources { resources } = c.rr(msg)? {
        resources
    } else {
        bail!("Failed to received torrent resource list!");
    };

    let mut results = Vec::new();
    for r in resources {
        if let SResourceUpdate::OResource(res) = r {
            results.push(res);
        } else {
            bail!("Failed to received full resource!");
        }
    }
    Ok(results)
}

fn fmt_bytes(num: f64) -> String {
    let num = num.abs();
    let units = ["B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    if num < 1_f64 {
        return format!("{} {}", num, "B");
    }
    let delimiter = 1024_f64;
    let exponent = cmp::min(
        (num.ln() / delimiter.ln()).floor() as i32,
        (units.len() - 1) as i32,
    );
    let pretty_bytes = format!("{:.2}", num / delimiter.powi(exponent))
        .parse::<f64>()
        .unwrap() * 1_f64;
    let unit = units[exponent as usize];
    format!("{} {}", pretty_bytes, unit)
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::process::{Command, Stdio};
use std::env;

fn main() {
    // 1. Build the object file from source using node-gyp.
    build_object_file();

    // 2. Link the library from the object file using gcc.
    link_library();
}

fn build_object_file() {
    let npm_command = if cfg!(unix) { "npm" } else { "npm.cmd" };
    let node_gyp_command = if cfg!(unix) { "node-gyp" } else { "node-gyp.cmd" };

    // Ensure that all package.json dependencies and dev dependencies are installed.
    Command::new(npm_command).args(&["install", "--silent"]).status().ok().expect("Failed to run \"npm install\" for neon-sys!");

    // Run `node-gyp configure` (appending -d in debug mode).
    let configure_args = if debug() { vec!["configure", "-d"] } else { vec!["configure"] };
    let output = Command::new(node_gyp_command)
        .args(&configure_args)
        .output()
        .expect("Failed to run \"node-gyp configure\" for neon-sys!");

    if cfg!(windows) {
        let node_gyp_output = String::from_utf8_lossy(&output.stderr);
        let node_root_dir_flag_pattern = "'-Dnode_root_dir=";
        let node_root_dir_start_index = node_gyp_output
            .find(node_root_dir_flag_pattern)
            .map(|i| i + node_root_dir_flag_pattern.len())
            .expect("Couldn't find node_root_dir in node-gyp output.");
        let node_root_dir_end_index = node_gyp_output[node_root_dir_start_index..].find("'").unwrap() + node_root_dir_start_index;
        println!("cargo:node_root_dir={}", &node_gyp_output[node_root_dir_start_index..node_root_dir_end_index]);
    }

    // Run `node-gyp build` (appending -d in debug mode).
    let build_args = if debug() { vec!["build", "-d"] } else { vec!["build"] };
    Command::new(node_gyp_command)
        .stderr(Stdio::null()) // Prevent cargo build from hanging on Windows.
        .args(&build_args)
        .status()
        .ok()
        .expect("Failed to run \"node-gyp build\" for neon-sys!");
}

// Link the built object file into a static library.
fn link_library() {
    let configuration = if debug() { "Debug" } else { "Release" };
    let object_path = if cfg!(unix) {
        format!("build/{}/obj.target/neon/src/neon.o", configuration)
    } else {
        format!("build\\{}\\obj\\neon\\neon.obj", configuration)
    };

    gcc::Config::new().object(object_path).compile("libneon.a");
}

fn debug() -> bool {
    match env::var("DEBUG") {
        Ok(s) => s == "true",
        Err(_) => false
    }
}
<commit_msg>Temporarily build node bindings only against ia32 for testing<commit_after>extern crate gcc;

use std::process::{Command, Stdio};
use std::env;

fn main() {
    // 1. Build the object file from source using node-gyp.
    build_object_file();

    // 2. Link the library from the object file using gcc.
    link_library();
}

fn build_object_file() {
    let npm_command = if cfg!(unix) { "npm" } else { "npm.cmd" };
    let node_gyp_command = if cfg!(unix) { "node-gyp" } else { "node-gyp.cmd" };

    // Ensure that all package.json dependencies and dev dependencies are installed.
    Command::new(npm_command).args(&["install", "--silent"]).status().ok().expect("Failed to run \"npm install\" for neon-sys!");

    // Run `node-gyp configure` (appending -d in debug mode).
    let configure_args = if debug() { vec!["configure", "-d", "--arch=ia32"] } else { vec!["configure", "--arch=ia32"] };
    let output = Command::new(node_gyp_command)
        .args(&configure_args)
        .output()
        .expect("Failed to run \"node-gyp configure\" for neon-sys!");

    if cfg!(windows) {
        let node_gyp_output = String::from_utf8_lossy(&output.stderr);
        let node_root_dir_flag_pattern = "'-Dnode_root_dir=";
        let node_root_dir_start_index = node_gyp_output
            .find(node_root_dir_flag_pattern)
            .map(|i| i + node_root_dir_flag_pattern.len())
            .expect("Couldn't find node_root_dir in node-gyp output.");
        let node_root_dir_end_index = node_gyp_output[node_root_dir_start_index..].find("'").unwrap() + node_root_dir_start_index;
        println!("cargo:node_root_dir={}", &node_gyp_output[node_root_dir_start_index..node_root_dir_end_index]);
    }

    // Run `node-gyp build` (appending -d in debug mode).
    let build_args = if debug() { vec!["build", "-d"] } else { vec!["build"] };
    Command::new(node_gyp_command)
        .stderr(Stdio::null()) // Prevent cargo build from hanging on Windows.
        .args(&build_args)
        .status()
        .ok()
        .expect("Failed to run \"node-gyp build\" for neon-sys!");
}

// Link the built object file into a static library.
fn link_library() {
    let configuration = if debug() { "Debug" } else { "Release" };
    let object_path = if cfg!(unix) {
        format!("build/{}/obj.target/neon/src/neon.o", configuration)
    } else {
        format!("build\\{}\\obj\\neon\\neon.obj", configuration)
    };

    gcc::Config::new().object(object_path).compile("libneon.a");
}

fn debug() -> bool {
    match env::var("DEBUG") {
        Ok(s) => s == "true",
        Err(_) => false
    }
}
<|endoftext|>


<commit_before>use std::{
    hash::{Hash, Hasher},
    sync::Arc,
};

use ra_db::{FileId, salsa};
use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
use mbe::MacroRules;

use crate::{
    Module, DefDatabase, AstId, FileAstId,
};

/// hir makes heavy use of ids: integer (u32) handlers to various things. You
/// can think of id as a pointer (but without a lifetime) or a file descriptor
/// (but for hir objects).
///
/// This module defines a bunch of ids we are using. The most important ones are
/// probably `HirFileId` and `DefId`.

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &impl DefDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::File(file_id) => file_id,
            HirFileIdRepr::Macro(macro_call_id) => {
                let loc = macro_call_id.loc(db);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// XXX: this is a temporary function, which should go away when we implement the
    /// nameresolution+macro expansion combo. Prefer using `original_file` if
    /// possible.
    pub fn as_original_file(self) -> FileId {
        match self.0 {
            HirFileIdRepr::File(file_id) => file_id,
            HirFileIdRepr::Macro(_r) => panic!("macro generated file: {:?}", self),
        }
    }

    pub(crate) fn hir_parse_query(
        db: &impl DefDatabase,
        file_id: HirFileId,
    ) -> TreeArc<SourceFile> {
        match file_id.0 {
            HirFileIdRepr::File(file_id) => db.parse(file_id),
            HirFileIdRepr::Macro(macro_call_id) => {
                parse_macro(db, macro_call_id).unwrap_or_else(|err| {
                    // Note:
                    // The final goal we would like to make all parse_macro success,
                    // such that the following log will not call anyway.
                    log::warn!(
                        "fail on macro_parse: (reason: {}) {}",
                        err,
                        macro_call_id.debug_dump(db)
                    );

                    // returning an empty string looks fishy...
                    SourceFile::parse("")
                })
            }
        }
    }
}

fn parse_macro(
    db: &impl DefDatabase,
    macro_call_id: MacroCallId,
) -> Result<TreeArc<SourceFile>, String> {
    let loc = macro_call_id.loc(db);
    let macro_arg = db.macro_arg(macro_call_id).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;

    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }

    Ok(mbe::token_tree_to_ast_item_list(&tt))
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    File(FileId),
    Macro(MacroCallId),
}

impl From<FileId> for HirFileId {
    fn from(file_id: FileId) -> HirFileId {
        HirFileId(HirFileIdRepr::File(file_id))
    }
}

impl From<MacroCallId> for HirFileId {
    fn from(macro_call_id: MacroCallId) -> HirFileId {
        HirFileId(HirFileIdRepr::Macro(macro_call_id))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>);

pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
    let macro_call = id.0.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(arg).or_else(|| {
        log::warn!("fail on macro_def to token tree: {:#?}", arg);
        None
    })?;
    let rules = MacroRules::parse(&tt).ok().or_else(|| {
        log::warn!("fail on macro_def parse: {:#?}", tt);
        None
    })?;
    Some(Arc::new(rules))
}

pub(crate) fn macro_arg_query(db: &impl DefDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
    let loc = id.loc(db);
    let macro_call = loc.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(arg)?;
    Some(Arc::new(tt))
}

macro_rules! impl_intern_key {
    ($name:ident) => {
        impl salsa::InternKey for $name {
            fn from_intern_id(v: salsa::InternId) -> Self {
                $name(v)
            }
            fn as_intern_id(&self) -> salsa::InternId {
                self.0
            }
        }
    };
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl_intern_key!(MacroCallId);

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub(crate) def: MacroDefId,
    pub(crate) ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub(crate) fn loc(self, db: &impl DefDatabase) -> MacroCallLoc {
        db.lookup_intern_macro(self)
    }
}

impl MacroCallLoc {
    pub(crate) fn id(self, db: &impl DefDatabase) -> MacroCallId {
        db.intern_macro(self)
    }
}

#[derive(Debug)]
pub struct ItemLoc<N: AstNode> {
    pub(crate) module: Module,
    ast_id: AstId<N>,
}

impl<N: AstNode> PartialEq for ItemLoc<N> {
    fn eq(&self, other: &Self) -> bool {
        self.module == other.module && self.ast_id == other.ast_id
    }
}
impl<N: AstNode> Eq for ItemLoc<N> {}
impl<N: AstNode> Hash for ItemLoc<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.module.hash(hasher);
        self.ast_id.hash(hasher);
    }
}

impl<N: AstNode> Clone for ItemLoc<N> {
    fn clone(&self) -> ItemLoc<N> {
        ItemLoc { module: self.module, ast_id: self.ast_id }
    }
}

#[derive(Clone, Copy)]
pub(crate) struct LocationCtx<DB> {
    db: DB,
    module: Module,
    file_id: HirFileId,
}

impl<'a, DB: DefDatabase> LocationCtx<&'a DB> {
    pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
        LocationCtx { db, module, file_id }
    }
    pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
    where
        N: AstNode,
        DEF: AstItemDef<N>,
    {
        DEF::from_ast(self, ast)
    }
}

pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<N>) -> Self;
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<N>;

    fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self {
        let items = ctx.db.ast_id_map(ctx.file_id);
        let item_id = items.ast_id(ast);
        Self::from_ast_id(ctx, item_id)
    }
    fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self {
        let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
        Self::intern(ctx.db, loc)
    }
    fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) {
        let loc = self.lookup_intern(db);
        let ast = loc.ast_id.to_node(db);
        (loc.ast_id.file_id(), ast)
    }
    fn module(self, db: &impl DefDatabase) -> Module {
        let loc = self.lookup_intern(db);
        loc.module
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FunctionId(salsa::InternId);
impl_intern_key!(FunctionId);

impl AstItemDef<ast::FnDef> for FunctionId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
        db.intern_function(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::FnDef> {
        db.lookup_intern_function(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructId(salsa::InternId);
impl_intern_key!(StructId);
impl AstItemDef<ast::StructDef> for StructId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
        db.intern_struct(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StructDef> {
        db.lookup_intern_struct(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumId(salsa::InternId);
impl_intern_key!(EnumId);
impl AstItemDef<ast::EnumDef> for EnumId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
        db.intern_enum(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::EnumDef> {
        db.lookup_intern_enum(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConstId(salsa::InternId);
impl_intern_key!(ConstId);
impl AstItemDef<ast::ConstDef> for ConstId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
        db.intern_const(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::ConstDef> {
        db.lookup_intern_const(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StaticId(salsa::InternId);
impl_intern_key!(StaticId);
impl AstItemDef<ast::StaticDef> for StaticId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
        db.intern_static(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StaticDef> {
        db.lookup_intern_static(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TraitId(salsa::InternId);
impl_intern_key!(TraitId);
impl AstItemDef<ast::TraitDef> for TraitId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
        db.intern_trait(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TraitDef> {
        db.lookup_intern_trait(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeAliasId(salsa::InternId);
impl_intern_key!(TypeAliasId);
impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
        db.intern_type_alias(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TypeAliasDef> {
        db.lookup_intern_type_alias(self)
    }
}

impl MacroCallId {
    pub fn debug_dump(&self, db: &impl DefDatabase) -> String {
        let loc = self.clone().loc(db);
        let node = loc.ast_id.to_node(db);
        let syntax_str = node.syntax().text().chunks().collect::<Vec<_>>().join(" ");

        // dump the file name
        let file_id: HirFileId = self.clone().into();
        let original = file_id.original_file(db);
        let macro_rules = db.macro_def(loc.def);

        format!(
            "macro call [file: {:#?}] : {}\nhas rules: {}",
            db.file_relative_path(original),
            syntax_str,
            macro_rules.is_some()
        )
    }
}
<commit_msg>minor, move<commit_after>use std::{
    hash::{Hash, Hasher},
    sync::Arc,
};

use ra_db::{FileId, salsa};
use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
use mbe::MacroRules;

use crate::{
    Module, DefDatabase, AstId, FileAstId,
};

/// hir makes heavy use of ids: integer (u32) handlers to various things. You
/// can think of id as a pointer (but without a lifetime) or a file descriptor
/// (but for hir objects).
///
/// This module defines a bunch of ids we are using. The most important ones are
/// probably `HirFileId` and `DefId`.

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &impl DefDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::File(file_id) => file_id,
            HirFileIdRepr::Macro(macro_call_id) => {
                let loc = macro_call_id.loc(db);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// XXX: this is a temporary function, which should go away when we implement the
    /// nameresolution+macro expansion combo. Prefer using `original_file` if
    /// possible.
    pub fn as_original_file(self) -> FileId {
        match self.0 {
            HirFileIdRepr::File(file_id) => file_id,
            HirFileIdRepr::Macro(_r) => panic!("macro generated file: {:?}", self),
        }
    }

    pub(crate) fn hir_parse_query(
        db: &impl DefDatabase,
        file_id: HirFileId,
    ) -> TreeArc<SourceFile> {
        match file_id.0 {
            HirFileIdRepr::File(file_id) => db.parse(file_id),
            HirFileIdRepr::Macro(macro_call_id) => {
                parse_macro(db, macro_call_id).unwrap_or_else(|err| {
                    // Note:
                    // The final goal we would like to make all parse_macro success,
                    // such that the following log will not call anyway.
                    log::warn!(
                        "fail on macro_parse: (reason: {}) {}",
                        err,
                        macro_call_id.debug_dump(db)
                    );

                    // returning an empty string looks fishy...
                    SourceFile::parse("")
                })
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    File(FileId),
    Macro(MacroCallId),
}

impl From<FileId> for HirFileId {
    fn from(file_id: FileId) -> HirFileId {
        HirFileId(HirFileIdRepr::File(file_id))
    }
}

impl From<MacroCallId> for HirFileId {
    fn from(macro_call_id: MacroCallId) -> HirFileId {
        HirFileId(HirFileIdRepr::Macro(macro_call_id))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>);

pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
    let macro_call = id.0.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(arg).or_else(|| {
        log::warn!("fail on macro_def to token tree: {:#?}", arg);
        None
    })?;
    let rules = MacroRules::parse(&tt).ok().or_else(|| {
        log::warn!("fail on macro_def parse: {:#?}", tt);
        None
    })?;
    Some(Arc::new(rules))
}

pub(crate) fn macro_arg_query(db: &impl DefDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
    let loc = id.loc(db);
    let macro_call = loc.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(arg)?;
    Some(Arc::new(tt))
}

fn parse_macro(
    db: &impl DefDatabase,
    macro_call_id: MacroCallId,
) -> Result<TreeArc<SourceFile>, String> {
    let loc = macro_call_id.loc(db);
    let macro_arg = db.macro_arg(macro_call_id).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;

    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }

    Ok(mbe::token_tree_to_ast_item_list(&tt))
}

macro_rules! impl_intern_key {
    ($name:ident) => {
        impl salsa::InternKey for $name {
            fn from_intern_id(v: salsa::InternId) -> Self {
                $name(v)
            }
            fn as_intern_id(&self) -> salsa::InternId {
                self.0
            }
        }
    };
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl_intern_key!(MacroCallId);

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub(crate) def: MacroDefId,
    pub(crate) ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub(crate) fn loc(self, db: &impl DefDatabase) -> MacroCallLoc {
        db.lookup_intern_macro(self)
    }
}

impl MacroCallLoc {
    pub(crate) fn id(self, db: &impl DefDatabase) -> MacroCallId {
        db.intern_macro(self)
    }
}

#[derive(Debug)]
pub struct ItemLoc<N: AstNode> {
    pub(crate) module: Module,
    ast_id: AstId<N>,
}

impl<N: AstNode> PartialEq for ItemLoc<N> {
    fn eq(&self, other: &Self) -> bool {
        self.module == other.module && self.ast_id == other.ast_id
    }
}
impl<N: AstNode> Eq for ItemLoc<N> {}
impl<N: AstNode> Hash for ItemLoc<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.module.hash(hasher);
        self.ast_id.hash(hasher);
    }
}

impl<N: AstNode> Clone for ItemLoc<N> {
    fn clone(&self) -> ItemLoc<N> {
        ItemLoc { module: self.module, ast_id: self.ast_id }
    }
}

#[derive(Clone, Copy)]
pub(crate) struct LocationCtx<DB> {
    db: DB,
    module: Module,
    file_id: HirFileId,
}

impl<'a, DB: DefDatabase> LocationCtx<&'a DB> {
    pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
        LocationCtx { db, module, file_id }
    }
    pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
    where
        N: AstNode,
        DEF: AstItemDef<N>,
    {
        DEF::from_ast(self, ast)
    }
}

pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<N>) -> Self;
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<N>;

    fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self {
        let items = ctx.db.ast_id_map(ctx.file_id);
        let item_id = items.ast_id(ast);
        Self::from_ast_id(ctx, item_id)
    }
    fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self {
        let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
        Self::intern(ctx.db, loc)
    }
    fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) {
        let loc = self.lookup_intern(db);
        let ast = loc.ast_id.to_node(db);
        (loc.ast_id.file_id(), ast)
    }
    fn module(self, db: &impl DefDatabase) -> Module {
        let loc = self.lookup_intern(db);
        loc.module
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FunctionId(salsa::InternId);
impl_intern_key!(FunctionId);

impl AstItemDef<ast::FnDef> for FunctionId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
        db.intern_function(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::FnDef> {
        db.lookup_intern_function(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructId(salsa::InternId);
impl_intern_key!(StructId);
impl AstItemDef<ast::StructDef> for StructId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
        db.intern_struct(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StructDef> {
        db.lookup_intern_struct(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumId(salsa::InternId);
impl_intern_key!(EnumId);
impl AstItemDef<ast::EnumDef> for EnumId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
        db.intern_enum(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::EnumDef> {
        db.lookup_intern_enum(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConstId(salsa::InternId);
impl_intern_key!(ConstId);
impl AstItemDef<ast::ConstDef> for ConstId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
        db.intern_const(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::ConstDef> {
        db.lookup_intern_const(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StaticId(salsa::InternId);
impl_intern_key!(StaticId);
impl AstItemDef<ast::StaticDef> for StaticId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
        db.intern_static(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StaticDef> {
        db.lookup_intern_static(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TraitId(salsa::InternId);
impl_intern_key!(TraitId);
impl AstItemDef<ast::TraitDef> for TraitId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
        db.intern_trait(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TraitDef> {
        db.lookup_intern_trait(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeAliasId(salsa::InternId);
impl_intern_key!(TypeAliasId);
impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
        db.intern_type_alias(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TypeAliasDef> {
        db.lookup_intern_type_alias(self)
    }
}

impl MacroCallId {
    pub fn debug_dump(&self, db: &impl DefDatabase) -> String {
        let loc = self.clone().loc(db);
        let node = loc.ast_id.to_node(db);
        let syntax_str = node.syntax().text().chunks().collect::<Vec<_>>().join(" ");

        // dump the file name
        let file_id: HirFileId = self.clone().into();
        let original = file_id.original_file(db);
        let macro_rules = db.macro_def(loc.def);

        format!(
            "macro call [file: {:#?}] : {}\nhas rules: {}",
            db.file_relative_path(original),
            syntax_str,
            macro_rules.is_some()
        )
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! A library for configuring your servers.
//!
//! The library is organised into a set of _primitives_, which are
//! the building blocks for creating complex configurations.

#![recursion_limit = "1024"]

extern crate erased_serde;
#[macro_use] extern crate error_chain;
extern crate hostname;
extern crate ipnetwork;
extern crate pnet;
extern crate regex;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

pub mod command;
pub mod errors;
pub mod host;
mod target;
pub mod telemetry;

use errors::*;
use erased_serde::Serialize;

pub trait ExecutableProvider<'de>: serde::Serialize + serde::Deserialize<'de> {
    // @todo It'd be nice to return Result<Serialize> here someday...
    // See https://github.com/rust-lang/rfcs/issues/518.
    fn exec(self, &host::Host) -> Result<Box<Serialize>>;
}

#[derive(Serialize, Deserialize)]
pub enum RemoteProvider {
    Command(command::RemoteProvider),
    Telemetry(telemetry::RemoteProvider),
}

impl <'de>ExecutableProvider<'de> for RemoteProvider {
    fn exec(self, host: &host::Host) -> Result<Box<Serialize>> {
        match self {
            RemoteProvider::Command(p) => p.exec(host),
            RemoteProvider::Telemetry(p) => p.exec(host),
        }
    }
}
<commit_msg>Add prelude module to export common types<commit_after>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! A library for configuring your servers.
//!
//! The library is organised into a set of _primitives_, which are
//! the building blocks for creating complex configurations.

#![recursion_limit = "1024"]

extern crate erased_serde;
#[macro_use] extern crate error_chain;
extern crate hostname;
extern crate ipnetwork;
extern crate pnet;
extern crate regex;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

pub mod command;
pub mod errors;
pub mod host;
pub mod prelude {
    pub use command::Command;
    pub use host::Host;
    pub use telemetry::{Cpu, FsMount, Os, OsFamily, OsPlatform, Telemetry};
}
mod target;
pub mod telemetry;

use errors::*;
use erased_serde::Serialize;

pub trait ExecutableProvider<'de>: serde::Serialize + serde::Deserialize<'de> {
    // @todo It'd be nice to return Result<Serialize> here someday...
    // See https://github.com/rust-lang/rfcs/issues/518.
    fn exec(self, &host::Host) -> Result<Box<Serialize>>;
}

#[derive(Serialize, Deserialize)]
pub enum RemoteProvider {
    Command(command::RemoteProvider),
    Telemetry(telemetry::RemoteProvider),
}

impl <'de>ExecutableProvider<'de> for RemoteProvider {
    fn exec(self, host: &host::Host) -> Result<Box<Serialize>> {
        match self {
            RemoteProvider::Command(p) => p.exec(host),
            RemoteProvider::Telemetry(p) => p.exec(host),
        }
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use crate::{jsonrpc::client::utils::to_suffix_repr, stratis::StratisResult};

// stratis-min filesystem create
pub fn filesystem_create(pool_name: String, filesystem_name: String) -> StratisResult<()> {
    do_request_standard!(FsCreate, pool_name, filesystem_name)
}

// stratis-min filesystem [list]
pub fn filesystem_list() -> StratisResult<()> {
    let (pool_names, fs_names, used, created, paths, uuids) = do_request!(FsList);
    let used_formatted: Vec<_> = used
        .into_iter()
        .map(|u_opt| {
            u_opt
                .map(to_suffix_repr)
                .unwrap_or_else(|| "FAILURE".to_string())
        })
        .collect();
    let devices_formatted: Vec<_> = paths.into_iter().map(|p| p.display().to_string()).collect();
    let uuids_formatted: Vec<_> = uuids
        .into_iter()
        .map(|u| u.as_simple().to_string())
        .collect();
    print_table!(
        "Pool Name", pool_names, "<";
        "Name", fs_names, "<";
        "Used", used_formatted, "<";
        "Created", created, "<";
        "Device", devices_formatted, "<";
        "UUID", uuids_formatted, "<"
    );
    Ok(())
}

// stratis-min filesystem destroy
pub fn filesystem_destroy(pool_name: String, filesystem_name: String) -> StratisResult<()> {
    do_request_standard!(FsDestroy, pool_name, filesystem_name)
}

// stratis-min filesystem rename
pub fn filesystem_rename(
    pool_name: String,
    filesystem_name: String,
    new_filesystem_name: String,
) -> StratisResult<()> {
    do_request_standard!(FsRename, pool_name, filesystem_name, new_filesystem_name)
}
<commit_msg>Make stratis-min 'filesystem' UUID formatting consistent with 'pool'<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use crate::{jsonrpc::client::utils::to_suffix_repr, stratis::StratisResult};

// stratis-min filesystem create
pub fn filesystem_create(pool_name: String, filesystem_name: String) -> StratisResult<()> {
    do_request_standard!(FsCreate, pool_name, filesystem_name)
}

// stratis-min filesystem [list]
pub fn filesystem_list() -> StratisResult<()> {
    let (pool_names, fs_names, used, created, paths, uuids) = do_request!(FsList);
    let used_formatted: Vec<_> = used
        .into_iter()
        .map(|u_opt| {
            u_opt
                .map(to_suffix_repr)
                .unwrap_or_else(|| "FAILURE".to_string())
        })
        .collect();
    let devices_formatted: Vec<_> = paths.into_iter().map(|p| p.display().to_string()).collect();
    let uuids_formatted: Vec<_> = uuids.into_iter().map(|u| u.to_string()).collect();
    print_table!(
        "Pool Name", pool_names, "<";
        "Name", fs_names, "<";
        "Used", used_formatted, "<";
        "Created", created, "<";
        "Device", devices_formatted, "<";
        "UUID", uuids_formatted, "<"
    );
    Ok(())
}

// stratis-min filesystem destroy
pub fn filesystem_destroy(pool_name: String, filesystem_name: String) -> StratisResult<()> {
    do_request_standard!(FsDestroy, pool_name, filesystem_name)
}

// stratis-min filesystem rename
pub fn filesystem_rename(
    pool_name: String,
    filesystem_name: String,
    new_filesystem_name: String,
) -> StratisResult<()> {
    do_request_standard!(FsRename, pool_name, filesystem_name, new_filesystem_name)
}
<|endoftext|>


<commit_before>//! Activation Functions.
//!
//! This module contains a number of structs implementing the `ActivationFunc` trait.
//!
//! These structs are used within Neural Networks and
//! Generalized Linear Regression (not yet implemented).
//!
//! You can also create your own custom activation Functions for use in your models.
//! Just create a unit struct implementing the `ActivationFunc` trait.

/// Trait for activation functions in models.
pub trait ActivationFunc {
    /// The activation function.
    fn func(x: f64) -> f64;

    /// The gradient of the activation function.
    fn func_grad(x: f64) -> f64;

    /// The inverse of the activation function.
    fn func_inv(x: f64) -> f64;
}

/// Sigmoid activation function.
#[derive(Clone, Copy, Debug)]
pub struct Sigmoid;

impl ActivationFunc for Sigmoid {
    /// Sigmoid function.
    ///
    /// Returns 1 / ( 1 + e^-t).
    fn func(x: f64) -> f64 {
        1.0 / (1.0 + (-x).exp())
    }

    /// Gradient of sigmoid function.
    ///
    /// Evaluates to (1 - e^-t) / (1 + e^-t)^2
    fn func_grad(x: f64) -> f64 {
        Self::func(x) * (1f64 - Self::func(x))
    }

    fn func_inv(x: f64) -> f64 {
        (x / (1f64 - x)).ln()
    }
}

/// Linear activation function.
#[derive(Clone, Copy, Debug)]
pub struct Linear;

impl ActivationFunc for Linear {
    fn func(x: f64) -> f64 {
        x
    }

    fn func_grad(_: f64) -> f64 {
        1f64
    }

    fn func_inv(x: f64) -> f64 {
        x
    }
}

/// Exponential activation function.
#[derive(Clone, Copy, Debug)]
pub struct Exp;

impl ActivationFunc for Exp {
    fn func(x: f64) -> f64 {
        x.exp()
    }

    fn func_grad(x: f64) -> f64 {
        Self::func(x)
    }

    fn func_inv(x: f64) -> f64 {
        x.ln()
    }
}
<commit_msg>Added hyperbolic tangent activation function<commit_after>//! Activation Functions.
//!
//! This module contains a number of structs implementing the `ActivationFunc` trait.
//!
//! These structs are used within Neural Networks and
//! Generalized Linear Regression (not yet implemented).
//!
//! You can also create your own custom activation Functions for use in your models.
//! Just create a unit struct implementing the `ActivationFunc` trait.

/// Trait for activation functions in models.
pub trait ActivationFunc {
    /// The activation function.
    fn func(x: f64) -> f64;

    /// The gradient of the activation function.
    fn func_grad(x: f64) -> f64;

    /// The inverse of the activation function.
    fn func_inv(x: f64) -> f64;
}

/// Sigmoid activation function.
#[derive(Clone, Copy, Debug)]
pub struct Sigmoid;

impl ActivationFunc for Sigmoid {
    /// Sigmoid function.
    ///
    /// Returns 1 / ( 1 + e^-t).
    fn func(x: f64) -> f64 {
        1.0 / (1.0 + (-x).exp())
    }

    /// Gradient of sigmoid function.
    ///
    /// Evaluates to (1 - e^-t) / (1 + e^-t)^2
    fn func_grad(x: f64) -> f64 {
        Self::func(x) * (1f64 - Self::func(x))
    }

    fn func_inv(x: f64) -> f64 {
        (x / (1f64 - x)).ln()
    }
}

/// Linear activation function.
#[derive(Clone, Copy, Debug)]
pub struct Linear;

impl ActivationFunc for Linear {
    fn func(x: f64) -> f64 {
        x
    }

    fn func_grad(_: f64) -> f64 {
        1f64
    }

    fn func_inv(x: f64) -> f64 {
        x
    }
}

/// Exponential activation function.
#[derive(Clone, Copy, Debug)]
pub struct Exp;

impl ActivationFunc for Exp {
    fn func(x: f64) -> f64 {
        x.exp()
    }

    fn func_grad(x: f64) -> f64 {
        Self::func(x)
    }

    fn func_inv(x: f64) -> f64 {
        x.ln()
    }
}

/// Hyperbolic tangent activation function
#[derive(Clone, Copy, Debug)]
pub struct Tanh;

impl ActivationFunc for Tanh {
    fn func(x: f64) -> f64 {
        x.tanh()
    }

    fn func_grad(x: f64) -> f64 {
        let y = x.tanh();
        1.0 - y*y
    }

    fn func_inv(x: f64) -> f64 {
        0.5*((1.0+x)/(1.0-x)).ln()
    }
}<|endoftext|>


<commit_before>use crate::ops::{Deref, DerefMut};
use crate::ptr;

/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
///
/// This wrapper is 0-cost.
///
/// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
/// As a consequence, it has *no effect* on the assumptions that the compiler makes
/// about its contents. For example, initializing a `ManuallyDrop<&mut T>`
/// with [`mem::zeroed`] is undefined behavior.
/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
///
/// # Examples
///
/// This wrapper can be used to enforce a particular drop order on fields, regardless
/// of how they are defined in the struct:
///
/// ```rust
/// use std::mem::ManuallyDrop;
/// struct Peach;
/// struct Banana;
/// struct Melon;
/// struct FruitBox {
///     // Immediately clear there’s something non-trivial going on with these fields.
///     peach: ManuallyDrop<Peach>,
///     melon: Melon, // Field that’s independent of the other two.
///     banana: ManuallyDrop<Banana>,
/// }
///
/// impl Drop for FruitBox {
///     fn drop(&mut self) {
///         unsafe {
///             // Explicit ordering in which field destructors are run specified in the intuitive
///             // location – the destructor of the structure containing the fields.
///             // Moreover, one can now reorder fields within the struct however much they want.
///             ManuallyDrop::drop(&mut self.peach);
///             ManuallyDrop::drop(&mut self.banana);
///         }
///         // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
///         // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
///     }
/// }
/// ```
///
/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
/// would also be leaked.
///
/// In contrast, the automatically-generated compiler drop implementation would have ensured
/// that all fields are dropped even in the presence of panics. This is especially important when
/// working with [pinned] data, where reusing the memory without calling the destructor could lead
/// to Undefined Behaviour.
///
/// [`mem::zeroed`]: fn.zeroed.html
/// [`MaybeUninit<T>`]: union.MaybeUninit.html
/// [pinned]: ../pin/index.html
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ManuallyDrop<T: ?Sized> {
    value: T,
}

impl<T> ManuallyDrop<T> {
    /// Wrap a value to be manually dropped.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// ManuallyDrop::new(Box::new(()));
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
    #[inline(always)]
    pub const fn new(value: T) -> ManuallyDrop<T> {
        ManuallyDrop { value }
    }

    /// Extracts the value from the `ManuallyDrop` container.
    ///
    /// This allows the value to be dropped again.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// let x = ManuallyDrop::new(Box::new(()));
    /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`.
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
    #[inline(always)]
    pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
        slot.value
    }

    /// Takes the value from the `ManuallyDrop<T>` container out.
    ///
    /// This method is primarily intended for moving out values in drop.
    /// Instead of using [`ManuallyDrop::drop`] to manually drop the value,
    /// you can use this method to take the value and use it however desired.
    ///
    /// Whenever possible, it is preferable to use [`into_inner`][`ManuallyDrop::into_inner`]
    /// instead, which prevents duplicating the content of the `ManuallyDrop<T>`.
    ///
    /// # Safety
    ///
    /// This function semantically moves out the contained value without preventing further usage,
    /// leaving the state of this container unchanged.
    /// It is your responsibility to ensure that this `ManuallyDrop` is not used again.
    ///
    /// [`ManuallyDrop::drop`]: #method.drop
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"]
    #[stable(feature = "manually_drop_take", since = "1.42.0")]
    #[inline]
    pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
        ptr::read(&slot.value)
    }
}

impl<T: ?Sized> ManuallyDrop<T> {
    /// Manually drops the contained value. This is exactly equivalent to calling
    /// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless
    /// the contained value is a packed struct, the destructor will be called in-place
    /// without moving the value, and thus can be used to safely drop [pinned] data.
    ///
    /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
    ///
    /// # Safety
    ///
    /// This function runs the destructor of the contained value. Other than changes made by
    /// the destructor itself, the memory is left unchanged, and so as far as the compiler is
    /// concerned still holds a bit-pattern which is valid for the type `T`.
    ///
    /// However, this "zombie" value should not be exposed to safe code, and this function
    /// should not be called more than once. To use a value after it's been dropped, or drop
    /// a value multiple times, can cause Undefined Behavior (depending on what `drop` does).
    /// This is normally prevented by the type system, but users of `ManuallyDrop` must
    /// uphold those guarantees without assistance from the compiler.
    ///
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    /// [`ptr::drop_in_place`]: ../ptr/fn.drop_in_place.html
    /// [pinned]: ../pin/index.html
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline]
    pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
        ptr::drop_in_place(&mut slot.value)
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> Deref for ManuallyDrop<T> {
    type Target = T;
    #[inline(always)]
    fn deref(&self) -> &T {
        &self.value
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}
<commit_msg>emphasize that ManuallyDrop is safe-to-access and unsafe-to-drop<commit_after>use crate::ops::{Deref, DerefMut};
use crate::ptr;

/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
/// This wrapper is 0-cost.
///
/// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
/// As a consequence, it has *no effect* on the assumptions that the compiler makes
/// about its contents. For example, initializing a `ManuallyDrop<&mut T>`
/// with [`mem::zeroed`] is undefined behavior.
/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
///
/// Note that accessing the value inside a `ManuallyDrop<T>` is safe.
/// This means that a `ManuallyDrop<T>` whose content has been dropped must not
/// be exposed through a public safe API.
/// Correspondingly, `ManuallyDrop::drop` is unsafe.
///
/// # Examples
///
/// This wrapper can be used to enforce a particular drop order on fields, regardless
/// of how they are defined in the struct:
///
/// ```rust
/// use std::mem::ManuallyDrop;
/// struct Peach;
/// struct Banana;
/// struct Melon;
/// struct FruitBox {
///     // Immediately clear there’s something non-trivial going on with these fields.
///     peach: ManuallyDrop<Peach>,
///     melon: Melon, // Field that’s independent of the other two.
///     banana: ManuallyDrop<Banana>,
/// }
///
/// impl Drop for FruitBox {
///     fn drop(&mut self) {
///         unsafe {
///             // Explicit ordering in which field destructors are run specified in the intuitive
///             // location – the destructor of the structure containing the fields.
///             // Moreover, one can now reorder fields within the struct however much they want.
///             ManuallyDrop::drop(&mut self.peach);
///             ManuallyDrop::drop(&mut self.banana);
///         }
///         // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
///         // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
///     }
/// }
/// ```
///
/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
/// would also be leaked.
///
/// In contrast, the automatically-generated compiler drop implementation would have ensured
/// that all fields are dropped even in the presence of panics. This is especially important when
/// working with [pinned] data, where reusing the memory without calling the destructor could lead
/// to Undefined Behaviour.
///
/// [`mem::zeroed`]: fn.zeroed.html
/// [`MaybeUninit<T>`]: union.MaybeUninit.html
/// [pinned]: ../pin/index.html
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ManuallyDrop<T: ?Sized> {
    value: T,
}

impl<T> ManuallyDrop<T> {
    /// Wrap a value to be manually dropped.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// ManuallyDrop::new(Box::new(()));
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
    #[inline(always)]
    pub const fn new(value: T) -> ManuallyDrop<T> {
        ManuallyDrop { value }
    }

    /// Extracts the value from the `ManuallyDrop` container.
    ///
    /// This allows the value to be dropped again.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// let x = ManuallyDrop::new(Box::new(()));
    /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`.
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
    #[inline(always)]
    pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
        slot.value
    }

    /// Takes the value from the `ManuallyDrop<T>` container out.
    ///
    /// This method is primarily intended for moving out values in drop.
    /// Instead of using [`ManuallyDrop::drop`] to manually drop the value,
    /// you can use this method to take the value and use it however desired.
    ///
    /// Whenever possible, it is preferable to use [`into_inner`][`ManuallyDrop::into_inner`]
    /// instead, which prevents duplicating the content of the `ManuallyDrop<T>`.
    ///
    /// # Safety
    ///
    /// This function semantically moves out the contained value without preventing further usage,
    /// leaving the state of this container unchanged.
    /// It is your responsibility to ensure that this `ManuallyDrop` is not used again.
    ///
    /// [`ManuallyDrop::drop`]: #method.drop
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"]
    #[stable(feature = "manually_drop_take", since = "1.42.0")]
    #[inline]
    pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
        ptr::read(&slot.value)
    }
}

impl<T: ?Sized> ManuallyDrop<T> {
    /// Manually drops the contained value. This is exactly equivalent to calling
    /// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless
    /// the contained value is a packed struct, the destructor will be called in-place
    /// without moving the value, and thus can be used to safely drop [pinned] data.
    ///
    /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
    ///
    /// # Safety
    ///
    /// This function runs the destructor of the contained value. Other than changes made by
    /// the destructor itself, the memory is left unchanged, and so as far as the compiler is
    /// concerned still holds a bit-pattern which is valid for the type `T`.
    ///
    /// However, this "zombie" value should not be exposed to safe code, and this function
    /// should not be called more than once. To use a value after it's been dropped, or drop
    /// a value multiple times, can cause Undefined Behavior (depending on what `drop` does).
    /// This is normally prevented by the type system, but users of `ManuallyDrop` must
    /// uphold those guarantees without assistance from the compiler.
    ///
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    /// [`ptr::drop_in_place`]: ../ptr/fn.drop_in_place.html
    /// [pinned]: ../pin/index.html
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline]
    pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
        ptr::drop_in_place(&mut slot.value)
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> Deref for ManuallyDrop<T> {
    type Target = T;
    #[inline(always)]
    fn deref(&self) -> &T {
        &self.value
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use dot;
use rustc::mir::repr::*;
use std::borrow::IntoCow;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct EdgeIndex {
    source: BasicBlock,
    target: BasicBlock,
    index: usize,
}

impl<'a,'tcx> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
    fn graph_id(&'a self) -> dot::Id<'a> {
        dot::Id::new("Mir").unwrap()
    }

    fn node_id(&'a self, n: &BasicBlock) -> dot::Id<'a> {
        dot::Id::new(format!("BB{}", n.index())).unwrap()
    }

    fn node_shape(&'a self, _: &BasicBlock) -> Option<dot::LabelText<'a>> {
        Some(dot::LabelText::label("none"))
    }

    fn node_label(&'a self, &n: &BasicBlock) -> dot::LabelText<'a> {
        let mut buffer = String::new();
        buffer.push_str("
");

        buffer.push_str("
");
        buffer.push_str(&format!("{:?}", n));
        buffer.push_str("
");

        let data = self.basic_block_data(n);
        for statement in &data.statements {
            buffer.push_str("
");
            buffer.push_str(&escape(format!("{:?}", statement)));
            buffer.push_str("
");
        }

        buffer.push_str("
");
        buffer.push_str(&escape(format!("{:?}", &data.terminator)));
        buffer.push_str("
");

        buffer.push_str("
");

        dot::LabelText::html(buffer)
    }

    fn edge_label(&'a self, edge: &EdgeIndex) -> dot::LabelText<'a> {
        dot::LabelText::label(format!("{}", edge.index))
    }
}

impl<'a,'tcx> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
    fn nodes(&'a self) -> dot::Nodes<'a, BasicBlock> {
        self.all_basic_blocks().into_cow()
    }

    fn edges(&'a self) -> dot::Edges<'a, EdgeIndex> {
        self.all_basic_blocks()
            .into_iter()
            .flat_map(|source| {
                self.basic_block_data(source)
                    .terminator
                    .successors()
                    .iter()
                    .enumerate()
                    .map(move |(index, &target)| {
                        EdgeIndex {
                            source: source,
                            target: target,
                            index: index,
                        }
                    })
            })
            .collect::<Vec<_>>()
            .into_cow()
    }

    fn source(&'a self, edge: &EdgeIndex) -> BasicBlock {
        edge.source
    }

    fn target(&'a self, edge: &EdgeIndex) -> BasicBlock {
        edge.target
    }
}

fn escape(text: String) -> String {
    let text = dot::escape_html(&text);
    let text = all_to_subscript("Temp", text);
    let text = all_to_subscript("Var", text);
    let text = all_to_subscript("Arg", text);
    let text = all_to_subscript("BB", text);
    text
}

/// A call like `all_to_subscript("Temp", "Temp(123)")` will convert
/// to `Temp₁₂₃`.
fn all_to_subscript(header: &str, mut text: String) -> String {
    let mut offset = 0;
    while offset < text.len() {
        if let Some(text1) = to_subscript1(header, &text, &mut offset) {
            text = text1;
        }
    }
    return text;

    /// Looks for `Foo(\d*)` where `header=="Foo"` and replaces the `\d` with subscripts.
    /// Updates `offset` to point to the next location where we might want to search.
    /// Returns an updated string if changes were made, else None.
    fn to_subscript1(header: &str, text: &str, offset: &mut usize) -> Option<String> {
        let a = match text[*offset..].find(header) {
            None => {
                *offset = text.len();
                return None;
            }
            Some(a) => a + *offset,
        };

        // Example:
        //
        // header: "Foo"
        // text:   ....Foo(123)...
        //             ^  ^
        //             a  b

        let b = a + header.len();
        *offset = b;

        let mut chars = text[b..].chars();
        if Some('(') != chars.next() {
            return None;
        }

        let mut result = String::new();
        result.push_str(&text[..b]);

        while let Some(c) = chars.next() {
            if c == ')' {
                break;
            }
            if !c.is_digit(10) {
                return None;
            }

            // 0x208 is _0 in unicode, 0x209 is _1, etc
            const SUBSCRIPTS: &'static str = "₀₁₂₃₄₅₆₇₈₉";
            let n = (c as usize) - ('0' as usize);
            result.extend(SUBSCRIPTS.chars().skip(n).take(1));
        }

        result.extend(chars);
        return Some(result);
    }
}
<commit_msg>Prettify MIR graphviz output<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use dot;
use rustc::mir::repr::*;
use std::borrow::IntoCow;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct EdgeIndex {
    source: BasicBlock,
    target: BasicBlock,
    index: usize,
}

impl<'a,'tcx> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
    fn graph_id(&'a self) -> dot::Id<'a> {
        dot::Id::new("Mir").unwrap()
    }

    fn node_id(&'a self, n: &BasicBlock) -> dot::Id<'a> {
        dot::Id::new(format!("BB{}", n.index())).unwrap()
    }

    fn node_shape(&'a self, _: &BasicBlock) -> Option<dot::LabelText<'a>> {
        Some(dot::LabelText::label("none"))
    }

    fn node_label(&'a self, &n: &BasicBlock) -> dot::LabelText<'a> {
        let mut buffer = String::new();
        buffer.push_str("
");

        buffer.push_str("
");
        buffer.push_str(&escape(format!("{:?}", n)));
        buffer.push_str("
");

        let data = self.basic_block_data(n);
        for statement in &data.statements {
            buffer.push_str("
");
            buffer.push_str(&escape(format!("{:?}", statement)));
            buffer.push_str("
");
        }

        buffer.push_str("
");
        buffer.push_str(&escape(format!("{:?}", &data.terminator)));
        buffer.push_str("
");

        buffer.push_str("
");

        dot::LabelText::html(buffer)
    }

    fn edge_label(&'a self, edge: &EdgeIndex) -> dot::LabelText<'a> {
        dot::LabelText::label(format!("{}", edge.index))
    }
}

impl<'a,'tcx> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
    fn nodes(&'a self) -> dot::Nodes<'a, BasicBlock> {
        self.all_basic_blocks().into_cow()
    }

    fn edges(&'a self) -> dot::Edges<'a, EdgeIndex> {
        self.all_basic_blocks()
            .into_iter()
            .flat_map(|source| {
                self.basic_block_data(source)
                    .terminator
                    .successors()
                    .iter()
                    .enumerate()
                    .map(move |(index, &target)| {
                        EdgeIndex {
                            source: source,
                            target: target,
                            index: index,
                        }
                    })
            })
            .collect::<Vec<_>>()
            .into_cow()
    }

    fn source(&'a self, edge: &EdgeIndex) -> BasicBlock {
        edge.source
    }

    fn target(&'a self, edge: &EdgeIndex) -> BasicBlock {
        edge.target
    }
}

fn escape(text: String) -> String {
    let text = dot::escape_html(&text);
    let text = all_to_subscript("Temp", text);
    let text = all_to_subscript("Var", text);
    let text = all_to_subscript("Arg", text);
    let text = all_to_subscript("BB", text);
    text
}

/// A call like `all_to_subscript("Temp", "Temp(123)")` will convert
/// to `Temp₁₂₃`.
fn all_to_subscript(header: &str, mut text: String) -> String {
    let mut offset = 0;
    while offset < text.len() {
        if let Some(text1) = to_subscript1(header, &text, &mut offset) {
            text = text1;
        }
    }
    return text;

    /// Looks for `Foo(\d*)` where `header=="Foo"` and replaces the `\d` with subscripts.
    /// Updates `offset` to point to the next location where we might want to search.
    /// Returns an updated string if changes were made, else None.
    fn to_subscript1(header: &str, text: &str, offset: &mut usize) -> Option<String> {
        let a = match text[*offset..].find(header) {
            None => {
                *offset = text.len();
                return None;
            }
            Some(a) => a + *offset,
        };

        // Example:
        //
        // header: "Foo"
        // text:   ....Foo(123)...
        //             ^  ^
        //             a  b

        let b = a + header.len();
        *offset = b;

        let mut chars = text[b..].chars();
        if Some('(') != chars.next() {
            return None;
        }

        let mut result = String::new();
        result.push_str(&text[..b]);

        while let Some(c) = chars.next() {
            if c == ')' {
                break;
            }
            if !c.is_digit(10) {
                return None;
            }

            // 0x208 is _0 in unicode, 0x209 is _1, etc
            const SUBSCRIPTS: &'static str = "₀₁₂₃₄₅₆₇₈₉";
            let n = (c as usize) - ('0' as usize);
            result.extend(SUBSCRIPTS.chars().skip(n).take(1));
        }

        result.extend(chars);
        return Some(result);
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with devices.

use std::{fs::File, os::unix::prelude::AsRawFd};

use devicemapper::Bytes;

use crate::stratis::{StratisError, StratisResult};

ioctl_read!(
    /// # Safety
    ///
    /// This function is a wrapper for `libc::ioctl` and therefore is unsafe for the same reasons
    /// as other libc bindings. It accepts a file descriptor and mutable pointer so the semantics
    /// of the invoked `ioctl` command should be examined to determine the effect it will have
    /// on the resources passed to the command.
    blkgetsize64,
    0x12,
    114,
    u64
);

pub fn blkdev_size(file: &File) -> StratisResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(StratisError::Nix(x)),
        Ok(_) => Ok(Bytes::from(val)),
    }
}
<commit_msg>Remove a bunch of safety notes<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with devices.

use std::{fs::File, os::unix::prelude::AsRawFd};

use devicemapper::Bytes;

use crate::stratis::{StratisError, StratisResult};

ioctl_read!(blkgetsize64, 0x12, 114, u64);

pub fn blkdev_size(file: &File) -> StratisResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(StratisError::Nix(x)),
        Ok(_) => Ok(Bytes::from(val)),
    }
}
<|endoftext|>


<commit_before>//! Contains AST transformers such as Linters and Optimizers that can be run on an AST and report
//! warnings or mutate it.

use ::Warning;
use ast::Function;

use std::collections::HashMap;

pub mod deprecated_ops;
pub mod fold;
pub mod globalwrite;

/// Transform function used by Linters and Optimizers
pub type Transform = for<'a> fn(Function<'a>) -> (Function<'a>, Vec<Warning>);

/// Specifies how a Lint's (or Optimizer's) emitted warnings should be handled by the compiler.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum LintMode {
    /// The warnings will be ignored and not returned to the caller.
    Ignore,
    /// The warnings will be returned to the caller. It is up to them to handle / print them.
    Warn,
    /// Any warning emitted by this Lint will cause a compilation error.
    Error,
}

/// Creates a `HashMap` that maps the given name to the `run` function declared in the module with
/// the same name (`run` must have a compatible signature).
macro_rules! transform_map {
    ( $( $name:ident, )* ) => {{
        let mut map = HashMap::new();
        $( map.insert(stringify!($name), $name::run as Transform); )*

        map
    }};
}

/// Creates a vector of 2-tuples, containing the transform function and default severity of
/// warnings returned by the function.
macro_rules! transform_vec {
    ( $( $name:ident : $mode:ident, )* ) => {{
        vec![
            $( (stringify!($name), LintMode::$mode), )*
        ]
    }};
}

/// `TRANSFORMS` contains all transformations that can be applied to an AST.
lazy_static! {
    pub static ref TRANSFORMS: HashMap<&'static str, Transform> = transform_map! {
        deprecated_ops,
        fold,
        globalwrite,
    };
}

/// `TRANSFORMS_DEFAULT` is the default set of transforms to apply when compiling Lea code.
lazy_static! {
    pub static ref TRANSFORMS_DEFAULT: Vec<(&'static str, LintMode)> = transform_vec! [
        deprecated_ops: Warn,
        globalwrite: Warn,
        fold: Ignore,
    ];
}

/// `TRANSFORMS_COMPAT` is a list of transforms to apply when compiling in compatibility mode (ie
/// Lua code).
lazy_static! {
    pub static ref TRANSFORMS_COMPAT: Vec<(&'static str, LintMode)> = transform_vec! [
        fold: Ignore,
    ];
}
<commit_msg>Added thoughts about a proper lint interface<commit_after>//! Contains AST transformers such as Linters and Optimizers that can be run on an AST and report
//! warnings or mutate it.

// TODO Add a proper Lint/Optimizer interface (although we probably don't need an optimizer interface at all)
// Some thoughts:
// * Lints are named and may be en-/disabled via cmd line switches
// * Foreign code can register own Lints and register them to be run just like the builtin Lints
// * Pass some object to Lints that allows emitting warnings (less overhead when warnings are
//   disabled for that lint; no need to store a `Vec<Warning>` inside each Lint)
// * Lints implement Visitor, not Transform (they should be forced to take a `&Function`)
// * Lints may be executed in parallel (and even parallel to code emission), but this won't
//   necessarily make anything faster (it might, when many lints are run and the AST is large -
//   need a heuristic for this!)
// * We can only do a few optimizations. Lea is completely dynamic, so constant folding and simple
//   DCE is probably all we can do (inlining of local function could be done, too, but is probably
//   not worth it)

use ::Warning;
use ast::Function;

use std::collections::HashMap;

pub mod deprecated_ops;
pub mod fold;
pub mod globalwrite;

/// Transform function used by Linters and Optimizers
pub type Transform = for<'a> fn(Function<'a>) -> (Function<'a>, Vec<Warning>);

/// Specifies how a Lint's (or Optimizer's) emitted warnings should be handled by the compiler.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum LintMode {
    /// The warnings will be ignored and not returned to the caller.
    Ignore,
    /// The warnings will be returned to the caller. It is up to them to handle / print them.
    Warn,
    /// Any warning emitted by this Lint will cause a compilation error.
    Error,
}

/// Creates a `HashMap` that maps the given name to the `run` function declared in the module with
/// the same name (`run` must have a compatible signature).
macro_rules! transform_map {
    ( $( $name:ident, )* ) => {{
        let mut map = HashMap::new();
        $( map.insert(stringify!($name), $name::run as Transform); )*

        map
    }};
}

/// Creates a vector of 2-tuples, containing the transform function and default severity of
/// warnings returned by the function.
macro_rules! transform_vec {
    ( $( $name:ident : $mode:ident, )* ) => {{
        vec![
            $( (stringify!($name), LintMode::$mode), )*
        ]
    }};
}

/// `TRANSFORMS` contains all transformations that can be applied to an AST.
lazy_static! {
    pub static ref TRANSFORMS: HashMap<&'static str, Transform> = transform_map! {
        deprecated_ops,
        fold,
        globalwrite,
    };
}

/// `TRANSFORMS_DEFAULT` is the default set of transforms to apply when compiling Lea code.
lazy_static! {
    pub static ref TRANSFORMS_DEFAULT: Vec<(&'static str, LintMode)> = transform_vec! [
        deprecated_ops: Warn,
        globalwrite: Warn,
        fold: Ignore,
    ];
}

/// `TRANSFORMS_COMPAT` is a list of transforms to apply when compiling in compatibility mode (ie
/// Lua code).
lazy_static! {
    pub static ref TRANSFORMS_COMPAT: Vec<(&'static str, LintMode)> = transform_vec! [
        fold: Ignore,
    ];
}
<|endoftext|>