<commit_before>extern crate rust_playpen;

#[macro_use] extern crate iron;
extern crate hyper;
extern crate staticfile;
extern crate router;
extern crate unicase;
extern crate rustc_serialize;

use rust_playpen::*;

use iron::prelude::*;
use iron::status;
use iron::headers;
use iron::middleware::AfterMiddleware;
use iron::modifiers::Header;
use iron::method::Method;
use hyper::header;
use staticfile::Static;
use router::Router;
use unicase::UniCase;
use rustc_serialize::json;

use std::fmt;
use std::path::Path;
use std::io::Read;
use std::process::Command;

#[derive(Clone, Debug)]
struct XXssProtection(bool);

impl header::Header for XXssProtection {
    fn header_name() -> &'static str {
        "X-XSS-Protection"
    }

    fn parse_header(raw: &[Vec<u8>]) -> hyper::Result<Self> {
        if raw.len() == 1 {
            let line = &raw[0];
            if line.len() == 1 {
                let byte = line[0];
                match byte {
                    b'1' => return Ok(XXssProtection(true)),
                    b'0' => return Ok(XXssProtection(false)),
                    _ => ()
                }
            }
        }
        Err(hyper::Error::Header)
    }
}

impl header::HeaderFormat for XXssProtection {
    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.0 {
            f.write_str("1")
        } else {
            f.write_str("0")
        }
    }
}

fn index(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((Path::new("static/web.html"),
                       Header(XXssProtection(false)))))
}

/// The JSON-encoded request sent to `evaluate.json`.
#[derive(RustcDecodable)]
struct EvaluateReq {
    color: Option<bool>,
    test: Option<bool>,
    version: Option<String>,
    optimize: Option<String>,
    separate_output: Option<bool>,
    code: String,
}

fn evaluate(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    itry!(req.body.read_to_string(&mut body));

    let data: EvaluateReq = itry!(json::decode(&body));
    let color = data.color.unwrap_or(false);
    let test = data.test.unwrap_or(false);
    let version = itry!(data.version.map(|v| v.parse()).unwrap_or(Ok(ReleaseChannel::Stable)));
    let opt = itry!(data.optimize.map(|opt| opt.parse()).unwrap_or(Ok(OptLevel::O2)));
    let separate_output = data.separate_output.unwrap_or(false);

    let mut args = vec![String::from("-C"), format!("opt-level={}", opt.as_u8())];
    if opt == OptLevel::O0 {
        args.push(String::from("-g"));
    }
    if color {
        args.push(String::from("--color=always"));
    }
    if test {
        args.push(String::from("--test"));
    }

    let (_status, output) = itry!(
        rust_playpen::exec(version, "/usr/local/bin/evaluate.sh", args, data.code));

    if separate_output {
        // {"rustc": "...", "program": "..."}
        let mut split = output.splitn(2, |b| *b == b'\xff');
        let rustc = String::from_utf8(split.next().unwrap().into()).unwrap();

        let mut obj = json::Object::new();
        obj.insert(String::from("rustc"), json::Json::String(rustc));

        if let Some(program) = split.next() {
            // Compilation succeeded
            let output = String::from_utf8_lossy(program).into_owned();
            obj.insert(String::from("program"), json::Json::String(output));
        }

        Ok(Response::with((status::Ok, format!("{}", json::Json::Object(obj)))))
    } else {
        // {"result": "..."}
        // TODO
        unimplemented!()
    }
}

#[derive(RustcDecodable)]
struct CompileReq {
    syntax: Option<String>,
    color: Option<bool>,
    version: Option<String>,
    optimize: Option<String>,
    emit: Option<String>,
    code: String,
}

fn compile(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    itry!(req.body.read_to_string(&mut body));

    let data: CompileReq = itry!(json::decode(&body));
    let syntax = data.syntax.map(|s| s.parse().unwrap()).unwrap_or(AsmFlavor::Att);
    let color = data.color.unwrap_or(false);
    let version = itry!(data.version.map(|v| v.parse()).unwrap_or(Ok(ReleaseChannel::Stable)));
    let opt = itry!(data.optimize.map(|opt| opt.parse()).unwrap_or(Ok(OptLevel::O2)));
    let emit = itry!(data.emit.map(|emit| emit.parse()).unwrap_or(Ok(CompileOutput::Asm)));

    let mut args = vec![
        String::from("-C"),
        format!("opt-level={}", opt.as_u8()),
        String::from("-C"),
        format!("llvm-args=-x86-asm-syntax={}", syntax.as_str()),
    ];
    for opt in emit.as_opts() {
        args.push(String::from(*opt));
    }
    if opt == OptLevel::O0 {
        args.push(String::from("-g"));
    }
    if color {
        args.push(String::from("--color=always"));
    }

    let (_status, output) = itry!(
        rust_playpen::exec(version, "/usr/local/bin/compile.sh", args, data.code));
    let mut split = output.splitn(2, |b| *b == b'\xff');
    let rustc = String::from_utf8(split.next().unwrap().into()).unwrap();

    let mut obj = json::Object::new();;
    match split.next() {
        Some(program_out) => {
            // Compilation succeeded
            let output = highlight(emit,
                                   &String::from_utf8_lossy(program_out).into_owned());
            obj.insert(String::from("result"), json::Json::String(output));
        }
        None => {
            obj.insert(String::from("error"), json::Json::String(rustc));
        }
    }

    Ok(Response::with((status::Ok, format!("{}", json::Json::Object(obj)))))
}

#[derive(RustcDecodable)]
struct FormatReq {
    version: Option<String>,
    code: String,
}

fn format(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    req.body.read_to_string(&mut body).unwrap();

    let data: FormatReq = itry!(json::decode(&body));
    let version = itry!(data.version.map(|v| v.parse()).unwrap_or(Ok(ReleaseChannel::Stable)));

    let (status, output) = itry!(
        rust_playpen::exec(version, "/usr/bin/rustfmt", Vec::new(), data.code));
    let output = String::from_utf8(output).unwrap();
    let mut response_obj = json::Object::new();
    if status.success() {
        response_obj.insert(String::from("result"), json::Json::String(output));
    } else {
        response_obj.insert(String::from("error"), json::Json::String(output));
    }

    Ok(Response::with((status::Ok, format!("{}", json::Json::Object(response_obj)))))
}

// This is neat!
struct EnablePostCors;
impl AfterMiddleware for EnablePostCors {
    fn after(&self, _: &mut Request, res: Response) -> IronResult<Response> {
        Ok(res.set(Header(headers::AccessControlAllowOrigin::Any))
              .set(Header(headers::AccessControlAllowMethods(
                  vec![Method::Post,
                       Method::Options])))
              .set(Header(headers::AccessControlAllowHeaders(
                  vec![UniCase(String::from("Origin")),
                       UniCase(String::from("Accept")),
                       UniCase(String::from("Content-Type"))]))))
    }
}

fn main() {
    // Make sure pygmentize is installed before starting the server
    Command::new("pygmentize").spawn().unwrap().kill().unwrap();

    let mut router = Router::new();
    router.get("/", index);
    router.get("/:path", Static::new("static"));
    router.post("/evaluate.json", evaluate);
    router.post("/compile.json", compile);
    router.post("/format.json", format);

    // Use our router as the middleware, and pass the generated response through `EnablePostCors`
    let mut chain = Chain::new(router);
    chain.link_after(EnablePostCors);

    let addr = ("0.0.0.0", 80);
    println!("listening on {:?}", addr);
    Iron::new(chain).http(addr).unwrap();
}
<commit_msg>Implement "non-separate output mode"<commit_after>extern crate rust_playpen;

#[macro_use] extern crate iron;
extern crate hyper;
extern crate staticfile;
extern crate router;
extern crate unicase;
extern crate rustc_serialize;

use rust_playpen::*;

use iron::prelude::*;
use iron::status;
use iron::headers;
use iron::middleware::AfterMiddleware;
use iron::modifiers::Header;
use iron::method::Method;
use hyper::header;
use staticfile::Static;
use router::Router;
use unicase::UniCase;
use rustc_serialize::json;

use std::fmt;
use std::path::Path;
use std::io::Read;
use std::process::Command;

#[derive(Clone, Debug)]
struct XXssProtection(bool);

impl header::Header for XXssProtection {
    fn header_name() -> &'static str {
        "X-XSS-Protection"
    }

    fn parse_header(raw: &[Vec<u8>]) -> hyper::Result<Self> {
        if raw.len() == 1 {
            let line = &raw[0];
            if line.len() == 1 {
                let byte = line[0];
                match byte {
                    b'1' => return Ok(XXssProtection(true)),
                    b'0' => return Ok(XXssProtection(false)),
                    _ => ()
                }
            }
        }
        Err(hyper::Error::Header)
    }
}

impl header::HeaderFormat for XXssProtection {
    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.0 {
            f.write_str("1")
        } else {
            f.write_str("0")
        }
    }
}

fn index(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((Path::new("static/web.html"),
                       Header(XXssProtection(false)))))
}

/// The JSON-encoded request sent to `evaluate.json`.
#[derive(RustcDecodable)]
struct EvaluateReq {
    color: Option<bool>,
    test: Option<bool>,
    version: Option<String>,
    optimize: Option<String>,
    separate_output: Option<bool>,
    code: String,
}

fn evaluate(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    itry!(req.body.read_to_string(&mut body));

    let data: EvaluateReq = itry!(json::decode(&body));
    let color = data.color.unwrap_or(false);
    let test = data.test.unwrap_or(false);
    let version = itry!(data.version.map(|v| v.parse()).unwrap_or(Ok(ReleaseChannel::Stable)));
    let opt = itry!(data.optimize.map(|opt| opt.parse()).unwrap_or(Ok(OptLevel::O2)));
    let separate_output = data.separate_output.unwrap_or(false);

    let mut args = vec![String::from("-C"), format!("opt-level={}", opt.as_u8())];
    if opt == OptLevel::O0 {
        args.push(String::from("-g"));
    }
    if color {
        args.push(String::from("--color=always"));
    }
    if test {
        args.push(String::from("--test"));
    }

    let (_status, output) = itry!(
        rust_playpen::exec(version, "/usr/local/bin/evaluate.sh", args, data.code));

    let mut obj = json::Object::new();
    if separate_output {
        // {"rustc": "...", "program": "..."}
        let mut split = output.splitn(2, |b| *b == b'\xff');
        let rustc = String::from_utf8(split.next().unwrap().into()).unwrap();

        obj.insert(String::from("rustc"), json::Json::String(rustc));

        if let Some(program) = split.next() {
            // Compilation succeeded
            let output = String::from_utf8_lossy(program).into_owned();
            obj.insert(String::from("program"), json::Json::String(output));
        }
    } else {
        // {"result": "...""}
        let result = output.splitn(2, |b| *b == b'\xff')
                           .map(|sub| String::from_utf8_lossy(sub).into_owned())
                           .collect::<String>();

        obj.insert(String::from("result"), json::Json::String(result));
    }

    Ok(Response::with((status::Ok, format!("{}", json::Json::Object(obj)))))
}

#[derive(RustcDecodable)]
struct CompileReq {
    syntax: Option<String>,
    color: Option<bool>,
    version: Option<String>,
    optimize: Option<String>,
    emit: Option<String>,
    code: String,
}

fn compile(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    itry!(req.body.read_to_string(&mut body));

    let data: CompileReq = itry!(json::decode(&body));
    let syntax = data.syntax.map(|s| s.parse().unwrap()).unwrap_or(AsmFlavor::Att);
    let color = data.color.unwrap_or(false);
    let version = itry!(data.version.map(|v| v.parse()).unwrap_or(Ok(ReleaseChannel::Stable)));
    let opt = itry!(data.optimize.map(|opt| opt.parse()).unwrap_or(Ok(OptLevel::O2)));
    let emit = itry!(data.emit.map(|emit| emit.parse()).unwrap_or(Ok(CompileOutput::Asm)));

    let mut args = vec![
        String::from("-C"),
        format!("opt-level={}", opt.as_u8()),
        String::from("-C"),
        format!("llvm-args=-x86-asm-syntax={}", syntax.as_str()),
    ];
    for opt in emit.as_opts() {
        args.push(String::from(*opt));
    }
    if opt == OptLevel::O0 {
        args.push(String::from("-g"));
    }
    if color {
        args.push(String::from("--color=always"));
    }

    let (_status, output) = itry!(
        rust_playpen::exec(version, "/usr/local/bin/compile.sh", args, data.code));
    let mut split = output.splitn(2, |b| *b == b'\xff');
    let rustc = String::from_utf8(split.next().unwrap().into()).unwrap();

    let mut obj = json::Object::new();;
    match split.next() {
        Some(program_out) => {
            // Compilation succeeded
            let output = highlight(emit,
                                   &String::from_utf8_lossy(program_out).into_owned());
            obj.insert(String::from("result"), json::Json::String(output));
        }
        None => {
            obj.insert(String::from("error"), json::Json::String(rustc));
        }
    }

    Ok(Response::with((status::Ok, format!("{}", json::Json::Object(obj)))))
}

#[derive(RustcDecodable)]
struct FormatReq {
    version: Option<String>,
    code: String,
}

fn format(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    req.body.read_to_string(&mut body).unwrap();

    let data: FormatReq = itry!(json::decode(&body));
    let version = itry!(data.version.map(|v| v.parse()).unwrap_or(Ok(ReleaseChannel::Stable)));

    let (status, output) = itry!(
        rust_playpen::exec(version, "/usr/bin/rustfmt", Vec::new(), data.code));
    let output = String::from_utf8(output).unwrap();
    let mut response_obj = json::Object::new();
    if status.success() {
        response_obj.insert(String::from("result"), json::Json::String(output));
    } else {
        response_obj.insert(String::from("error"), json::Json::String(output));
    }

    Ok(Response::with((status::Ok, format!("{}", json::Json::Object(response_obj)))))
}

// This is neat!
struct EnablePostCors;
impl AfterMiddleware for EnablePostCors {
    fn after(&self, _: &mut Request, res: Response) -> IronResult<Response> {
        Ok(res.set(Header(headers::AccessControlAllowOrigin::Any))
              .set(Header(headers::AccessControlAllowMethods(
                  vec![Method::Post,
                       Method::Options])))
              .set(Header(headers::AccessControlAllowHeaders(
                  vec![UniCase(String::from("Origin")),
                       UniCase(String::from("Accept")),
                       UniCase(String::from("Content-Type"))]))))
    }
}

fn main() {
    // Make sure pygmentize is installed before starting the server
    Command::new("pygmentize").spawn().unwrap().kill().unwrap();

    let mut router = Router::new();
    router.get("/", index);
    router.get("/:path", Static::new("static"));
    router.post("/evaluate.json", evaluate);
    router.post("/compile.json", compile);
    router.post("/format.json", format);

    // Use our router as the middleware, and pass the generated response through `EnablePostCors`
    let mut chain = Chain::new(router);
    chain.link_after(EnablePostCors);

    let addr = ("0.0.0.0", 80);
    println!("listening on {:?}", addr);
    Iron::new(chain).http(addr).unwrap();
}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use hyper::{Method, StatusCode, Headers};

use header::response_ignore::HeaderResponseBloomResponseIgnore;

pub struct CacheCheck;

impl CacheCheck {
    pub fn from_request(method: &Method) -> bool {
        Self::is_cacheable_method(method) == true
    }

    pub fn from_response(method: &Method, status: &StatusCode, headers: &Headers) -> bool {
        Self::is_cacheable_method(method) == true && Self::is_cacheable_status(status) == true &&
            Self::is_cacheable_response(headers) == true
    }

    fn is_cacheable_method(method: &Method) -> bool {
        match *method {
            Method::Get | Method::Head => true,
            _ => false,
        }
    }

    fn is_cacheable_status(status: &StatusCode) -> bool {
        match *status {
            StatusCode::Ok |
            StatusCode::NonAuthoritativeInformation |
            StatusCode::NoContent |
            StatusCode::ResetContent |
            StatusCode::PartialContent |
            StatusCode::MultiStatus |
            StatusCode::AlreadyReported |
            StatusCode::MultipleChoices |
            StatusCode::MovedPermanently |
            StatusCode::Found |
            StatusCode::SeeOther |
            StatusCode::PermanentRedirect |
            StatusCode::Unauthorized |
            StatusCode::PaymentRequired |
            StatusCode::Forbidden |
            StatusCode::NotFound |
            StatusCode::MethodNotAllowed |
            StatusCode::Gone |
            StatusCode::UriTooLong |
            StatusCode::Locked |
            StatusCode::FailedDependency |
            StatusCode::NotImplemented => true,
            _ => false,
        }
    }

    fn is_cacheable_response(headers: &Headers) -> bool {
        // Ignore responses with 'Bloom-Response-Ignore'
        headers.has::<HeaderResponseBloomResponseIgnore>() == false
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_asserts_valid_cacheable_method() {
        assert_eq!(CacheCheck::is_cacheable_method(&Method::Get), true, "GET");
        assert_eq!(CacheCheck::is_cacheable_method(&Method::Head), true, "HEAD");
        assert_eq!(
            CacheCheck::is_cacheable_method(&Method::Options),
            false,
            "OPTIONS"
        );
        assert_eq!(
            CacheCheck::is_cacheable_method(&Method::Post),
            false,
            "POST"
        );
    }

    #[test]
    fn it_asserts_valid_cacheable_status() {
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::Ok),
            true,
            "200 OK"
        );
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::Unauthorized),
            true,
            "401 OK"
        );
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::BadRequest),
            false,
            "400 Bad Request"
        );
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::InternalServerError),
            false,
            "500 Internal Server Error"
        );
    }
}
<commit_msg>Add more cached statuses<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use hyper::{Method, StatusCode, Headers};

use header::response_ignore::HeaderResponseBloomResponseIgnore;

pub struct CacheCheck;

impl CacheCheck {
    pub fn from_request(method: &Method) -> bool {
        Self::is_cacheable_method(method) == true
    }

    pub fn from_response(method: &Method, status: &StatusCode, headers: &Headers) -> bool {
        Self::is_cacheable_method(method) == true && Self::is_cacheable_status(status) == true &&
            Self::is_cacheable_response(headers) == true
    }

    fn is_cacheable_method(method: &Method) -> bool {
        match *method {
            Method::Get | Method::Head => true,
            _ => false,
        }
    }

    fn is_cacheable_status(status: &StatusCode) -> bool {
        match *status {
            StatusCode::Ok |
            StatusCode::NonAuthoritativeInformation |
            StatusCode::NoContent |
            StatusCode::ResetContent |
            StatusCode::PartialContent |
            StatusCode::MultiStatus |
            StatusCode::AlreadyReported |
            StatusCode::MultipleChoices |
            StatusCode::MovedPermanently |
            StatusCode::Found |
            StatusCode::SeeOther |
            StatusCode::PermanentRedirect |
            StatusCode::Unauthorized |
            StatusCode::PaymentRequired |
            StatusCode::Forbidden |
            StatusCode::NotFound |
            StatusCode::MethodNotAllowed |
            StatusCode::Gone |
            StatusCode::UriTooLong |
            StatusCode::UnsupportedMediaType |
            StatusCode::RangeNotSatisfiable |
            StatusCode::ExpectationFailed |
            StatusCode::ImATeapot |
            StatusCode::Locked |
            StatusCode::FailedDependency |
            StatusCode::PreconditionRequired |
            StatusCode::RequestHeaderFieldsTooLarge |
            StatusCode::NotImplemented |
            StatusCode::NotExtended => true,
            _ => false,
        }
    }

    fn is_cacheable_response(headers: &Headers) -> bool {
        // Ignore responses with 'Bloom-Response-Ignore'
        headers.has::<HeaderResponseBloomResponseIgnore>() == false
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_asserts_valid_cacheable_method() {
        assert_eq!(CacheCheck::is_cacheable_method(&Method::Get), true, "GET");
        assert_eq!(CacheCheck::is_cacheable_method(&Method::Head), true, "HEAD");
        assert_eq!(
            CacheCheck::is_cacheable_method(&Method::Options),
            false,
            "OPTIONS"
        );
        assert_eq!(
            CacheCheck::is_cacheable_method(&Method::Post),
            false,
            "POST"
        );
    }

    #[test]
    fn it_asserts_valid_cacheable_status() {
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::Ok),
            true,
            "200 OK"
        );
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::Unauthorized),
            true,
            "401 OK"
        );
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::BadRequest),
            false,
            "400 Bad Request"
        );
        assert_eq!(
            CacheCheck::is_cacheable_status(&StatusCode::InternalServerError),
            false,
            "500 Internal Server Error"
        );
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use Component;
use processor::*;
use process::*;
use std::fs::{File, read_link};
use std::io::Read;
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{stat, lstat, c_char, sysconf, _SC_PAGESIZE, S_IFLNK, S_IFMT};
use std::path::Component::Normal;

pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_used: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
}

impl System {
    pub fn new() -> System {
        let mut s = System {
            process_list: HashMap::new(),
            mem_total: 0,
            mem_used: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: Vec::new(),
        };
        s.refresh_all();
        s
    }

    pub fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo");
        let lines : Vec<&str> = data.split('\n').collect();

        for component in self.temperatures.iter_mut() {
            component.update();
        }
        for line in lines.iter() {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemFree:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.mem_used = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat");
        let lines : Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.len() == 0;
        for line in lines.iter() {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _) : (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| s.len() > 0);
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(self.processors.get_mut(i).unwrap(),
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    pub fn refresh_process(&mut self) {
        match fs::read_dir(&Path::new("/proc")) {
            Ok(d) => {
                for entry in d {
                    if !entry.is_ok() {
                        continue;
                    }
                    let entry = entry.unwrap();
                    let entry = entry.path();

                    if entry.is_dir() {
                        _get_process_data(entry.as_path(), &mut self.process_list, self.page_size_kb);
                    } else {
                        match entry.to_str().unwrap() {
                           _ => {},
                        }
                    }
                }
                if self.processors.len() > 0 {
                    let (new, old) = get_raw_times(&self.processors[0]);
                    let total_time = (new - old) as f32;
                    let mut to_delete = Vec::new();
                    let nb_processors = self.processors.len() as u64 - 1;

                    for (pid, proc_) in self.process_list.iter_mut() {
                        if has_been_updated(&proc_) == false {
                            to_delete.push(*pid);
                        } else {
                            compute_cpu_usage(proc_, nb_processors, total_time);
                        }
                    }
                    for pid in to_delete {
                        self.process_list.remove(&pid);
                    }
                }
            }
            Err(_) => {}
        }
    }

    pub fn refresh_all(&mut self) {
        self.refresh_system();
        self.refresh_process();
    }

    pub fn get_process_list<'a>(&'a self) -> &'a HashMap<usize, Process> {
        &self.process_list
    }

    pub fn get_process(&self, pid: i64) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    /// The first process in the array is the "main" process
    pub fn get_processor_list<'a>(&'a self) -> &'a [Processor] {
        &self.processors[..]
    }

    pub fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    pub fn get_used_memory(&self) -> u64 {
        self.mem_used
    }

    pub fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    // need to be checked
    pub fn get_used_swap(&self) -> u64 {
        self.swap_free
    }

    pub fn get_components_list<'a>(&'a self) -> &'a [Component] {
        &self.temperatures[..]
    }
}

fn get_all_data(file_path: &str) -> String {
    let mut file = File::open(file_path).unwrap();
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();
    data
}

fn _get_process_data(path: &Path, proc_list: &mut HashMap<usize, Process>, page_size_kb: u64) {
    if !path.exists() || !path.is_dir() {
        return ;
    }
    let paths : Vec<&str> = path.as_os_str().to_str().unwrap().split("/").collect();
    let last = paths[paths.len() - 1];
    match i64::from_str(last) {
        Ok(nb) => {
            let mut tmp = PathBuf::from(path);

            tmp.push("stat");
            let data = get_all_data(tmp.to_str().unwrap());
            let (parts, _) : (Vec<&str>, Vec<&str>) = data.split(' ').partition(|s| s.len() > 0);
            match proc_list.get(&(nb as usize)) {
                Some(_) => {}
                None => {
                    let mut p = Process::new(nb, u64::from_str(parts[21]).unwrap());

                    tmp = PathBuf::from(path);
                    tmp.push("cmdline");
                    p.cmd = copy_from_file(&tmp)[0].clone();
                    p.name = p.cmd.split("/").last().unwrap().split(":").collect::<Vec<&str>>()[0].to_owned();
                    tmp = PathBuf::from(path);
                    tmp.push("environ");
                    p.environ = copy_from_file(&tmp);
                    tmp = PathBuf::from(path);
                    tmp.push("exe");

                    let s = read_link(tmp.to_str().unwrap());

                    if s.is_ok() {
                        p.exe = s.unwrap().to_str().unwrap().to_owned();
                    }
                    tmp = PathBuf::from(path);
                    tmp.push("cwd");
                    p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
                    tmp = PathBuf::from(path);
                    tmp.push("root");
                    p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
                    proc_list.insert(nb as usize, p);
                }
            }
            let mut entry = proc_list.get_mut(&(nb as usize)).unwrap();

            //entry.name = parts[1][1..].to_owned();
            //entry.name.pop();
            // we get the rss then we add the vsize
            entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb + u64::from_str(parts[22]).unwrap() / 1024;
            set_time(&mut entry, u64::from_str(parts[13]).unwrap(),
                u64::from_str(parts[14]).unwrap());
        }
        _ => {}
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            let v : Vec<&str> = d.split('\0').collect();
            let mut ret : Vec<String> = Vec::new();

            for tmp in v.iter() {
                ret.push((*tmp).to_owned());
            }
            ret
        },
        Err(_) => Vec::new()
    }
}

fn realpath(original: &Path) -> PathBuf {
    let ori = Path::new(original.to_str().unwrap());

    const MAX_LINKS_FOLLOWED: usize = 256;

    // Right now lstat on windows doesn't work quite well
    if cfg!(windows) {
        return PathBuf::from(ori);
    }
    let original = ::std::env::current_dir().unwrap().join(ori);
    let mut result = PathBuf::from(original.parent().unwrap());
    let mut followed = 0;
    for part in original.components() {
        match part {
            Normal(s) => {
                result.push(s);
                loop {
                    if followed == MAX_LINKS_FOLLOWED {
                        return PathBuf::new();
                    }
                    let mut buf : stat = unsafe { ::std::mem::uninitialized() };
                    let res = unsafe { lstat(result.to_str().unwrap().as_ptr() as *const c_char, &mut buf as *mut stat) };

                    if res < 0 || (buf.st_mode  & S_IFMT) != S_IFLNK {
                        break;
                    } else {
                        followed += 1;
                        let path = fs::read_link(&result).unwrap();
                        result.pop();
                        result.push(path);
                    }
                }
            }
            _ => {}
        }
    }
    result
}
<commit_msg>Get components info<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use Component;
use processor::*;
use process::*;
use std::fs::{File, read_link};
use std::io::Read;
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{stat, lstat, c_char, sysconf, _SC_PAGESIZE, S_IFLNK, S_IFMT};
use std::path::Component::Normal;

pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_used: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
}

impl System {
    pub fn new() -> System {
        let mut s = System {
            process_list: HashMap::new(),
            mem_total: 0,
            mem_used: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: Component::get_components(),
        };
        s.refresh_all();
        s
    }

    pub fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo");
        let lines : Vec<&str> = data.split('\n').collect();

        for component in self.temperatures.iter_mut() {
            component.update();
        }
        for line in lines.iter() {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemFree:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.mem_used = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts : Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat");
        let lines : Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.len() == 0;
        for line in lines.iter() {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _) : (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| s.len() > 0);
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(self.processors.get_mut(i).unwrap(),
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    pub fn refresh_process(&mut self) {
        match fs::read_dir(&Path::new("/proc")) {
            Ok(d) => {
                for entry in d {
                    if !entry.is_ok() {
                        continue;
                    }
                    let entry = entry.unwrap();
                    let entry = entry.path();

                    if entry.is_dir() {
                        _get_process_data(entry.as_path(), &mut self.process_list, self.page_size_kb);
                    } else {
                        match entry.to_str().unwrap() {
                           _ => {},
                        }
                    }
                }
                if self.processors.len() > 0 {
                    let (new, old) = get_raw_times(&self.processors[0]);
                    let total_time = (new - old) as f32;
                    let mut to_delete = Vec::new();
                    let nb_processors = self.processors.len() as u64 - 1;

                    for (pid, proc_) in self.process_list.iter_mut() {
                        if has_been_updated(&proc_) == false {
                            to_delete.push(*pid);
                        } else {
                            compute_cpu_usage(proc_, nb_processors, total_time);
                        }
                    }
                    for pid in to_delete {
                        self.process_list.remove(&pid);
                    }
                }
            }
            Err(_) => {}
        }
    }

    pub fn refresh_all(&mut self) {
        self.refresh_system();
        self.refresh_process();
    }

    pub fn get_process_list<'a>(&'a self) -> &'a HashMap<usize, Process> {
        &self.process_list
    }

    pub fn get_process(&self, pid: i64) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    /// The first process in the array is the "main" process
    pub fn get_processor_list<'a>(&'a self) -> &'a [Processor] {
        &self.processors[..]
    }

    pub fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    pub fn get_used_memory(&self) -> u64 {
        self.mem_used
    }

    pub fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    // need to be checked
    pub fn get_used_swap(&self) -> u64 {
        self.swap_free
    }

    pub fn get_components_list<'a>(&'a self) -> &'a [Component] {
        &self.temperatures[..]
    }
}

fn get_all_data(file_path: &str) -> String {
    let mut file = File::open(file_path).unwrap();
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();
    data
}

fn _get_process_data(path: &Path, proc_list: &mut HashMap<usize, Process>, page_size_kb: u64) {
    if !path.exists() || !path.is_dir() {
        return ;
    }
    let paths : Vec<&str> = path.as_os_str().to_str().unwrap().split("/").collect();
    let last = paths[paths.len() - 1];
    match i64::from_str(last) {
        Ok(nb) => {
            let mut tmp = PathBuf::from(path);

            tmp.push("stat");
            let data = get_all_data(tmp.to_str().unwrap());
            let (parts, _) : (Vec<&str>, Vec<&str>) = data.split(' ').partition(|s| s.len() > 0);
            match proc_list.get(&(nb as usize)) {
                Some(_) => {}
                None => {
                    let mut p = Process::new(nb, u64::from_str(parts[21]).unwrap());

                    tmp = PathBuf::from(path);
                    tmp.push("cmdline");
                    p.cmd = copy_from_file(&tmp)[0].clone();
                    p.name = p.cmd.split("/").last().unwrap().split(":").collect::<Vec<&str>>()[0].to_owned();
                    tmp = PathBuf::from(path);
                    tmp.push("environ");
                    p.environ = copy_from_file(&tmp);
                    tmp = PathBuf::from(path);
                    tmp.push("exe");

                    let s = read_link(tmp.to_str().unwrap());

                    if s.is_ok() {
                        p.exe = s.unwrap().to_str().unwrap().to_owned();
                    }
                    tmp = PathBuf::from(path);
                    tmp.push("cwd");
                    p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
                    tmp = PathBuf::from(path);
                    tmp.push("root");
                    p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
                    proc_list.insert(nb as usize, p);
                }
            }
            let mut entry = proc_list.get_mut(&(nb as usize)).unwrap();

            //entry.name = parts[1][1..].to_owned();
            //entry.name.pop();
            // we get the rss then we add the vsize
            entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb + u64::from_str(parts[22]).unwrap() / 1024;
            set_time(&mut entry, u64::from_str(parts[13]).unwrap(),
                u64::from_str(parts[14]).unwrap());
        }
        _ => {}
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            let v : Vec<&str> = d.split('\0').collect();
            let mut ret : Vec<String> = Vec::new();

            for tmp in v.iter() {
                ret.push((*tmp).to_owned());
            }
            ret
        },
        Err(_) => Vec::new()
    }
}

fn realpath(original: &Path) -> PathBuf {
    let ori = Path::new(original.to_str().unwrap());

    const MAX_LINKS_FOLLOWED: usize = 256;

    // Right now lstat on windows doesn't work quite well
    if cfg!(windows) {
        return PathBuf::from(ori);
    }
    let original = ::std::env::current_dir().unwrap().join(ori);
    let mut result = PathBuf::from(original.parent().unwrap());
    let mut followed = 0;
    for part in original.components() {
        match part {
            Normal(s) => {
                result.push(s);
                loop {
                    if followed == MAX_LINKS_FOLLOWED {
                        return PathBuf::new();
                    }
                    let mut buf : stat = unsafe { ::std::mem::uninitialized() };
                    let res = unsafe { lstat(result.to_str().unwrap().as_ptr() as *const c_char, &mut buf as *mut stat) };

                    if res < 0 || (buf.st_mode  & S_IFMT) != S_IFLNK {
                        break;
                    } else {
                        followed += 1;
                        let path = fs::read_link(&result).unwrap();
                        result.pop();
                        result.push(path);
                    }
                }
            }
            _ => {}
        }
    }
    result
}
<|endoftext|>


<commit_before>#[crate_id = "tester"];

extern mod extra;

use cpu::CPU;
use extra::getopts;

mod register;
mod mmu;
mod cpu;
mod serial;
mod timer;

fn main() {
	let args: ~[~str] = std::os::args();
	let program = args[0].clone() + " <filename>";

	let opts = ~[ getopts::groups::optflag("s", "serial", "Output serial to stdout") ];
	let matches = match getopts::groups::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { fail!(f.to_err_msg()) }
	};

	let filename: &str = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		println!("{}", getopts::groups::usage(program, opts));
		return;
	};

	let mut c = CPU::new();
	c.mmu.loadrom(filename);
	c.mmu.serial.enabled = matches.opt_present("serial");

	loop {
		c.cycle();
	}
}
<commit_msg>Nicer command line parsing error messages<commit_after>#[crate_id = "tester"];

extern mod extra;

use cpu::CPU;
use extra::getopts;

mod register;
mod mmu;
mod cpu;
mod serial;
mod timer;

fn main() {
	let args: ~[~str] = std::os::args();
	let program = args[0].clone() + " <filename>";

	let opts = ~[ getopts::groups::optflag("s", "serial", "Output serial to stdout") ];
	let matches = match getopts::groups::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f.to_err_msg()); return }
	};

	let filename: &str = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		println!("{}", getopts::groups::usage(program, opts));
		return;
	};

	let mut c = CPU::new();
	c.mmu.loadrom(filename);
	c.mmu.serial.enabled = matches.opt_present("serial");

	loop {
		c.cycle();
	}
}
<|endoftext|>


<commit_before>// Std
use std::io::Write;

// Internal
use app::parser::Parser;
use args::{ArgSettings, OptBuilder};
use shell::Shell;

macro_rules! w {
    ($buf:expr, $to_w:expr) => {
        match $buf.write_all($to_w) {
            Ok(..) => (),
            Err(..) => panic!("Failed to write to file completions file"),
        }
    };
}

pub struct ComplGen<'a, 'b>
    where 'a: 'b
{
    p: &'b Parser<'a, 'b>,
}

impl<'a, 'b> ComplGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>) -> Self {
        ComplGen { p: p }
    }

    pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
        match for_shell {
            Shell::Bash => self.gen_bash(buf),
            Shell::Fish => self.gen_fish(buf),
        }
    }

    fn gen_bash<W: Write>(&self, buf: &mut W) {
        w!(buf,
           format!("_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} {name}
",
                   name = self.p.meta.bin_name.as_ref().unwrap(),
                   name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
                   name_opts_details =
                       self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
                   subcmds = self.all_subcommands(),
                   subcmd_details = self.subcommand_details())
               .as_bytes());
    }

    fn all_subcommands(&self) -> String {
        let mut subcmds = String::new();
        let scs = get_all_subcommands(self.p);

        for sc in &scs {
            subcmds = format!("{}
            {name})
                cmd+=\"_{name}\"
                ;;",
                              subcmds,
                              name = sc.replace("-", "_"));
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        let mut subcmd_dets = String::new();
        let mut scs = get_all_subcommand_paths(self.p, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!("{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;",
                                  subcmd_dets,
                                  subcmd = sc.replace("-", "_"),
                                  sc_opts = self.all_options_for_path(&*sc),
                                  level = sc.split("_").map(|_| 1).fold(0, |acc, n| acc + n),
                                  opts_details = self.option_details_for_path(&*sc));
        }

        subcmd_dets
    }

    fn all_options_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split('_').skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands
                .iter()
                .find(|s| {
                    s.p.meta.name == sc ||
                    (s.p.meta.aliases.is_some() &&
                     s.p
                        .meta
                        .aliases
                        .as_ref()
                        .unwrap()
                        .iter()
                        .any(|&(n, _)| n == sc))
                })
                .unwrap()
                .p;
        }
        let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
        opts = format!("{} {}",
                       opts,
                       p.long_list
                           .iter()
                           .fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
        opts = format!("{} {}",
                       opts,
                       p.positionals
                           .values()
                           .fold(String::new(), |acc, p| format!("{} {}", acc, p)));
        opts = format!("{} {}",
                       opts,
                       p.subcommands
                           .iter()
                           .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
        for sc in &p.subcommands {
            if let Some(ref aliases) = sc.p.meta.aliases {
                opts = format!("{} {}",
                               opts,
                               aliases.iter()
                                   .map(|&(n, _)| n)
                                   .fold(String::new(), |acc, a| format!("{} {}", acc, a)));
            }
        }
        opts
    }

    fn option_details_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split('_').skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands
                .iter()
                .find(|s| {
                    s.p.meta.name == sc ||
                    (s.p.meta.aliases.is_some() &&
                     s.p
                        .meta
                        .aliases
                        .as_ref()
                        .unwrap()
                        .iter()
                        .any(|&(n, _)| n == sc))
                })
                .unwrap()
                .p;
        }
        let mut opts = String::new();
        for o in &p.opts {
            if let Some(l) = o.long {
                opts = format!("{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                               opts,
                               l,
                               vals_for(o));
            }
            if let Some(s) = o.short {
                opts = format!("{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                               opts,
                               s,
                               vals_for(o));
            }
        }
        opts
    }

    fn gen_fish<W: Write>(&self, buf: &mut W) {
        let command = self.p.meta.bin_name.as_ref().unwrap();

        // function to detect subcommand
        let detect_subcommand_function =
r#"function __fish_using_command
    set cmd (commandline -opc)
    if [ (count $cmd) -eq (count $argv) ]
        for i in (seq (count $argv))
            if [ $cmd[$i] != $argv[$i] ]
                return 1
            end
        end
        return 0
    end
    return 1
end

"#.to_string();

        let mut buffer = detect_subcommand_function;
        gen_fish_inner(command, self, &command.to_string(), &mut buffer);
        w!(buf, buffer.as_bytes());
    }
}

pub fn get_all_subcommands(p: &Parser) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        let mut ret = vec![p.meta.name.clone()];
        if let Some(ref aliases) = p.meta.aliases {
            for &(n, _) in aliases {
                ret.push(n.to_owned());
            }
        }
        return ret;
    }
    for sc in &p.subcommands {
        if let Some(ref aliases) = sc.p.meta.aliases {
            for &(n, _) in aliases {
                subcmds.push(n.to_owned());
            }
        }
        subcmds.push(sc.p.meta.name.clone());
    }
    for sc_v in p.subcommands.iter().map(|s| get_all_subcommands(&s.p)) {
        subcmds.extend(sc_v);
    }
    subcmds.sort();
    subcmds.dedup();
    subcmds
}

pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        if !first {
            let name = &*p.meta.name;
            let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_");
            let mut ret = vec![path.clone()];
            if let Some(ref aliases) = p.meta.aliases {
                for &(n, _) in aliases {
                    ret.push(path.replace(name, n));
                }
            }
            return ret;
        }
        return vec![];
    }
    for sc in &p.subcommands {
        let name = &*sc.p.meta.name;
        let path = sc.p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_");
        subcmds.push(path.clone());
        if let Some(ref aliases) = sc.p.meta.aliases {
            for &(n, _) in aliases {
                subcmds.push(path.replace(name, n));
            }
        }
    }
    for sc_v in p.subcommands.iter().map(|s| get_all_subcommand_paths(&s.p, false)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

fn vals_for(o: &OptBuilder) -> String {
    use args::AnyArg;
    let mut ret = String::new();
    let mut needs_quotes = true;
    if let Some(vals) = o.possible_vals() {
        needs_quotes = false;
        ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
    } else if let Some(vec) = o.val_names() {
        let mut it = vec.iter().peekable();
        while let Some((_, val)) = it.next() {
            ret = format!("{}<{}>{}",
                          ret,
                          val,
                          if it.peek().is_some() { " " } else { "" });
        }
        let num = vec.len();
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else if let Some(num) = o.num_vals() {
        let mut it = (0..num).peekable();
        while let Some(_) = it.next() {
            ret = format!("{}<{}>{}",
                          ret,
                          o.name(),
                          if it.peek().is_some() { " " } else { "" });
        }
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else {
        ret = format!("<{}>", o.name());
        if o.is_set(ArgSettings::Multiple) {
            ret = format!("{}...", ret);
        }
    }
    if needs_quotes {
        ret = format!("\"{}\"", ret);
    }
    ret
}

fn gen_fish_inner(root_command: &str,
                  comp_gen: &ComplGen,
                  parent_cmds: &String,
                  buffer: &mut String) {

    // example :
    //
    // complete
    //      -c {command}
    //      -d "{description}"
    //      -s {short}
    //      -l {long}
    //      -a "{possible_arguments}"
    //      -r # if require parameter
    //      -f # don't use file completion
    //      -n "__fish_using_command myprog subcmd1" # complete for command "myprog subcmd1"

    let basic_template = format!("complete -c {} -n '__fish_using_command {}'",
                                 root_command,
                                 parent_cmds);

    for option in &comp_gen.p.opts {
        let mut template = basic_template.clone();
        if let Some(data) = option.short {
            template.push_str(format!(" -s {}", data).as_str());
        }
        if let Some(data) = option.long {
            template.push_str(format!(" -l {}", data).as_str());
        }
        if let Some(data) = option.help {
            template.push_str(format!(" -d '{}'", data).as_str());
        }
        if let Some(ref data) = option.possible_vals {
            template.push_str(format!(" -r -f -a '{}'", data.join(" ")).as_str());
        }
        buffer.push_str(template.as_str());
        buffer.push_str("\n");
    }

    for flag in &comp_gen.p.flags {
        let mut template = basic_template.clone();
        if let Some(data) = flag.short {
            template.push_str(format!(" -s {}", data).as_str());
        }
        if let Some(data) = flag.long {
            template.push_str(format!(" -l {}", data).as_str());
        }
        if let Some(data) = flag.help {
            template.push_str(format!(" -d '{}'", data).as_str());
        }
        buffer.push_str(template.as_str());
        buffer.push_str("\n");
    }

    for subcommand in &comp_gen.p.subcommands {
        let mut template = basic_template.clone();
        template.push_str(" -f");
        template.push_str(format!(" -a '{}'", &subcommand.p.meta.name).as_str());
        buffer.push_str(template.as_str());
        buffer.push_str("\n");
    }

    // generate options of subcommands
    for subcommand in &comp_gen.p.subcommands {
        let sub_comp_gen = ComplGen::new(&subcommand.p);
        // make new "parent_cmds" for different subcommands
        let mut sub_parent_cmds = parent_cmds.clone();
        if !sub_parent_cmds.is_empty() {
            sub_parent_cmds.push_str(" ");
        }
        sub_parent_cmds.push_str(&subcommand.p.meta.name);
        gen_fish_inner(root_command,
                       &sub_comp_gen,
                       &mut sub_parent_cmds,
                       buffer);
    }
}
<commit_msg>style: Fix new lints in fish_inner()<commit_after>// Std
use std::io::Write;

// Internal
use app::parser::Parser;
use args::{ArgSettings, OptBuilder};
use shell::Shell;

macro_rules! w {
    ($buf:expr, $to_w:expr) => {
        match $buf.write_all($to_w) {
            Ok(..) => (),
            Err(..) => panic!("Failed to write to file completions file"),
        }
    };
}

pub struct ComplGen<'a, 'b>
    where 'a: 'b
{
    p: &'b Parser<'a, 'b>,
}

impl<'a, 'b> ComplGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>) -> Self {
        ComplGen { p: p }
    }

    pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
        match for_shell {
            Shell::Bash => self.gen_bash(buf),
            Shell::Fish => self.gen_fish(buf),
        }
    }

    fn gen_bash<W: Write>(&self, buf: &mut W) {
        w!(buf,
           format!("_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} {name}
",
                   name = self.p.meta.bin_name.as_ref().unwrap(),
                   name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
                   name_opts_details =
                       self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
                   subcmds = self.all_subcommands(),
                   subcmd_details = self.subcommand_details())
               .as_bytes());
    }

    fn all_subcommands(&self) -> String {
        let mut subcmds = String::new();
        let scs = get_all_subcommands(self.p);

        for sc in &scs {
            subcmds = format!("{}
            {name})
                cmd+=\"_{name}\"
                ;;",
                              subcmds,
                              name = sc.replace("-", "_"));
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        let mut subcmd_dets = String::new();
        let mut scs = get_all_subcommand_paths(self.p, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!("{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;",
                                  subcmd_dets,
                                  subcmd = sc.replace("-", "_"),
                                  sc_opts = self.all_options_for_path(&*sc),
                                  level = sc.split("_").map(|_| 1).fold(0, |acc, n| acc + n),
                                  opts_details = self.option_details_for_path(&*sc));
        }

        subcmd_dets
    }

    fn all_options_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split('_').skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands
                .iter()
                .find(|s| {
                    s.p.meta.name == sc ||
                    (s.p.meta.aliases.is_some() &&
                     s.p
                        .meta
                        .aliases
                        .as_ref()
                        .unwrap()
                        .iter()
                        .any(|&(n, _)| n == sc))
                })
                .unwrap()
                .p;
        }
        let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
        opts = format!("{} {}",
                       opts,
                       p.long_list
                           .iter()
                           .fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
        opts = format!("{} {}",
                       opts,
                       p.positionals
                           .values()
                           .fold(String::new(), |acc, p| format!("{} {}", acc, p)));
        opts = format!("{} {}",
                       opts,
                       p.subcommands
                           .iter()
                           .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
        for sc in &p.subcommands {
            if let Some(ref aliases) = sc.p.meta.aliases {
                opts = format!("{} {}",
                               opts,
                               aliases.iter()
                                   .map(|&(n, _)| n)
                                   .fold(String::new(), |acc, a| format!("{} {}", acc, a)));
            }
        }
        opts
    }

    fn option_details_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split('_').skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands
                .iter()
                .find(|s| {
                    s.p.meta.name == sc ||
                    (s.p.meta.aliases.is_some() &&
                     s.p
                        .meta
                        .aliases
                        .as_ref()
                        .unwrap()
                        .iter()
                        .any(|&(n, _)| n == sc))
                })
                .unwrap()
                .p;
        }
        let mut opts = String::new();
        for o in &p.opts {
            if let Some(l) = o.long {
                opts = format!("{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                               opts,
                               l,
                               vals_for(o));
            }
            if let Some(s) = o.short {
                opts = format!("{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;",
                               opts,
                               s,
                               vals_for(o));
            }
        }
        opts
    }

    fn gen_fish<W: Write>(&self, buf: &mut W) {
        let command = self.p.meta.bin_name.as_ref().unwrap();

        // function to detect subcommand
        let detect_subcommand_function =
r#"function __fish_using_command
    set cmd (commandline -opc)
    if [ (count $cmd) -eq (count $argv) ]
        for i in (seq (count $argv))
            if [ $cmd[$i] != $argv[$i] ]
                return 1
            end
        end
        return 0
    end
    return 1
end

"#.to_string();

        let mut buffer = detect_subcommand_function;
        gen_fish_inner(command, self, &command.to_string(), &mut buffer);
        w!(buf, buffer.as_bytes());
    }
}

pub fn get_all_subcommands(p: &Parser) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        let mut ret = vec![p.meta.name.clone()];
        if let Some(ref aliases) = p.meta.aliases {
            for &(n, _) in aliases {
                ret.push(n.to_owned());
            }
        }
        return ret;
    }
    for sc in &p.subcommands {
        if let Some(ref aliases) = sc.p.meta.aliases {
            for &(n, _) in aliases {
                subcmds.push(n.to_owned());
            }
        }
        subcmds.push(sc.p.meta.name.clone());
    }
    for sc_v in p.subcommands.iter().map(|s| get_all_subcommands(&s.p)) {
        subcmds.extend(sc_v);
    }
    subcmds.sort();
    subcmds.dedup();
    subcmds
}

pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        if !first {
            let name = &*p.meta.name;
            let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_");
            let mut ret = vec![path.clone()];
            if let Some(ref aliases) = p.meta.aliases {
                for &(n, _) in aliases {
                    ret.push(path.replace(name, n));
                }
            }
            return ret;
        }
        return vec![];
    }
    for sc in &p.subcommands {
        let name = &*sc.p.meta.name;
        let path = sc.p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_");
        subcmds.push(path.clone());
        if let Some(ref aliases) = sc.p.meta.aliases {
            for &(n, _) in aliases {
                subcmds.push(path.replace(name, n));
            }
        }
    }
    for sc_v in p.subcommands.iter().map(|s| get_all_subcommand_paths(&s.p, false)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

fn vals_for(o: &OptBuilder) -> String {
    use args::AnyArg;
    let mut ret = String::new();
    let mut needs_quotes = true;
    if let Some(vals) = o.possible_vals() {
        needs_quotes = false;
        ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
    } else if let Some(vec) = o.val_names() {
        let mut it = vec.iter().peekable();
        while let Some((_, val)) = it.next() {
            ret = format!("{}<{}>{}",
                          ret,
                          val,
                          if it.peek().is_some() { " " } else { "" });
        }
        let num = vec.len();
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else if let Some(num) = o.num_vals() {
        let mut it = (0..num).peekable();
        while let Some(_) = it.next() {
            ret = format!("{}<{}>{}",
                          ret,
                          o.name(),
                          if it.peek().is_some() { " " } else { "" });
        }
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else {
        ret = format!("<{}>", o.name());
        if o.is_set(ArgSettings::Multiple) {
            ret = format!("{}...", ret);
        }
    }
    if needs_quotes {
        ret = format!("\"{}\"", ret);
    }
    ret
}

fn gen_fish_inner(root_command: &str,
                  comp_gen: &ComplGen,
                  parent_cmds: &str,
                  buffer: &mut String) {

    // example :
    //
    // complete
    //      -c {command}
    //      -d "{description}"
    //      -s {short}
    //      -l {long}
    //      -a "{possible_arguments}"
    //      -r # if require parameter
    //      -f # don't use file completion
    //      -n "__fish_using_command myprog subcmd1" # complete for command "myprog subcmd1"

    let basic_template = format!("complete -c {} -n '__fish_using_command {}'",
                                 root_command,
                                 parent_cmds);

    for option in &comp_gen.p.opts {
        let mut template = basic_template.clone();
        if let Some(data) = option.short {
            template.push_str(format!(" -s {}", data).as_str());
        }
        if let Some(data) = option.long {
            template.push_str(format!(" -l {}", data).as_str());
        }
        if let Some(data) = option.help {
            template.push_str(format!(" -d '{}'", data).as_str());
        }
        if let Some(ref data) = option.possible_vals {
            template.push_str(format!(" -r -f -a '{}'", data.join(" ")).as_str());
        }
        buffer.push_str(template.as_str());
        buffer.push_str("\n");
    }

    for flag in &comp_gen.p.flags {
        let mut template = basic_template.clone();
        if let Some(data) = flag.short {
            template.push_str(format!(" -s {}", data).as_str());
        }
        if let Some(data) = flag.long {
            template.push_str(format!(" -l {}", data).as_str());
        }
        if let Some(data) = flag.help {
            template.push_str(format!(" -d '{}'", data).as_str());
        }
        buffer.push_str(template.as_str());
        buffer.push_str("\n");
    }

    for subcommand in &comp_gen.p.subcommands {
        let mut template = basic_template.clone();
        template.push_str(" -f");
        template.push_str(format!(" -a '{}'", &subcommand.p.meta.name).as_str());
        buffer.push_str(template.as_str());
        buffer.push_str("\n");
    }

    // generate options of subcommands
    for subcommand in &comp_gen.p.subcommands {
        let sub_comp_gen = ComplGen::new(&subcommand.p);
        // make new "parent_cmds" for different subcommands
        let mut sub_parent_cmds = parent_cmds.to_string();
        if !sub_parent_cmds.is_empty() {
            sub_parent_cmds.push_str(" ");
        }
        sub_parent_cmds.push_str(&subcommand.p.meta.name);
        gen_fish_inner(root_command,
                       &sub_comp_gen,
                       &sub_parent_cmds,
                       buffer);
    }
}
<|endoftext|>


<commit_before>// Copyright © 2015-2017 winapi-rs developers
// 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.
// All files in the project carrying such notice may not be copied, modified, or distributed
// except according to those terms.

#![allow(bad_style)]

use std::os::raw;

pub type wchar_t = u16;

pub type UINT = raw::c_uint;
pub type LPUNKNOWN = *mut IUnknown;
pub type REFIID = *const IID;
pub type IID = GUID;
pub type REFCLSID = *const IID;
pub type PVOID = *mut raw::c_void;
pub type USHORT = raw::c_ushort;
pub type ULONG = raw::c_ulong;
pub type LONG = raw::c_long;
pub type DWORD = u32;
pub type LPVOID = *mut raw::c_void;
pub type HRESULT = raw::c_long;
pub type LPFILETIME = *mut FILETIME;
pub type BSTR = *mut OLECHAR;
pub type OLECHAR = WCHAR;
pub type WCHAR = wchar_t;
pub type LPCOLESTR = *const OLECHAR;
pub type LCID = DWORD;
pub type LPCWSTR = *const WCHAR;
pub type PULONGLONG = *mut ULONGLONG;
pub type ULONGLONG = u64;

pub const S_OK: HRESULT = 0;
pub const S_FALSE: HRESULT = 1;
pub const COINIT_MULTITHREADED: u32 = 0x0;

pub type CLSCTX = u32;

pub const CLSCTX_INPROC_SERVER: CLSCTX = 0x1;
pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2;
pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4;
pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10;

pub const CLSCTX_ALL: CLSCTX = CLSCTX_INPROC_SERVER |
    CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GUID {
    pub Data1: raw::c_ulong,
    pub Data2: raw::c_ushort,
    pub Data3: raw::c_ushort,
    pub Data4: [raw::c_uchar; 8],
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct FILETIME {
    pub dwLowDateTime: DWORD,
    pub dwHighDateTime: DWORD,
}

pub trait Interface {
    fn uuidof() -> GUID;
}

#[link(name = "Ole32")]
#[link(name = "OleAut32")]
extern { }

extern "system" {
    pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT;
    pub fn CoCreateInstance(rclsid: REFCLSID, pUnkOuter: LPUNKNOWN,
                            dwClsContext: DWORD, riid: REFIID,
                            ppv: *mut LPVOID) -> HRESULT;
    pub fn SysFreeString(bstrString: BSTR);
    pub fn SysStringLen(pbstr: BSTR) -> UINT;
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SAFEARRAYBOUND {
    pub cElements: ULONG,
    pub lLbound: LONG,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SAFEARRAY {
    pub cDims: USHORT,
    pub fFeatures: USHORT,
    pub cbElements: ULONG,
    pub cLocks: ULONG,
    pub pvData: PVOID,
    pub rgsabound: [SAFEARRAYBOUND; 1],
}

pub type LPSAFEARRAY = *mut SAFEARRAY;

macro_rules! DEFINE_GUID {
    (
        $name:ident, $l:expr, $w1:expr, $w2:expr,
        $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
    ) => {
        pub const $name: $crate::winapi::GUID = $crate::winapi::GUID {
            Data1: $l,
            Data2: $w1,
            Data3: $w2,
            Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
        };
    }
}

macro_rules! RIDL {
    (#[uuid($($uuid:expr),+)]
    interface $interface:ident ($vtbl:ident) {$(
        fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
    )+}) => (
        #[repr(C)]
        pub struct $vtbl {
            $(pub $method: unsafe extern "system" fn(
                This: *mut $interface,
                $($p: $t),*
            ) -> $rtr,)+
        }
        #[repr(C)]
        pub struct $interface {
            pub lpVtbl: *const $vtbl,
        }
        RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
        RIDL!{@uuid $interface $($uuid),+}
    );
    (#[uuid($($uuid:expr),+)]
    interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {
    }) => (
        #[repr(C)]
        pub struct $vtbl {
            pub parent: $pvtbl,
        }
        #[repr(C)]
        pub struct $interface {
            pub lpVtbl: *const $vtbl,
        }
        RIDL!{@deref $interface $pinterface}
        RIDL!{@uuid $interface $($uuid),+}
    );
    (#[uuid($($uuid:expr),+)]
    interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$(
        fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
    )+}) => (
        #[repr(C)]
        pub struct $vtbl {
            pub parent: $pvtbl,
            $(pub $method: unsafe extern "system" fn(
                This: *mut $interface,
                $($p: $t,)*
            ) -> $rtr,)+
        }
        #[repr(C)]
        pub struct $interface {
            pub lpVtbl: *const $vtbl,
        }
        RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
        RIDL!{@deref $interface $pinterface}
        RIDL!{@uuid $interface $($uuid),+}
    );
    (@deref $interface:ident $pinterface:ident) => (
        impl ::std::ops::Deref for $interface {
            type Target = $pinterface;
            #[inline]
            fn deref(&self) -> &$pinterface {
                unsafe { &*(self as *const $interface as *const $pinterface) }
            }
        }
    );
    (@impl $interface:ident {$(
        fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
    )+}) => (
        impl $interface {
            $(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr {
                ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*)
            })+
        }
    );
    (@uuid $interface:ident
        $l:expr, $w1:expr, $w2:expr,
        $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
    ) => (
        impl $crate::winapi::Interface for $interface {
            #[inline]
            fn uuidof() -> $crate::winapi::GUID {
                $crate::winapi::GUID {
                    Data1: $l,
                    Data2: $w1,
                    Data3: $w2,
                    Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
                }
            }
        }
    );
}

RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)]
interface IUnknown(IUnknownVtbl) {
    fn QueryInterface(
        riid: REFIID,
        ppvObject: *mut *mut raw::c_void,
    ) -> HRESULT,
    fn AddRef() -> ULONG,
    fn Release() -> ULONG,
}}
<commit_msg>Don't capitalize library names<commit_after>// Copyright © 2015-2017 winapi-rs developers
// 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.
// All files in the project carrying such notice may not be copied, modified, or distributed
// except according to those terms.

#![allow(bad_style)]

use std::os::raw;

pub type wchar_t = u16;

pub type UINT = raw::c_uint;
pub type LPUNKNOWN = *mut IUnknown;
pub type REFIID = *const IID;
pub type IID = GUID;
pub type REFCLSID = *const IID;
pub type PVOID = *mut raw::c_void;
pub type USHORT = raw::c_ushort;
pub type ULONG = raw::c_ulong;
pub type LONG = raw::c_long;
pub type DWORD = u32;
pub type LPVOID = *mut raw::c_void;
pub type HRESULT = raw::c_long;
pub type LPFILETIME = *mut FILETIME;
pub type BSTR = *mut OLECHAR;
pub type OLECHAR = WCHAR;
pub type WCHAR = wchar_t;
pub type LPCOLESTR = *const OLECHAR;
pub type LCID = DWORD;
pub type LPCWSTR = *const WCHAR;
pub type PULONGLONG = *mut ULONGLONG;
pub type ULONGLONG = u64;

pub const S_OK: HRESULT = 0;
pub const S_FALSE: HRESULT = 1;
pub const COINIT_MULTITHREADED: u32 = 0x0;

pub type CLSCTX = u32;

pub const CLSCTX_INPROC_SERVER: CLSCTX = 0x1;
pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2;
pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4;
pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10;

pub const CLSCTX_ALL: CLSCTX = CLSCTX_INPROC_SERVER |
    CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GUID {
    pub Data1: raw::c_ulong,
    pub Data2: raw::c_ushort,
    pub Data3: raw::c_ushort,
    pub Data4: [raw::c_uchar; 8],
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct FILETIME {
    pub dwLowDateTime: DWORD,
    pub dwHighDateTime: DWORD,
}

pub trait Interface {
    fn uuidof() -> GUID;
}

#[link(name = "ole32")]
#[link(name = "oleaut32")]
extern { }

extern "system" {
    pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT;
    pub fn CoCreateInstance(rclsid: REFCLSID, pUnkOuter: LPUNKNOWN,
                            dwClsContext: DWORD, riid: REFIID,
                            ppv: *mut LPVOID) -> HRESULT;
    pub fn SysFreeString(bstrString: BSTR);
    pub fn SysStringLen(pbstr: BSTR) -> UINT;
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SAFEARRAYBOUND {
    pub cElements: ULONG,
    pub lLbound: LONG,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SAFEARRAY {
    pub cDims: USHORT,
    pub fFeatures: USHORT,
    pub cbElements: ULONG,
    pub cLocks: ULONG,
    pub pvData: PVOID,
    pub rgsabound: [SAFEARRAYBOUND; 1],
}

pub type LPSAFEARRAY = *mut SAFEARRAY;

macro_rules! DEFINE_GUID {
    (
        $name:ident, $l:expr, $w1:expr, $w2:expr,
        $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
    ) => {
        pub const $name: $crate::winapi::GUID = $crate::winapi::GUID {
            Data1: $l,
            Data2: $w1,
            Data3: $w2,
            Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
        };
    }
}

macro_rules! RIDL {
    (#[uuid($($uuid:expr),+)]
    interface $interface:ident ($vtbl:ident) {$(
        fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
    )+}) => (
        #[repr(C)]
        pub struct $vtbl {
            $(pub $method: unsafe extern "system" fn(
                This: *mut $interface,
                $($p: $t),*
            ) -> $rtr,)+
        }
        #[repr(C)]
        pub struct $interface {
            pub lpVtbl: *const $vtbl,
        }
        RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
        RIDL!{@uuid $interface $($uuid),+}
    );
    (#[uuid($($uuid:expr),+)]
    interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {
    }) => (
        #[repr(C)]
        pub struct $vtbl {
            pub parent: $pvtbl,
        }
        #[repr(C)]
        pub struct $interface {
            pub lpVtbl: *const $vtbl,
        }
        RIDL!{@deref $interface $pinterface}
        RIDL!{@uuid $interface $($uuid),+}
    );
    (#[uuid($($uuid:expr),+)]
    interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$(
        fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
    )+}) => (
        #[repr(C)]
        pub struct $vtbl {
            pub parent: $pvtbl,
            $(pub $method: unsafe extern "system" fn(
                This: *mut $interface,
                $($p: $t,)*
            ) -> $rtr,)+
        }
        #[repr(C)]
        pub struct $interface {
            pub lpVtbl: *const $vtbl,
        }
        RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
        RIDL!{@deref $interface $pinterface}
        RIDL!{@uuid $interface $($uuid),+}
    );
    (@deref $interface:ident $pinterface:ident) => (
        impl ::std::ops::Deref for $interface {
            type Target = $pinterface;
            #[inline]
            fn deref(&self) -> &$pinterface {
                unsafe { &*(self as *const $interface as *const $pinterface) }
            }
        }
    );
    (@impl $interface:ident {$(
        fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
    )+}) => (
        impl $interface {
            $(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr {
                ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*)
            })+
        }
    );
    (@uuid $interface:ident
        $l:expr, $w1:expr, $w2:expr,
        $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
    ) => (
        impl $crate::winapi::Interface for $interface {
            #[inline]
            fn uuidof() -> $crate::winapi::GUID {
                $crate::winapi::GUID {
                    Data1: $l,
                    Data2: $w1,
                    Data3: $w2,
                    Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
                }
            }
        }
    );
}

RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)]
interface IUnknown(IUnknownVtbl) {
    fn QueryInterface(
        riid: REFIID,
        ppvObject: *mut *mut raw::c_void,
    ) -> HRESULT,
    fn AddRef() -> ULONG,
    fn Release() -> ULONG,
}}
<|endoftext|>


<commit_before>use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use super::{Spawner, make_spawner};
use super::arena::Arena;
use super::job::Job;
use super::queue::{Queue, Stolen};
use super::rand::{Rng, XorShiftRng};

// Each worker lives on a specific thread and manages a job queue and allocator.
// When attempting to run jobs, it will first look in its own queue and then
// attempt to steal from its siblings.
pub struct Worker {
    queues: Arc<Vec<Queue>>,
    arenas: Arc<Vec<Arena>>,
    idx: usize, // the index of this worker's queue and pool in the Vec.
    rng: UnsafeCell<XorShiftRng>,
}

impl Worker {
    pub fn new(queues: Arc<Vec<Queue>>, arenas: Arc<Vec<Arena>>, idx: usize, rng: XorShiftRng)
    -> Self {
        Worker {
            queues: queues,
            arenas: arenas,
            idx: idx,
            rng: UnsafeCell::new(rng),
        }
    }
    // pop a job from the worker's queue, or steal one from another queue.
    unsafe fn pop_or_steal(&self) -> Option<*mut Job> {
        const ABORTS_BEFORE_BACKOFF: usize = 64;

        if let Some(job) = self.queues[self.idx].pop() {
            return Some(job);
        }

        let idx = (*self.rng.get()).gen::<usize>() % self.queues.len();

        if idx != self.idx {
            let mut aborts = 0;
            loop {
                aborts += 1;
                if aborts > ABORTS_BEFORE_BACKOFF {
                    return None;
                }

                match self.queues[idx].steal() {
                    Stolen::Success(job) => return Some(job),
                    Stolen::Empty => return None,
                    _ => {}
                }
            }
        } else {
            None
        }
    }

    // do a sweep through all the queues, saying whether all
    // were observed to be empty initially.
    fn clear_pass(&self) -> bool {
        let mut all_clear = true;
        for (idx, queue) in self.queues.iter().enumerate() {
            if idx != self.idx {
                loop {
                    match queue.steal() {
                        Stolen::Success(job) => {
                            all_clear = false;
                            unsafe { (*job).call(self) }
                        }
                        Stolen::Empty => break,
                        Stolen::Abort => {
                            all_clear = false;
                        }
                    }
                }
            } else {
                while let Some(job) = unsafe { queue.pop() } {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            }
        }

        all_clear
    }

    pub fn clear(&self) {
        while !self.clear_pass() {}
    }

    // run the next job.
    pub unsafe fn run_next(&self) {
        if let Some(job) = self.pop_or_steal() {
            (*job).call(self)
        }
    }

    // This must be called on the thread the worker is assigned to.
    pub unsafe fn submit_internal<F>(&self, counter: *const AtomicUsize, f: F)
        where F: Send + FnOnce(&Worker)
    {
        let job = Job::new(counter, f);
        let job_ptr = self.arenas[self.idx].alloc(job);
        self.queues[self.idx].push(job_ptr);
    }

    // construct a new spawning scope.
    // this waits for all jobs submitted internally to complete.
    pub fn scope<'pool, 'new, F, R>(&'pool self, f: F) -> R
        where F: 'new + FnOnce(&Spawner<'pool, 'new>) -> R,
              R: 'new,

    {
        let counter = AtomicUsize::new(0);
        let s = make_spawner(self, &counter);

        // store the top of the job arena before the scope is run.
        let top = self.arenas[self.idx].top();

        let res = f(&s);

        struct PanicGuard<'a>(&'a AtomicUsize);
        impl<'a> Drop for PanicGuard<'a> {
            fn drop(&mut self) {
                while self.0.load(Ordering::Acquire) > 0 {
                    ::std::thread::yield_now()
                }
            }
        }

        // if this thread panics while running a job, we need
        // to wait for other threads to finish the scoped jobs
        // before unwinding. this could result in a deadlock in cases
        // where many functions are panicking and no other threads exist
        // to finish jobs.
        let guard = PanicGuard(&counter);

        loop {
            let status = counter.load(Ordering::Acquire);
            if status == 0 { break }
            unsafe { self.run_next() }
        }

        ::std::mem::forget(guard);

        // once all jobs have completed from the scope, we can reset the arena
        // to its previous state. This only holds true if:
        //   - the arena is only used from this thread. this is already supposed to be true.
        //   - spawners cannot be cloned. If we could clone spawners, using one within another's
        //     scope could lead to jobs being overwritten.
        unsafe { self.arenas[self.idx].set_top(top); }

        res
    }

    // gets a slice of all the workers' queues.
    pub fn queues(&self) -> &[Queue] {
        &self.queues
    }

    // gets a slice of all the workers' arenas.
    pub fn arenas(&self) -> &[Arena] {
        &self.arenas
    }
}<commit_msg>Tweak ABORTS_BEFORE_BACKOFF<commit_after>use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use super::{Spawner, make_spawner};
use super::arena::Arena;
use super::job::Job;
use super::queue::{Queue, Stolen};
use super::rand::{Rng, XorShiftRng};

// Each worker lives on a specific thread and manages a job queue and allocator.
// When attempting to run jobs, it will first look in its own queue and then
// attempt to steal from its siblings.
pub struct Worker {
    queues: Arc<Vec<Queue>>,
    arenas: Arc<Vec<Arena>>,
    idx: usize, // the index of this worker's queue and pool in the Vec.
    rng: UnsafeCell<XorShiftRng>,
}

impl Worker {
    pub fn new(queues: Arc<Vec<Queue>>, arenas: Arc<Vec<Arena>>, idx: usize, rng: XorShiftRng)
    -> Self {
        Worker {
            queues: queues,
            arenas: arenas,
            idx: idx,
            rng: UnsafeCell::new(rng),
        }
    }
    // pop a job from the worker's queue, or steal one from another queue.
    unsafe fn pop_or_steal(&self) -> Option<*mut Job> {
        const ABORTS_BEFORE_BACKOFF: usize = 32;

        if let Some(job) = self.queues[self.idx].pop() {
            return Some(job);
        }

        let idx = (*self.rng.get()).gen::<usize>() % self.queues.len();

        if idx != self.idx {
            let mut aborts = 0;
            loop {
                aborts += 1;
                if aborts > ABORTS_BEFORE_BACKOFF {
                    return None;
                }

                match self.queues[idx].steal() {
                    Stolen::Success(job) => return Some(job),
                    Stolen::Empty => return None,
                    _ => {}
                }
            }
        } else {
            None
        }
    }

    // do a sweep through all the queues, saying whether all
    // were observed to be empty initially.
    fn clear_pass(&self) -> bool {
        let mut all_clear = true;
        for (idx, queue) in self.queues.iter().enumerate() {
            if idx != self.idx {
                loop {
                    match queue.steal() {
                        Stolen::Success(job) => {
                            all_clear = false;
                            unsafe { (*job).call(self) }
                        }
                        Stolen::Empty => break,
                        Stolen::Abort => {
                            all_clear = false;
                        }
                    }
                }
            } else {
                while let Some(job) = unsafe { queue.pop() } {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            }
        }

        all_clear
    }

    pub fn clear(&self) {
        while !self.clear_pass() {}
    }

    // run the next job.
    pub unsafe fn run_next(&self) {
        if let Some(job) = self.pop_or_steal() {
            (*job).call(self)
        }
    }

    // This must be called on the thread the worker is assigned to.
    pub unsafe fn submit_internal<F>(&self, counter: *const AtomicUsize, f: F)
        where F: Send + FnOnce(&Worker)
    {
        let job = Job::new(counter, f);
        let job_ptr = self.arenas[self.idx].alloc(job);
        self.queues[self.idx].push(job_ptr);
    }

    // construct a new spawning scope.
    // this waits for all jobs submitted internally to complete.
    pub fn scope<'pool, 'new, F, R>(&'pool self, f: F) -> R
        where F: 'new + FnOnce(&Spawner<'pool, 'new>) -> R,
              R: 'new,

    {
        let counter = AtomicUsize::new(0);
        let s = make_spawner(self, &counter);

        // store the top of the job arena before the scope is run.
        let top = self.arenas[self.idx].top();

        let res = f(&s);

        struct PanicGuard<'a>(&'a AtomicUsize);
        impl<'a> Drop for PanicGuard<'a> {
            fn drop(&mut self) {
                while self.0.load(Ordering::Acquire) > 0 {
                    ::std::thread::yield_now()
                }
            }
        }

        // if this thread panics while running a job, we need
        // to wait for other threads to finish the scoped jobs
        // before unwinding. this could result in a deadlock in cases
        // where many functions are panicking and no other threads exist
        // to finish jobs.
        let guard = PanicGuard(&counter);

        loop {
            let status = counter.load(Ordering::Acquire);
            if status == 0 { break }
            unsafe { self.run_next() }
        }

        ::std::mem::forget(guard);

        // once all jobs have completed from the scope, we can reset the arena
        // to its previous state. This only holds true if:
        //   - the arena is only used from this thread. this is already supposed to be true.
        //   - spawners cannot be cloned. If we could clone spawners, using one within another's
        //     scope could lead to jobs being overwritten.
        unsafe { self.arenas[self.idx].set_top(top); }

        res
    }

    // gets a slice of all the workers' queues.
    pub fn queues(&self) -> &[Queue] {
        &self.queues
    }

    // gets a slice of all the workers' arenas.
    pub fn arenas(&self) -> &[Arena] {
        &self.arenas
    }
}<|endoftext|>