<commit_before>#![crate_name = "uu_uniq"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::{Matches, Options};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
use std::str::FromStr;

static NAME: &'static str = "uniq";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq)]
enum Delimiters {
    Prepend,
    Separate,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

fn iter_ne<'a>(lhs: Box<Iterator<Item = char> + 'a>, rhs: Box<Iterator<Item = char> + 'a>) -> bool {
    lhs.ne(rhs)
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) {
        let mut lines: Vec<String> = vec![];
        let mut first_line_printed = false;
        let delimiters = &self.delimiters;
        let line_terminator = self.get_line_terminator();

        for io_line in reader.split(line_terminator) {
            let line = String::from_utf8(crash_if_err!(1, io_line)).unwrap();
            if !lines.is_empty() && self.cmp_keys(&lines[0], &line) {
                let print_delimiter = delimiters == &Delimiters::Prepend
                    || (delimiters == &Delimiters::Separate && first_line_printed);
                first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
                lines.truncate(0);
            }
            lines.push(line);
        }
        if !lines.is_empty() {
            let print_delimiter = delimiters == &Delimiters::Prepend
                || (delimiters == &Delimiters::Separate && first_line_printed);
            self.print_lines(writer, &lines, print_delimiter);
        }
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            if line.split_whitespace().count() > skip_fields {
                let mut field = 0;
                let mut i = 0;
                while field < skip_fields && i < line.len() {
                    while i < line.len() && line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    while i < line.len() && !line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    field = field + 1;
                }
                &line[i..]
            } else {
                ""
            }
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            '\n' as u8
        }
    }

    fn cmp_key<'a>(&'a self, line: &'a str) -> Box<Iterator<Item = char> + 'a> {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        let slice_start = self.slice_start.unwrap_or(0);
        let slice_stop = self.slice_stop.unwrap_or(len);
        if len > 0 {
            // fast path: we can avoid mapping chars to upper-case, if we don't want to ignore the case
            if !self.ignore_case {
                return Box::new(fields_to_check.chars().skip(slice_start).take(slice_stop));
            }

            Box::new(
                fields_to_check
                    .chars()
                    .skip(slice_start)
                    .take(slice_stop)
                    .map(move |c| match c {
                        'a'...'z' if self.ignore_case => ((c as u8) - 32) as char,
                        _ => c,
                    }),
            )
        } else {
            Box::new(fields_to_check.chars())
        }
    }

    fn print_lines<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        lines: &[String],
        print_delimiter: bool,
    ) -> bool {
        let mut first_line_printed = false;
        let mut count = if self.all_repeated { 1 } else { lines.len() };
        if lines.len() == 1 && !self.repeats_only || lines.len() > 1 && !self.uniques_only {
            self.print_line(writer, &lines[0], count, print_delimiter);
            first_line_printed = true;
            count += 1;
        }
        if self.all_repeated {
            for line in lines[1..].iter() {
                self.print_line(writer, line, count, print_delimiter && !first_line_printed);
                first_line_printed = true;
                count += 1;
            }
        }
        first_line_printed
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        print_delimiter: bool,
    ) {
        let line_terminator = self.get_line_terminator();

        if print_delimiter {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }

        crash_if_err!(
            1,
            if self.show_counts {
                writer.write_all(format!("{:7} {}", count, line).as_bytes())
            } else {
                writer.write_all(line.as_bytes())
            }
        );
        crash_if_err!(1, writer.write_all(&[line_terminator]));
    }
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &Matches) -> Option<T> {
    matches.opt_str(opt_name).map(|arg_str| {
        let opt_val: Option<T> = arg_str.parse().ok();
        opt_val.unwrap_or_else(|| crash!(1, "Invalid argument for {}: {}", opt_name, arg_str))
    })
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("c", "count", "prefix lines by the number of occurrences");
    opts.optflag("d", "repeated", "only print duplicate lines");
    opts.optflagopt(
        "D",
        "all-repeated",
        "print all duplicate lines delimit-method={none(default),prepend,separate} Delimiting is done with blank lines",
        "delimit-method"
    );
    opts.optopt(
        "f",
        "skip-fields",
        "avoid comparing the first N fields",
        "N",
    );
    opts.optopt(
        "s",
        "skip-chars",
        "avoid comparing the first N characters",
        "N",
    );
    opts.optopt(
        "w",
        "check-chars",
        "compare no more than N characters in lines",
        "N",
    );
    opts.optflag(
        "i",
        "ignore-case",
        "ignore differences in case when comparing",
    );
    opts.optflag("u", "unique", "only print unique lines");
    opts.optflag("z", "zero-terminated", "end lines with 0 byte, not newline");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", NAME);
        println!("");
        print!(
            "{}",
            opts.usage(
                "Filter adjacent matching lines from INPUT (or standard input),\n\
                 writing to OUTPUT (or standard output)."
            )
        );
        println!("");
        println!(
            "Note: '{0}' does not detect repeated lines unless they are adjacent.\n\
             You may want to sort the input first, or use 'sort -u' without '{0}'.\n",
            NAME
        );
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        let (in_file_name, out_file_name) = match matches.free.len() {
            0 => ("-".to_owned(), "-".to_owned()),
            1 => (matches.free[0].clone(), "-".to_owned()),
            2 => (matches.free[0].clone(), matches.free[1].clone()),
            _ => {
                crash!(1, "Extra operand: {}", matches.free[2]);
            }
        };
        let uniq = Uniq {
            repeats_only: matches.opt_present("repeated") || matches.opt_present("all-repeated"),
            uniques_only: matches.opt_present("unique"),
            all_repeated: matches.opt_present("all-repeated"),
            delimiters: match matches.opt_default("all-repeated", "none") {
                Some(ref opt_arg) if opt_arg != "none" => match &(*opt_arg.as_str()) {
                    "prepend" => Delimiters::Prepend,
                    "separate" => Delimiters::Separate,
                    _ => crash!(1, "Incorrect argument for all-repeated: {}", opt_arg),
                },
                _ => Delimiters::None,
            },
            show_counts: matches.opt_present("count"),
            skip_fields: opt_parsed("skip-fields", &matches),
            slice_start: opt_parsed("skip-chars", &matches),
            slice_stop: opt_parsed("check-chars", &matches),
            ignore_case: matches.opt_present("ignore-case"),
            zero_terminated: matches.opt_present("zero-terminated"),
        };
        uniq.print_uniq(
            &mut open_input_file(in_file_name),
            &mut open_output_file(out_file_name),
        );
    }
    0
}

fn open_input_file(in_file_name: String) -> BufReader<Box<Read + 'static>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path);
        let r = crash_if_err!(1, in_file);
        Box::new(r) as Box<Read>
    };
    BufReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> BufWriter<Box<Write + 'static>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let in_file = File::create(&path);
        let w = crash_if_err!(1, in_file);
        Box::new(w) as Box<Write>
    };
    BufWriter::new(out_file)
}
<commit_msg>uniq: add more fast-paths to avoid work<commit_after>#![crate_name = "uu_uniq"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::{Matches, Options};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
use std::str::FromStr;

static NAME: &'static str = "uniq";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq)]
enum Delimiters {
    Prepend,
    Separate,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

fn iter_ne<'a>(lhs: Box<Iterator<Item = char> + 'a>, rhs: Box<Iterator<Item = char> + 'a>) -> bool {
    lhs.ne(rhs)
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) {
        let mut lines: Vec<String> = vec![];
        let mut first_line_printed = false;
        let delimiters = &self.delimiters;
        let line_terminator = self.get_line_terminator();

        for io_line in reader.split(line_terminator) {
            let line = String::from_utf8(crash_if_err!(1, io_line)).unwrap();
            if !lines.is_empty() && self.cmp_keys(&lines[0], &line) {
                let print_delimiter = delimiters == &Delimiters::Prepend
                    || (delimiters == &Delimiters::Separate && first_line_printed);
                first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
                lines.truncate(0);
            }
            lines.push(line);
        }
        if !lines.is_empty() {
            let print_delimiter = delimiters == &Delimiters::Prepend
                || (delimiters == &Delimiters::Separate && first_line_printed);
            self.print_lines(writer, &lines, print_delimiter);
        }
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            if line.split_whitespace().count() > skip_fields {
                let mut field = 0;
                let mut i = 0;
                while field < skip_fields && i < line.len() {
                    while i < line.len() && line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    while i < line.len() && !line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    field = field + 1;
                }
                &line[i..]
            } else {
                ""
            }
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            '\n' as u8
        }
    }

    fn cmp_key<'a>(&'a self, line: &'a str) -> Box<Iterator<Item = char> + 'a> {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        let slice_start = self.slice_start.unwrap_or(0);
        let slice_stop = self.slice_stop.unwrap_or(len);
        if len > 0 {
            // fast path: avoid doing any work if there is no need to skip or map to lower-case
            if !self.ignore_case && slice_start == 0 && slice_stop == len {
                return Box::new(fields_to_check.chars());
            }

            // fast path: avoid skipping
            if self.ignore_case && slice_start == 0 && slice_stop == len {
                return Box::new(fields_to_check.chars().map(|c| match c {
                    'a'...'z' => ((c as u8) - 32) as char,
                    _ => c,
                }));
            }

            // fast path: we can avoid mapping chars to upper-case, if we don't want to ignore the case
            if !self.ignore_case {
                return Box::new(fields_to_check.chars().skip(slice_start).take(slice_stop));
            }

            Box::new(
                fields_to_check
                    .chars()
                    .skip(slice_start)
                    .take(slice_stop)
                    .map(|c| match c {
                        'a'...'z' => ((c as u8) - 32) as char,
                        _ => c,
                    }),
            )
        } else {
            Box::new(fields_to_check.chars())
        }
    }

    fn print_lines<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        lines: &[String],
        print_delimiter: bool,
    ) -> bool {
        let mut first_line_printed = false;
        let mut count = if self.all_repeated { 1 } else { lines.len() };
        if lines.len() == 1 && !self.repeats_only || lines.len() > 1 && !self.uniques_only {
            self.print_line(writer, &lines[0], count, print_delimiter);
            first_line_printed = true;
            count += 1;
        }
        if self.all_repeated {
            for line in lines[1..].iter() {
                self.print_line(writer, line, count, print_delimiter && !first_line_printed);
                first_line_printed = true;
                count += 1;
            }
        }
        first_line_printed
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        print_delimiter: bool,
    ) {
        let line_terminator = self.get_line_terminator();

        if print_delimiter {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }

        crash_if_err!(
            1,
            if self.show_counts {
                writer.write_all(format!("{:7} {}", count, line).as_bytes())
            } else {
                writer.write_all(line.as_bytes())
            }
        );
        crash_if_err!(1, writer.write_all(&[line_terminator]));
    }
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &Matches) -> Option<T> {
    matches.opt_str(opt_name).map(|arg_str| {
        let opt_val: Option<T> = arg_str.parse().ok();
        opt_val.unwrap_or_else(|| crash!(1, "Invalid argument for {}: {}", opt_name, arg_str))
    })
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("c", "count", "prefix lines by the number of occurrences");
    opts.optflag("d", "repeated", "only print duplicate lines");
    opts.optflagopt(
        "D",
        "all-repeated",
        "print all duplicate lines delimit-method={none(default),prepend,separate} Delimiting is done with blank lines",
        "delimit-method"
    );
    opts.optopt(
        "f",
        "skip-fields",
        "avoid comparing the first N fields",
        "N",
    );
    opts.optopt(
        "s",
        "skip-chars",
        "avoid comparing the first N characters",
        "N",
    );
    opts.optopt(
        "w",
        "check-chars",
        "compare no more than N characters in lines",
        "N",
    );
    opts.optflag(
        "i",
        "ignore-case",
        "ignore differences in case when comparing",
    );
    opts.optflag("u", "unique", "only print unique lines");
    opts.optflag("z", "zero-terminated", "end lines with 0 byte, not newline");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", NAME);
        println!("");
        print!(
            "{}",
            opts.usage(
                "Filter adjacent matching lines from INPUT (or standard input),\n\
                 writing to OUTPUT (or standard output)."
            )
        );
        println!("");
        println!(
            "Note: '{0}' does not detect repeated lines unless they are adjacent.\n\
             You may want to sort the input first, or use 'sort -u' without '{0}'.\n",
            NAME
        );
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        let (in_file_name, out_file_name) = match matches.free.len() {
            0 => ("-".to_owned(), "-".to_owned()),
            1 => (matches.free[0].clone(), "-".to_owned()),
            2 => (matches.free[0].clone(), matches.free[1].clone()),
            _ => {
                crash!(1, "Extra operand: {}", matches.free[2]);
            }
        };
        let uniq = Uniq {
            repeats_only: matches.opt_present("repeated") || matches.opt_present("all-repeated"),
            uniques_only: matches.opt_present("unique"),
            all_repeated: matches.opt_present("all-repeated"),
            delimiters: match matches.opt_default("all-repeated", "none") {
                Some(ref opt_arg) if opt_arg != "none" => match &(*opt_arg.as_str()) {
                    "prepend" => Delimiters::Prepend,
                    "separate" => Delimiters::Separate,
                    _ => crash!(1, "Incorrect argument for all-repeated: {}", opt_arg),
                },
                _ => Delimiters::None,
            },
            show_counts: matches.opt_present("count"),
            skip_fields: opt_parsed("skip-fields", &matches),
            slice_start: opt_parsed("skip-chars", &matches),
            slice_stop: opt_parsed("check-chars", &matches),
            ignore_case: matches.opt_present("ignore-case"),
            zero_terminated: matches.opt_present("zero-terminated"),
        };
        uniq.print_uniq(
            &mut open_input_file(in_file_name),
            &mut open_output_file(out_file_name),
        );
    }
    0
}

fn open_input_file(in_file_name: String) -> BufReader<Box<Read + 'static>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path);
        let r = crash_if_err!(1, in_file);
        Box::new(r) as Box<Read>
    };
    BufReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> BufWriter<Box<Write + 'static>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let in_file = File::create(&path);
        let w = crash_if_err!(1, in_file);
        Box::new(w) as Box<Write>
    };
    BufWriter::new(out_file)
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use {
    CommandResult,
    Host,
    Providers,
    Result,
    Cpu, Os, Telemetry,
};
use command::CommandTarget;
use directory::DirectoryTarget;
use error::Error;
use file::{FileTarget, FileOwner};
use package::PackageTarget;
use regex::Regex;
use service::ServiceTarget;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
use super::{default_base as default, Target, unix_base as unix};
use telemetry::TelemetryTarget;

//
// Command
//

impl CommandTarget for Target {
    #[allow(unused_variables)]
    fn exec(host: &mut Host, cmd: &str) -> Result<CommandResult> {
        default::command_exec(cmd)
    }
}

//
// Directory
//

impl<P: AsRef<Path>> DirectoryTarget<P> for Target {
    #[allow(unused_variables)]
    fn directory_is_directory(host: &mut Host, path: P) -> Result<bool> {
        default::directory_is_directory(path)
    }

    #[allow(unused_variables)]
    fn directory_exists(host: &mut Host, path: P) -> Result<bool> {
        default::file_exists(path)
    }

    #[allow(unused_variables)]
    fn directory_create(host: &mut Host, path: P, recursive: bool) -> Result<()> {
        default::directory_create(path, recursive)
    }

    #[allow(unused_variables)]
    fn directory_delete(host: &mut Host, path: P, recursive: bool) -> Result<()> {
        default::directory_delete(path, recursive)
    }

    #[allow(unused_variables)]
    fn directory_mv(host: &mut Host, path: P, new_path: P) -> Result<()> {
        default::file_mv(path, new_path)
    }

    #[allow(unused_variables)]
    fn directory_get_owner(host: &mut Host, path: P) -> Result<FileOwner> {
        unix::file_get_owner(path)
    }

    #[allow(unused_variables)]
    fn directory_set_owner(host: &mut Host, path: P, user: &str, group: &str) -> Result<()> {
        default::file_set_owner(path, user, group)
    }

    #[allow(unused_variables)]
    fn directory_get_mode(host: &mut Host, path: P) -> Result<u16> {
        unix::file_get_mode(path)
    }

    #[allow(unused_variables)]
    fn directory_set_mode(host: &mut Host, path: P, mode: u16) -> Result<()> {
        default::file_set_mode(path, mode)
    }
}

//
// File
//

impl<P: AsRef<Path>> FileTarget<P> for Target {
    #[allow(unused_variables)]
    fn file_is_file(host: &mut Host, path: P) -> Result<bool> {
        default::file_is_file(path)
    }

    #[allow(unused_variables)]
    fn file_exists(host: &mut Host, path: P) -> Result<bool> {
        default::file_exists(path)
    }

    #[allow(unused_variables)]
    fn file_delete(host: &mut Host, path: P) -> Result<()> {
        default::file_delete(path)
    }

    #[allow(unused_variables)]
    fn file_mv(host: &mut Host, path: P, new_path: P) -> Result<()> {
        default::file_mv(path, new_path)
    }

    #[allow(unused_variables)]
    fn file_copy(host: &mut Host, path: P, new_path: P) -> Result<()> {
        default::file_copy(path, new_path)
    }

    #[allow(unused_variables)]
    fn file_get_owner(host: &mut Host, path: P) -> Result<FileOwner> {
        unix::file_get_owner(path)
    }

    #[allow(unused_variables)]
    fn file_set_owner(host: &mut Host, path: P, user: &str, group: &str) -> Result<()> {
        default::file_set_owner(path, user, group)
    }

    #[allow(unused_variables)]
    fn file_get_mode(host: &mut Host, path: P) -> Result<u16> {
        unix::file_get_mode(path)
    }

    #[allow(unused_variables)]
    fn file_set_mode(host: &mut Host, path: P, mode: u16) -> Result<()> {
        default::file_set_mode(path, mode)
    }
}

//
// Package
//

impl PackageTarget for Target {
    fn default_provider(host: &mut Host) -> Result<Providers> {
        default::default_provider(host, vec![Providers::Pkg, Providers::Ports])
    }
}

//
// Service
//

impl ServiceTarget for Target {
    #[allow(unused_variables)]
    fn service_action(host: &mut Host, name: &str, action: &str) -> Result<Option<CommandResult>> {
        let mut rc_conf = try!(OpenOptions::new().read(true).write(true).open("/etc/rc.conf"));
        let mut rc = String::new();
        try!(rc_conf.read_to_string(&mut rc));

        let match_daemon = Regex::new(&format!("(?m)^\\s*{}_enable\\s*=\\s*[\"']{{0,1}}(?:YES|yes)[\"']{{0,1}}\n?", name)).unwrap();

        match action {
            "enable" => {
                if ! match_daemon.is_match(&rc) {
                    let newline = if rc.ends_with("\n") { "" } else { "\n" };
                    try!(rc_conf.write_all(&format!("{}{}_enable=\"YES\"\n", newline, name).into_bytes()));
                    try!(rc_conf.sync_data());

                    Ok(Some(CommandResult {
                        exit_code: 0,
                        stdout: String::new(),
                        stderr: String::new(),
                    }))
                } else {
                    Ok(None)
                }
            },
            "disable" => {
                if match_daemon.is_match(&rc) {
                    let replace = match_daemon.replace(&rc, "").trim().to_string();
                    try!(rc_conf.seek(SeekFrom::Start(0)));
                    try!(rc_conf.set_len(replace.len() as u64));
                    try!(rc_conf.write_all(replace.as_bytes()));
                    try!(rc_conf.sync_data());

                    Ok(Some(CommandResult {
                        exit_code: 0,
                        stdout: String::new(),
                        stderr: String::new(),
                    }))
                } else {
                    Ok(None)
                }
            },
            "start" | "stop" | "restart" if ! match_daemon.is_match(&rc) => {
                default::service_action(name, &format!("one{}", action))
            },
            _ => default::service_action(name, action),
        }
    }
}

//
// Telemetry
//

impl TelemetryTarget for Target {
    #[allow(unused_variables)]
    fn telemetry_init(host: &mut Host) -> Result<Telemetry> {
        let cpu_vendor = try!(telemetry_cpu_vendor());
        let cpu_brand = try!(unix::get_sysctl_item("hw\\.model"));
        let hostname = try!(default::hostname());
        let os_version = try!(unix::version());

        Ok(Telemetry::new(
            Cpu::new(
                &cpu_vendor,
                &cpu_brand,
                try!(try!(unix::get_sysctl_item("hw\\.ncpu")).parse::<u32>()),
            ),
            try!(default::fs()),
            &hostname,
            try!(try!(unix::get_sysctl_item("hw\\.physmem")).parse::<u64>()),
            try!(unix::net()),
            Os::new(env::consts::ARCH, "unix", "freebsd", &os_version),
        ))
    }
}

fn telemetry_cpu_vendor() -> Result<String> {
    let mut fh = try!(File::open("/var/run/dmesg.boot"));
    let mut fc = String::new();
    fh.read_to_string(&mut fc).unwrap();

    let regex = Regex::new(r#"(?m)^CPU:.+$\n\s+Origin="([A-Za-z]+)""#).unwrap();
    if let Some(cap) = regex.captures(&fc) {
        Ok(cap.at(1).unwrap().to_string())
    } else {
        Err(Error::Generic("Could not match CPU vendor".to_string()))
    }
}

#[cfg(test)]
mod tests {
    use Host;
    use package::PackageTarget;
    use target::Target;
    use telemetry::TelemetryTarget;

    #[test]
    fn test_package_default_provider() {
        let mut host = Host::new();
        let result = Target::default_provider(&mut host);
        assert!(result.is_ok());
    }

    #[test]
    fn test_telemetry_init() {
        let mut host = Host::new();
        let result = Target::telemetry_init(&mut host);
        assert!(result.is_ok());
    }
}
<commit_msg>Added missing Path use<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use {
    CommandResult,
    Host,
    Providers,
    Result,
    Cpu, Os, Telemetry,
};
use command::CommandTarget;
use directory::DirectoryTarget;
use error::Error;
use file::{FileTarget, FileOwner};
use package::PackageTarget;
use regex::Regex;
use service::ServiceTarget;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::Path;
use super::{default_base as default, Target, unix_base as unix};
use telemetry::TelemetryTarget;

//
// Command
//

impl CommandTarget for Target {
    #[allow(unused_variables)]
    fn exec(host: &mut Host, cmd: &str) -> Result<CommandResult> {
        default::command_exec(cmd)
    }
}

//
// Directory
//

impl<P: AsRef<Path>> DirectoryTarget<P> for Target {
    #[allow(unused_variables)]
    fn directory_is_directory(host: &mut Host, path: P) -> Result<bool> {
        default::directory_is_directory(path)
    }

    #[allow(unused_variables)]
    fn directory_exists(host: &mut Host, path: P) -> Result<bool> {
        default::file_exists(path)
    }

    #[allow(unused_variables)]
    fn directory_create(host: &mut Host, path: P, recursive: bool) -> Result<()> {
        default::directory_create(path, recursive)
    }

    #[allow(unused_variables)]
    fn directory_delete(host: &mut Host, path: P, recursive: bool) -> Result<()> {
        default::directory_delete(path, recursive)
    }

    #[allow(unused_variables)]
    fn directory_mv(host: &mut Host, path: P, new_path: P) -> Result<()> {
        default::file_mv(path, new_path)
    }

    #[allow(unused_variables)]
    fn directory_get_owner(host: &mut Host, path: P) -> Result<FileOwner> {
        unix::file_get_owner(path)
    }

    #[allow(unused_variables)]
    fn directory_set_owner(host: &mut Host, path: P, user: &str, group: &str) -> Result<()> {
        default::file_set_owner(path, user, group)
    }

    #[allow(unused_variables)]
    fn directory_get_mode(host: &mut Host, path: P) -> Result<u16> {
        unix::file_get_mode(path)
    }

    #[allow(unused_variables)]
    fn directory_set_mode(host: &mut Host, path: P, mode: u16) -> Result<()> {
        default::file_set_mode(path, mode)
    }
}

//
// File
//

impl<P: AsRef<Path>> FileTarget<P> for Target {
    #[allow(unused_variables)]
    fn file_is_file(host: &mut Host, path: P) -> Result<bool> {
        default::file_is_file(path)
    }

    #[allow(unused_variables)]
    fn file_exists(host: &mut Host, path: P) -> Result<bool> {
        default::file_exists(path)
    }

    #[allow(unused_variables)]
    fn file_delete(host: &mut Host, path: P) -> Result<()> {
        default::file_delete(path)
    }

    #[allow(unused_variables)]
    fn file_mv(host: &mut Host, path: P, new_path: P) -> Result<()> {
        default::file_mv(path, new_path)
    }

    #[allow(unused_variables)]
    fn file_copy(host: &mut Host, path: P, new_path: P) -> Result<()> {
        default::file_copy(path, new_path)
    }

    #[allow(unused_variables)]
    fn file_get_owner(host: &mut Host, path: P) -> Result<FileOwner> {
        unix::file_get_owner(path)
    }

    #[allow(unused_variables)]
    fn file_set_owner(host: &mut Host, path: P, user: &str, group: &str) -> Result<()> {
        default::file_set_owner(path, user, group)
    }

    #[allow(unused_variables)]
    fn file_get_mode(host: &mut Host, path: P) -> Result<u16> {
        unix::file_get_mode(path)
    }

    #[allow(unused_variables)]
    fn file_set_mode(host: &mut Host, path: P, mode: u16) -> Result<()> {
        default::file_set_mode(path, mode)
    }
}

//
// Package
//

impl PackageTarget for Target {
    fn default_provider(host: &mut Host) -> Result<Providers> {
        default::default_provider(host, vec![Providers::Pkg, Providers::Ports])
    }
}

//
// Service
//

impl ServiceTarget for Target {
    #[allow(unused_variables)]
    fn service_action(host: &mut Host, name: &str, action: &str) -> Result<Option<CommandResult>> {
        let mut rc_conf = try!(OpenOptions::new().read(true).write(true).open("/etc/rc.conf"));
        let mut rc = String::new();
        try!(rc_conf.read_to_string(&mut rc));

        let match_daemon = Regex::new(&format!("(?m)^\\s*{}_enable\\s*=\\s*[\"']{{0,1}}(?:YES|yes)[\"']{{0,1}}\n?", name)).unwrap();

        match action {
            "enable" => {
                if ! match_daemon.is_match(&rc) {
                    let newline = if rc.ends_with("\n") { "" } else { "\n" };
                    try!(rc_conf.write_all(&format!("{}{}_enable=\"YES\"\n", newline, name).into_bytes()));
                    try!(rc_conf.sync_data());

                    Ok(Some(CommandResult {
                        exit_code: 0,
                        stdout: String::new(),
                        stderr: String::new(),
                    }))
                } else {
                    Ok(None)
                }
            },
            "disable" => {
                if match_daemon.is_match(&rc) {
                    let replace = match_daemon.replace(&rc, "").trim().to_string();
                    try!(rc_conf.seek(SeekFrom::Start(0)));
                    try!(rc_conf.set_len(replace.len() as u64));
                    try!(rc_conf.write_all(replace.as_bytes()));
                    try!(rc_conf.sync_data());

                    Ok(Some(CommandResult {
                        exit_code: 0,
                        stdout: String::new(),
                        stderr: String::new(),
                    }))
                } else {
                    Ok(None)
                }
            },
            "start" | "stop" | "restart" if ! match_daemon.is_match(&rc) => {
                default::service_action(name, &format!("one{}", action))
            },
            _ => default::service_action(name, action),
        }
    }
}

//
// Telemetry
//

impl TelemetryTarget for Target {
    #[allow(unused_variables)]
    fn telemetry_init(host: &mut Host) -> Result<Telemetry> {
        let cpu_vendor = try!(telemetry_cpu_vendor());
        let cpu_brand = try!(unix::get_sysctl_item("hw\\.model"));
        let hostname = try!(default::hostname());
        let os_version = try!(unix::version());

        Ok(Telemetry::new(
            Cpu::new(
                &cpu_vendor,
                &cpu_brand,
                try!(try!(unix::get_sysctl_item("hw\\.ncpu")).parse::<u32>()),
            ),
            try!(default::fs()),
            &hostname,
            try!(try!(unix::get_sysctl_item("hw\\.physmem")).parse::<u64>()),
            try!(unix::net()),
            Os::new(env::consts::ARCH, "unix", "freebsd", &os_version),
        ))
    }
}

fn telemetry_cpu_vendor() -> Result<String> {
    let mut fh = try!(File::open("/var/run/dmesg.boot"));
    let mut fc = String::new();
    fh.read_to_string(&mut fc).unwrap();

    let regex = Regex::new(r#"(?m)^CPU:.+$\n\s+Origin="([A-Za-z]+)""#).unwrap();
    if let Some(cap) = regex.captures(&fc) {
        Ok(cap.at(1).unwrap().to_string())
    } else {
        Err(Error::Generic("Could not match CPU vendor".to_string()))
    }
}

#[cfg(test)]
mod tests {
    use Host;
    use package::PackageTarget;
    use target::Target;
    use telemetry::TelemetryTarget;

    #[test]
    fn test_package_default_provider() {
        let mut host = Host::new();
        let result = Target::default_provider(&mut host);
        assert!(result.is_ok());
    }

    #[test]
    fn test_telemetry_init() {
        let mut host = Host::new();
        let result = Target::telemetry_init(&mut host);
        assert!(result.is_ok());
    }
}
<|endoftext|>


<commit_before>use common::ReadExt;
use gfx::Texture;
use gl;
use std::ptr::copy_nonoverlapping;
use std::vec::Vec;
use types::WadTextureHeader;

pub struct Image {
    width: usize,
    height: usize,
    x_offset: isize,
    y_offset: isize,
    pixels: Vec<u16>,
}

impl Image {
    pub fn new(width: usize, height: usize) -> Image {
        Image {
            width: width,
            height: height,
            x_offset: 0,
            y_offset: 0,
            pixels: vec![0xff00; width * height],
        }
    }

    pub fn new_from_header(header: &WadTextureHeader) -> Image {
        Image::new(header.width as usize, header.height as usize)
    }

    pub fn from_buffer(buffer: &[u8]) -> Image {
        let mut reader = buffer;
        let width = reader.read_binary::<u16>().unwrap() as usize;
        let height = reader.read_binary::<u16>().unwrap() as usize;
        let x_offset = reader.read_binary::<i16>().unwrap() as isize;
        let y_offset = reader.read_binary::<i16>().unwrap() as isize;

        let mut pixels = vec![!0; width * height];
        // Sorry for the messy/unsafe code, but the array bounds checks in this
        // tight loop make it 6x slower.
        for i_column in 0 .. width as isize { unsafe {
            // Each column is defined as a number of vertical `runs' which are
            // defined starting at `offset' in the buffer.
            let offset = reader.read_binary::<u32>().unwrap() as isize;
            let mut src_ptr = buffer.as_ptr().offset(offset);
            'this_column: loop {
                // The first byte contains the vertical coordinate of the run's
                // start.
                let row_start = *src_ptr as isize; src_ptr = src_ptr.offset(1);

                // Pointer to the beginning of the run in `pixels'.
                let mut dest_ptr = pixels
                    .as_mut_ptr().offset(row_start * width as isize + i_column);

                // The special value of 255 means this is the last run in the
                // column, so move on to the next one.
                if row_start == 255 { break 'this_column; }

                // The second byte is the length of this run. Skip an additional
                // byte which is ignored for some reason.
                let run_length = *src_ptr as isize; src_ptr = src_ptr.offset(2);

                let src_end = src_ptr.offset(run_length);  // Ptr to end of run.
                while src_ptr < src_end {
                    // Copy one byte converting it into an opaque pixels (high
                    // bits are zero) and advance the pointers.
                    *dest_ptr = *src_ptr as u16;
                    dest_ptr = dest_ptr.offset(width as isize);
                    src_ptr = src_ptr.offset(1);
                }
                // And another ignored byte after the run.
                src_ptr = src_ptr.offset(1);
            }
        }}
        let pixels = pixels;

        Image { width: width,
                height: height,
                x_offset: x_offset,
                y_offset: y_offset,
                pixels: pixels }
    }

    pub fn blit(&mut self, source: &Image, x_offset: isize, y_offset: isize,
                ignore_transparency: bool) {
        // Figure out the region in source which is not out of bounds when
        // copied into self.
        let y_start = if y_offset < 0 { (-y_offset) as usize } else { 0 };
        let x_start = if x_offset < 0 { (-x_offset) as usize } else { 0 };
        let y_end = if self.height as isize > source.height as isize + y_offset {
            source.height
        } else {
            (self.height as isize - y_offset) as usize
        };
        let x_end = if self.width as isize > source.width as isize + x_offset {
            source.width
        } else {
            (self.width as isize - x_offset) as usize
        };

        if ignore_transparency {
            // If we don't care about transparency we can memcpy row by row.
            let src_pitch = source.width as isize;
            let dest_pitch = self.width as isize;
            let copy_width = x_end - x_start;
            let copy_height = (y_end - y_start) as isize;
            let (x_start, y_start) = (x_start as isize, y_start as isize);
            unsafe {
                let mut src_ptr = source.pixels.as_ptr().offset(
                    x_start + y_start * src_pitch);
                let mut dest_ptr = self.pixels.as_mut_ptr().offset(
                    x_start + x_offset + (y_start + y_offset) * dest_pitch);

                let src_end = src_ptr.offset(copy_height * src_pitch);
                while src_ptr < src_end {
                    copy_nonoverlapping(src_ptr, dest_ptr, copy_width);
                    src_ptr = src_ptr.offset(src_pitch);
                    dest_ptr = dest_ptr.offset(dest_pitch);
                }
            }
        } else {
            // Only copy pixels whose high bits are not set.
            let dest_ptr = self.pixels.as_mut_ptr();
            let src_ptr = source.pixels.as_ptr();
            for src_y in y_start .. y_end {
                let dest_y = (src_y as isize + y_offset) as usize;
                for src_x in x_start .. x_end {
                    let dest_x = (src_x as isize + x_offset) as usize;

                    let (dest_x, dest_y) = (dest_x, dest_y);
                    let dest_index = (dest_x + dest_y * self.width) as isize;
                    let src_index = (src_x + src_y * source.width) as isize;

                    unsafe {
                        // `Blending' is a simple copy/no copy, but using bit
                        // ops we can avoid branching.
                        let src_pixel = *src_ptr.offset(src_index);
                        let dest_pixel = dest_ptr.offset(dest_index);
                        let blend = 0u16.wrapping_sub(src_pixel >> 15);
                        *dest_pixel = (src_pixel & !blend) |
                                      (*dest_pixel & blend);
                    }
                }
            }
        }
    }

    pub fn to_texture(&self) -> Texture {
        let mut tex = Texture::new(gl::TEXTURE_2D);
        tex.bind(gl::TEXTURE0);
        tex.set_filters_nearest()
           .data_rg_u8(0, self.width, self.height, &self.pixels)
           .unbind(gl::TEXTURE0);
        tex
    }

    pub fn x_offset(&self) -> isize { self.x_offset }
    pub fn y_offset(&self) -> isize { self.y_offset }

    pub fn width(&self) -> usize { self.width }
    pub fn height(&self) -> usize { self.height }

    pub fn num_pixels(&self) -> usize { self.pixels.len() }

    pub fn pixels(&self) -> &[u16] { &self.pixels }

    // Commented out due to a bug in SDL2.
    //pub fn save_bmp(&self, palette: &[[u8; 3]; 256]) {
    //    use ::sdl2::surface::Surface;
    //    let mut pixels = vec![0u8; 3 * self.width * self.height];
    //    for (index, pixel) in self.pixels.iter().enumerate() {
    //        let pixel = palette[(pixel & 0xff) as usize];
    //        pixels[index * 3] = pixel[2];
    //        pixels[index * 3 + 1] = pixel[1];
    //        pixels[index * 3 + 2] = pixel[0];
    //    }
    //    Surface::from_data(&mut pixels[..], self.width as i32, self.height as i32,
    //                       24, self.width as i32 * 3,
    //                       0xff0000, 0x00ff00, 0x0000ff, 0x0)
    //        .unwrap()
    //        .save_bmp("/home/cristi/temp.bmp".as_ref())
    //        .unwrap();
    //}
}

<commit_msg>wad: add save_bmp to image<commit_after>use common::ReadExt;
use gfx::Texture;
use gl;
use std::ptr::copy_nonoverlapping;
use std::vec::Vec;
use types::WadTextureHeader;
use sdl2::pixels::PixelFormatEnum;
use std::path::Path;

pub struct Image {
    width: usize,
    height: usize,
    x_offset: isize,
    y_offset: isize,
    pixels: Vec<u16>,
}

impl Image {
    pub fn new(width: usize, height: usize) -> Image {
        Image {
            width: width,
            height: height,
            x_offset: 0,
            y_offset: 0,
            pixels: vec![0xff00; width * height],
        }
    }

    pub fn new_from_header(header: &WadTextureHeader) -> Image {
        Image::new(header.width as usize, header.height as usize)
    }

    pub fn from_buffer(buffer: &[u8]) -> Image {
        let mut reader = buffer;
        let width = reader.read_binary::<u16>().unwrap() as usize;
        let height = reader.read_binary::<u16>().unwrap() as usize;
        let x_offset = reader.read_binary::<i16>().unwrap() as isize;
        let y_offset = reader.read_binary::<i16>().unwrap() as isize;

        let mut pixels = vec![!0; width * height];
        // Sorry for the messy/unsafe code, but the array bounds checks in this
        // tight loop make it 6x slower.
        for i_column in 0 .. width as isize { unsafe {
            // Each column is defined as a number of vertical `runs' which are
            // defined starting at `offset' in the buffer.
            let offset = reader.read_binary::<u32>().unwrap() as isize;
            let mut src_ptr = buffer.as_ptr().offset(offset);
            'this_column: loop {
                // The first byte contains the vertical coordinate of the run's
                // start.
                let row_start = *src_ptr as isize; src_ptr = src_ptr.offset(1);

                // Pointer to the beginning of the run in `pixels'.
                let mut dest_ptr = pixels
                    .as_mut_ptr().offset(row_start * width as isize + i_column);

                // The special value of 255 means this is the last run in the
                // column, so move on to the next one.
                if row_start == 255 { break 'this_column; }

                // The second byte is the length of this run. Skip an additional
                // byte which is ignored for some reason.
                let run_length = *src_ptr as isize; src_ptr = src_ptr.offset(2);

                let src_end = src_ptr.offset(run_length);  // Ptr to end of run.
                while src_ptr < src_end {
                    // Copy one byte converting it into an opaque pixels (high
                    // bits are zero) and advance the pointers.
                    *dest_ptr = *src_ptr as u16;
                    dest_ptr = dest_ptr.offset(width as isize);
                    src_ptr = src_ptr.offset(1);
                }
                // And another ignored byte after the run.
                src_ptr = src_ptr.offset(1);
            }
        }}
        let pixels = pixels;

        Image { width: width,
                height: height,
                x_offset: x_offset,
                y_offset: y_offset,
                pixels: pixels }
    }

    pub fn blit(&mut self, source: &Image, x_offset: isize, y_offset: isize,
                ignore_transparency: bool) {
        // Figure out the region in source which is not out of bounds when
        // copied into self.
        let y_start = if y_offset < 0 { (-y_offset) as usize } else { 0 };
        let x_start = if x_offset < 0 { (-x_offset) as usize } else { 0 };
        let y_end = if self.height as isize > source.height as isize + y_offset {
            source.height
        } else {
            (self.height as isize - y_offset) as usize
        };
        let x_end = if self.width as isize > source.width as isize + x_offset {
            source.width
        } else {
            (self.width as isize - x_offset) as usize
        };

        if ignore_transparency {
            // If we don't care about transparency we can memcpy row by row.
            let src_pitch = source.width as isize;
            let dest_pitch = self.width as isize;
            let copy_width = x_end - x_start;
            let copy_height = (y_end - y_start) as isize;
            let (x_start, y_start) = (x_start as isize, y_start as isize);
            unsafe {
                let mut src_ptr = source.pixels.as_ptr().offset(
                    x_start + y_start * src_pitch);
                let mut dest_ptr = self.pixels.as_mut_ptr().offset(
                    x_start + x_offset + (y_start + y_offset) * dest_pitch);

                let src_end = src_ptr.offset(copy_height * src_pitch);
                while src_ptr < src_end {
                    copy_nonoverlapping(src_ptr, dest_ptr, copy_width);
                    src_ptr = src_ptr.offset(src_pitch);
                    dest_ptr = dest_ptr.offset(dest_pitch);
                }
            }
        } else {
            // Only copy pixels whose high bits are not set.
            let dest_ptr = self.pixels.as_mut_ptr();
            let src_ptr = source.pixels.as_ptr();
            for src_y in y_start .. y_end {
                let dest_y = (src_y as isize + y_offset) as usize;
                for src_x in x_start .. x_end {
                    let dest_x = (src_x as isize + x_offset) as usize;

                    let (dest_x, dest_y) = (dest_x, dest_y);
                    let dest_index = (dest_x + dest_y * self.width) as isize;
                    let src_index = (src_x + src_y * source.width) as isize;

                    unsafe {
                        // `Blending' is a simple copy/no copy, but using bit
                        // ops we can avoid branching.
                        let src_pixel = *src_ptr.offset(src_index);
                        let dest_pixel = dest_ptr.offset(dest_index);
                        let blend = 0u16.wrapping_sub(src_pixel >> 15);
                        *dest_pixel = (src_pixel & !blend) |
                                      (*dest_pixel & blend);
                    }
                }
            }
        }
    }

    pub fn to_texture(&self) -> Texture {
        let mut tex = Texture::new(gl::TEXTURE_2D);
        tex.bind(gl::TEXTURE0);
        tex.set_filters_nearest()
           .data_rg_u8(0, self.width, self.height, &self.pixels)
           .unbind(gl::TEXTURE0);
        tex
    }

    pub fn x_offset(&self) -> isize { self.x_offset }
    pub fn y_offset(&self) -> isize { self.y_offset }

    pub fn width(&self) -> usize { self.width }
    pub fn height(&self) -> usize { self.height }

    pub fn num_pixels(&self) -> usize { self.pixels.len() }

    pub fn pixels(&self) -> &[u16] { &self.pixels }

    pub fn save_bmp<P: AsRef<Path>>(&self, palette: &[[u8; 3]; 256], path: &P) {
        use ::sdl2::surface::Surface;
        let mut pixels = vec![0u8; 3 * self.width * self.height];
        for (index, pixel) in self.pixels.iter().enumerate() {
            let pixel = palette[(pixel & 0xff) as usize];
            pixels[index * 3] = pixel[2];
            pixels[index * 3 + 1] = pixel[1];
            pixels[index * 3 + 2] = pixel[0];
        }
        Surface::from_data(&mut pixels[..],
                           self.width as u32,
                           self.height as u32,
                           self.width as u32 * 3,
                           PixelFormatEnum::BGR24)
            .unwrap()
            .save_bmp(path)
            .unwrap();
    }
}

<|endoftext|>


<commit_before>use xen::hypercall::hypercall2;
use xen::hypercall::HyperCalls;

use ::arch::defs::Ulong;

#[allow(dead_code)]
enum SchedOp {
    Yield = 0,
    Block = 1,
    Shutdown = 2,
    Poll = 3,
    RemoteShutdown = 4,
    ShutdownCode = 5,
    Watchdog = 6,
}

#[allow(dead_code)]
fn sched_op(op: SchedOp, sched: Ulong) -> i32 {
    hypercall2(HyperCalls::SchedOp, op as Ulong, sched) as i32
}
<commit_msg>sched: Add yield_cpu() function<commit_after>use xen::hypercall::hypercall2;
use xen::hypercall::HyperCalls;

use ::arch::defs::Ulong;

#[allow(dead_code)]
enum SchedOp {
    Yield = 0,
    Block = 1,
    Shutdown = 2,
    Poll = 3,
    RemoteShutdown = 4,
    ShutdownCode = 5,
    Watchdog = 6,
}

#[allow(dead_code)]
fn sched_op(op: SchedOp, sched: Ulong) -> i32 {
    hypercall2(HyperCalls::SchedOp, op as Ulong, sched) as i32
}

pub fn yield_cpu() -> i32 {
    sched_op(SchedOp::Yield, 0)
}
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
use std::cmp::Ordering;

use super::command::capture_command;
use crate::update_service::Platform;
use crate::util::errors::SetupError;
use lazy_static::lazy_static;
use regex::bytes::Regex as BinRegex;
use regex::Regex;
use tokio::fs;

use super::errors::AnyError;

lazy_static! {
	static ref LDCONFIG_STDC_RE: Regex = Regex::new(r"libstdc\+\+.* => (.+)").unwrap();
	static ref LDD_VERSION_RE: BinRegex = BinRegex::new(r"^ldd.*(.+)\.(.+)\s").unwrap();
	static ref LIBSTD_CXX_VERSION_RE: BinRegex =
		BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap();
	static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 18);
	static ref MIN_LDD_VERSION: SimpleSemver = SimpleSemver::new(2, 17, 0);
}

const NIXOS_TEST_PATH: &str = "/etc/NIXOS";

pub struct PreReqChecker {}

impl Default for PreReqChecker {
	fn default() -> Self {
		Self::new()
	}
}

impl PreReqChecker {
	pub fn new() -> PreReqChecker {
		PreReqChecker {}
	}

	#[cfg(not(target_os = "linux"))]
	pub async fn verify(&self) -> Result<Platform, AnyError> {
		Platform::env_default().ok_or_else(|| {
			SetupError("VS Code is not supported on this platform".to_owned()).into()
		})
	}

	#[cfg(target_os = "linux")]
	pub async fn verify(&self) -> Result<Platform, AnyError> {
		let (is_nixos, gnu_a, gnu_b, or_musl) = tokio::join!(
			check_is_nixos(),
			check_glibc_version(),
			check_glibcxx_version(),
			check_musl_interpreter()
		);

		if (gnu_a.is_ok() && gnu_b.is_ok()) || is_nixos {
			return Ok(if cfg!(target_arch = "x86_64") {
				Platform::LinuxX64
			} else if cfg!(target_arch = "armhf") {
				Platform::LinuxARM32
			} else {
				Platform::LinuxARM64
			});
		}

		if or_musl.is_ok() {
			return Ok(if cfg!(target_arch = "x86_64") {
				Platform::LinuxAlpineX64
			} else {
				Platform::LinuxAlpineARM64
			});
		}

		let mut errors: Vec<String> = vec![];
		if let Err(e) = gnu_a {
			errors.push(e);
		} else if let Err(e) = gnu_b {
			errors.push(e);
		}

		if let Err(e) = or_musl {
			errors.push(e);
		}

		let bullets = errors
			.iter()
			.map(|e| format!("  - {}", e))
			.collect::<Vec<String>>()
			.join("\n");

		Err(AnyError::from(SetupError(format!(
			"This machine not meet VS Code Server's prerequisites, expected either...\n{}",
			bullets,
		))))
	}
}

#[allow(dead_code)]
async fn check_musl_interpreter() -> Result<(), String> {
	const MUSL_PATH: &str = if cfg!(target_platform = "aarch64") {
		"/lib/ld-musl-aarch64.so.1"
	} else {
		"/lib/ld-musl-x86_64.so.1"
	};

	if fs::metadata(MUSL_PATH).await.is_err() {
		return Err(format!(
			"find {}, which is required to run the VS Code Server in musl environments",
			MUSL_PATH
		));
	}

	Ok(())
}

#[allow(dead_code)]
async fn check_glibc_version() -> Result<(), String> {
	let ldd_version = capture_command("ldd", ["--version"])
		.await
		.ok()
		.and_then(|o| extract_ldd_version(&o.stdout));

	if let Some(v) = ldd_version {
		return if v.gte(&MIN_LDD_VERSION) {
			Ok(())
		} else {
			Err(format!(
				"find GLIBC >= 2.17 (but found {} instead) for GNU environments",
				v
			))
		};
	}

	Ok(())
}

/// Check for nixos to avoid mandating glibc versions. See:
/// https://github.com/microsoft/vscode-remote-release/issues/7129
#[allow(dead_code)]
async fn check_is_nixos() -> bool {
	fs::metadata(NIXOS_TEST_PATH).await.is_ok()
}

#[allow(dead_code)]
async fn check_glibcxx_version() -> Result<(), String> {
	let mut libstdc_path: Option<String> = None;

	const DEFAULT_LIB_PATH: &str = "/usr/lib64/libstdc++.so.6";
	const LDCONFIG_PATH: &str = "/sbin/ldconfig";

	if fs::metadata(DEFAULT_LIB_PATH).await.is_ok() {
		libstdc_path = Some(DEFAULT_LIB_PATH.to_owned());
	} else if fs::metadata(LDCONFIG_PATH).await.is_ok() {
		libstdc_path = capture_command(LDCONFIG_PATH, ["-p"])
			.await
			.ok()
			.and_then(|o| extract_libstd_from_ldconfig(&o.stdout));
	}

	match libstdc_path {
		Some(path) => match fs::read(&path).await {
			Ok(contents) => check_for_sufficient_glibcxx_versions(contents),
			Err(e) => Err(format!(
				"validate GLIBCXX version for GNU environments, but could not: {}",
				e
			)),
		},
		None => Err("find libstdc++.so or ldconfig for GNU environments".to_owned()),
	}
}

#[allow(dead_code)]
fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String> {
	let all_versions: Vec<SimpleSemver> = LIBSTD_CXX_VERSION_RE
		.captures_iter(&contents)
		.map(|m| SimpleSemver {
			major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
			minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())),
			patch: m.get(3).map_or(0, |s| u32_from_bytes(s.as_bytes())),
		})
		.collect();

	if !all_versions.iter().any(|v| MIN_CXX_VERSION.gte(v)) {
		return Err(format!(
			"find GLIBCXX >= 3.4.18 (but found {} instead) for GNU environments",
			all_versions
				.iter()
				.map(String::from)
				.collect::<Vec<String>>()
				.join(", ")
		));
	}

	Ok(())
}

fn extract_ldd_version(output: &[u8]) -> Option<SimpleSemver> {
	LDD_VERSION_RE.captures(output).map(|m| SimpleSemver {
		major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
		minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())),
		patch: 0,
	})
}

fn extract_libstd_from_ldconfig(output: &[u8]) -> Option<String> {
	String::from_utf8_lossy(output)
		.lines()
		.find_map(|l| LDCONFIG_STDC_RE.captures(l))
		.and_then(|cap| cap.get(1))
		.map(|cap| cap.as_str().to_owned())
}

fn u32_from_bytes(b: &[u8]) -> u32 {
	String::from_utf8_lossy(b).parse::<u32>().unwrap_or(0)
}

#[derive(Debug, PartialEq)]
struct SimpleSemver {
	major: u32,
	minor: u32,
	patch: u32,
}

impl From<&SimpleSemver> for String {
	fn from(s: &SimpleSemver) -> Self {
		format!("v{}.{}.{}", s.major, s.minor, s.patch)
	}
}

impl std::fmt::Display for SimpleSemver {
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		write!(f, "{}", String::from(self))
	}
}

#[allow(dead_code)]
impl SimpleSemver {
	fn new(major: u32, minor: u32, patch: u32) -> SimpleSemver {
		SimpleSemver {
			major,
			minor,
			patch,
		}
	}

	fn gte(&self, other: &SimpleSemver) -> bool {
		match self.major.cmp(&other.major) {
			Ordering::Greater => true,
			Ordering::Less => false,
			Ordering::Equal => match self.minor.cmp(&other.minor) {
				Ordering::Greater => true,
				Ordering::Less => false,
				Ordering::Equal => self.patch >= other.patch,
			},
		}
	}
}

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

	#[test]
	fn test_extract_libstd_from_ldconfig() {
		let actual = "
            libstoken.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstoken.so.1
            libstemmer.so.0d (libc6,x86-64) => /lib/x86_64-linux-gnu/libstemmer.so.0d
            libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6
            libstartup-notification-1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstartup-notification-1.so.0
            libssl3.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl3.so
        ".to_owned().into_bytes();

		assert_eq!(
			extract_libstd_from_ldconfig(&actual),
			Some("/lib/x86_64-linux-gnu/libstdc++.so.6".to_owned()),
		);

		assert_eq!(
			extract_libstd_from_ldconfig(&"nothing here!".to_owned().into_bytes()),
			None,
		);
	}

	#[test]
	fn test_gte() {
		assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 3)));
		assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(0, 10, 10)));
		assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 1, 10)));

		assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 10)));
		assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 3, 1)));
		assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(2, 2, 1)));
	}

	#[test]
	fn check_for_sufficient_glibcxx_versions() {
		let actual = "ldd (Ubuntu GLIBC 2.31-0ubuntu9.7) 2.31
        Copyright (C) 2020 Free Software Foundation, Inc.
        This is free software; see the source for copying conditions.  There is NO
        warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
        Written by Roland McGrath and Ulrich Drepper."
			.to_owned()
			.into_bytes();

		assert_eq!(
			extract_ldd_version(&actual),
			Some(SimpleSemver::new(2, 31, 0)),
		);
	}
}
<commit_msg>cli: check glibc version more correctly on gnu (#166622)<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
use std::cmp::Ordering;

use super::command::capture_command;
use crate::update_service::Platform;
use crate::util::errors::SetupError;
use lazy_static::lazy_static;
use regex::bytes::Regex as BinRegex;
use regex::Regex;
use tokio::fs;

use super::errors::AnyError;

lazy_static! {
	static ref LDCONFIG_STDC_RE: Regex = Regex::new(r"libstdc\+\+.* => (.+)").unwrap();
	static ref LDD_VERSION_RE: BinRegex = BinRegex::new(r"^ldd.*(.+)\.(.+)\s").unwrap();
	static ref GENERIC_VERSION_RE: Regex = Regex::new(r"^([0-9]+)\.([0-9]+)$").unwrap();
	static ref LIBSTD_CXX_VERSION_RE: BinRegex =
		BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap();
	static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 18);
	static ref MIN_LDD_VERSION: SimpleSemver = SimpleSemver::new(2, 17, 0);
}

const NIXOS_TEST_PATH: &str = "/etc/NIXOS";

pub struct PreReqChecker {}

impl Default for PreReqChecker {
	fn default() -> Self {
		Self::new()
	}
}

impl PreReqChecker {
	pub fn new() -> PreReqChecker {
		PreReqChecker {}
	}

	#[cfg(not(target_os = "linux"))]
	pub async fn verify(&self) -> Result<Platform, AnyError> {
		Platform::env_default().ok_or_else(|| {
			SetupError("VS Code is not supported on this platform".to_owned()).into()
		})
	}

	#[cfg(target_os = "linux")]
	pub async fn verify(&self) -> Result<Platform, AnyError> {
		let (is_nixos, gnu_a, gnu_b, or_musl) = tokio::join!(
			check_is_nixos(),
			check_glibc_version(),
			check_glibcxx_version(),
			check_musl_interpreter()
		);

		if (gnu_a.is_ok() && gnu_b.is_ok()) || is_nixos {
			return Ok(if cfg!(target_arch = "x86_64") {
				Platform::LinuxX64
			} else if cfg!(target_arch = "armhf") {
				Platform::LinuxARM32
			} else {
				Platform::LinuxARM64
			});
		}

		if or_musl.is_ok() {
			return Ok(if cfg!(target_arch = "x86_64") {
				Platform::LinuxAlpineX64
			} else {
				Platform::LinuxAlpineARM64
			});
		}

		let mut errors: Vec<String> = vec![];
		if let Err(e) = gnu_a {
			errors.push(e);
		} else if let Err(e) = gnu_b {
			errors.push(e);
		}

		if let Err(e) = or_musl {
			errors.push(e);
		}

		let bullets = errors
			.iter()
			.map(|e| format!("  - {}", e))
			.collect::<Vec<String>>()
			.join("\n");

		Err(AnyError::from(SetupError(format!(
			"This machine not meet VS Code Server's prerequisites, expected either...\n{}",
			bullets,
		))))
	}
}

#[allow(dead_code)]
async fn check_musl_interpreter() -> Result<(), String> {
	const MUSL_PATH: &str = if cfg!(target_platform = "aarch64") {
		"/lib/ld-musl-aarch64.so.1"
	} else {
		"/lib/ld-musl-x86_64.so.1"
	};

	if fs::metadata(MUSL_PATH).await.is_err() {
		return Err(format!(
			"find {}, which is required to run the VS Code Server in musl environments",
			MUSL_PATH
		));
	}

	Ok(())
}

#[allow(dead_code)]
async fn check_glibc_version() -> Result<(), String> {
	#[cfg(target_env = "gnu")]
	let version = {
		let v = unsafe { libc::gnu_get_libc_version() };
		let v = unsafe { std::ffi::CStr::from_ptr(v) };
		let v = v.to_str().unwrap();
		extract_generic_version(v)
	};
	#[cfg(not(target_env = "gnu"))]
	let version = {
		capture_command("ldd", ["--version"])
			.await
			.ok()
			.and_then(|o| extract_ldd_version(&o.stdout))
	};

	if let Some(v) = version {
		return if v >= *MIN_LDD_VERSION {
			Ok(())
		} else {
			Err(format!(
				"find GLIBC >= 2.17 (but found {} instead) for GNU environments",
				v
			))
		};
	}

	Ok(())
}

/// Check for nixos to avoid mandating glibc versions. See:
/// https://github.com/microsoft/vscode-remote-release/issues/7129
#[allow(dead_code)]
async fn check_is_nixos() -> bool {
	fs::metadata(NIXOS_TEST_PATH).await.is_ok()
}

#[allow(dead_code)]
async fn check_glibcxx_version() -> Result<(), String> {
	let mut libstdc_path: Option<String> = None;

	const DEFAULT_LIB_PATH: &str = "/usr/lib64/libstdc++.so.6";
	const LDCONFIG_PATH: &str = "/sbin/ldconfig";

	if fs::metadata(DEFAULT_LIB_PATH).await.is_ok() {
		libstdc_path = Some(DEFAULT_LIB_PATH.to_owned());
	} else if fs::metadata(LDCONFIG_PATH).await.is_ok() {
		libstdc_path = capture_command(LDCONFIG_PATH, ["-p"])
			.await
			.ok()
			.and_then(|o| extract_libstd_from_ldconfig(&o.stdout));
	}

	match libstdc_path {
		Some(path) => match fs::read(&path).await {
			Ok(contents) => check_for_sufficient_glibcxx_versions(contents),
			Err(e) => Err(format!(
				"validate GLIBCXX version for GNU environments, but could not: {}",
				e
			)),
		},
		None => Err("find libstdc++.so or ldconfig for GNU environments".to_owned()),
	}
}

#[allow(dead_code)]
fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String> {
	let all_versions: Vec<SimpleSemver> = LIBSTD_CXX_VERSION_RE
		.captures_iter(&contents)
		.map(|m| SimpleSemver {
			major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
			minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())),
			patch: m.get(3).map_or(0, |s| u32_from_bytes(s.as_bytes())),
		})
		.collect();

	if !all_versions.iter().any(|v| &*MIN_CXX_VERSION >= v) {
		return Err(format!(
			"find GLIBCXX >= 3.4.18 (but found {} instead) for GNU environments",
			all_versions
				.iter()
				.map(String::from)
				.collect::<Vec<String>>()
				.join(", ")
		));
	}

	Ok(())
}

#[allow(dead_code)]
fn extract_ldd_version(output: &[u8]) -> Option<SimpleSemver> {
	LDD_VERSION_RE.captures(output).map(|m| SimpleSemver {
		major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
		minor: m.get(2).map_or(0, |s| u32_from_bytes(s.as_bytes())),
		patch: 0,
	})
}

#[allow(dead_code)]
fn extract_generic_version(output: &str) -> Option<SimpleSemver> {
	GENERIC_VERSION_RE.captures(output).map(|m| SimpleSemver {
		major: m.get(1).map_or(0, |s| s.as_str().parse().unwrap()),
		minor: m.get(2).map_or(0, |s| s.as_str().parse().unwrap()),
		patch: 0,
	})
}

fn extract_libstd_from_ldconfig(output: &[u8]) -> Option<String> {
	String::from_utf8_lossy(output)
		.lines()
		.find_map(|l| LDCONFIG_STDC_RE.captures(l))
		.and_then(|cap| cap.get(1))
		.map(|cap| cap.as_str().to_owned())
}

fn u32_from_bytes(b: &[u8]) -> u32 {
	String::from_utf8_lossy(b).parse::<u32>().unwrap_or(0)
}

#[derive(Debug, Default, PartialEq, Eq)]
struct SimpleSemver {
	major: u32,
	minor: u32,
	patch: u32,
}

impl PartialOrd for SimpleSemver {
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		Some(self.cmp(other))
	}
}

impl Ord for SimpleSemver {
	fn cmp(&self, other: &Self) -> Ordering {
		let major = self.major.cmp(&other.major);
		if major != Ordering::Equal {
			return major;
		}

		let minor = self.minor.cmp(&other.minor);
		if minor != Ordering::Equal {
			return minor;
		}

		self.patch.cmp(&other.patch)
	}
}

impl From<&SimpleSemver> for String {
	fn from(s: &SimpleSemver) -> Self {
		format!("v{}.{}.{}", s.major, s.minor, s.patch)
	}
}

impl std::fmt::Display for SimpleSemver {
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		write!(f, "{}", String::from(self))
	}
}

#[allow(dead_code)]
impl SimpleSemver {
	fn new(major: u32, minor: u32, patch: u32) -> SimpleSemver {
		SimpleSemver {
			major,
			minor,
			patch,
		}
	}
}

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

	#[test]
	fn test_extract_libstd_from_ldconfig() {
		let actual = "
            libstoken.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstoken.so.1
            libstemmer.so.0d (libc6,x86-64) => /lib/x86_64-linux-gnu/libstemmer.so.0d
            libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6
            libstartup-notification-1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstartup-notification-1.so.0
            libssl3.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl3.so
        ".to_owned().into_bytes();

		assert_eq!(
			extract_libstd_from_ldconfig(&actual),
			Some("/lib/x86_64-linux-gnu/libstdc++.so.6".to_owned()),
		);

		assert_eq!(
			extract_libstd_from_ldconfig(&"nothing here!".to_owned().into_bytes()),
			None,
		);
	}

	#[test]
	fn test_gte() {
		assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(1, 2, 3));
		assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(0, 10, 10));
		assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(1, 1, 10));

		assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(1, 2, 10));
		assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(1, 3, 1));
		assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(2, 2, 1));
	}

	#[test]
	fn check_for_sufficient_glibcxx_versions() {
		let actual = "ldd (Ubuntu GLIBC 2.31-0ubuntu9.7) 2.31
        Copyright (C) 2020 Free Software Foundation, Inc.
        This is free software; see the source for copying conditions.  There is NO
        warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
        Written by Roland McGrath and Ulrich Drepper."
			.to_owned()
			.into_bytes();

		assert_eq!(
			extract_ldd_version(&actual),
			Some(SimpleSemver::new(2, 31, 0)),
		);
	}
}
<|endoftext|>


<commit_before>use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

#[allow(clippy::module_name_repetitions)]
#[derive(Copy, Clone)]
pub struct UselessVec {
    pub too_large_for_stack: u64,
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for usage of `&vec![..]` when using `&[..]` would
    /// be possible.
    ///
    /// ### Why is this bad?
    /// This is less efficient.
    ///
    /// ### Example
    /// ```rust
    /// # fn foo(my_vec: &[u8]) {}
    ///
    /// // Bad
    /// foo(&vec![1, 2]);
    ///
    /// // Good
    /// foo(&[1, 2]);
    /// ```
    pub USELESS_VEC,
    perf,
    "useless `vec!`"
}

impl_lint_pass!(UselessVec => [USELESS_VEC]);

impl<'tcx> LateLintPass<'tcx> for UselessVec {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
        if_chain! {
            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
            if let ty::Slice(..) = ty.kind();
            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
            if let Some(vec_args) = higher::VecArgs::hir(cx, addressee);
            then {
                self.check_vec_macro(cx, &vec_args, mutability, expr.span);
            }
        }

        // search for `for _ in vec![…]`
        if_chain! {
            if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr);
            if let Some(vec_args) = higher::VecArgs::hir(cx, arg);
            if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
            then {
                // report the error around the `vec!` not inside `<std macros>:`
                let span = arg.span
                    .ctxt()
                    .outer_expn_data()
                    .call_site
                    .ctxt()
                    .outer_expn_data()
                    .call_site;
                self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
            }
        }
    }
}

impl UselessVec {
    fn check_vec_macro<'tcx>(
        self,
        cx: &LateContext<'tcx>,
        vec_args: &higher::VecArgs<'tcx>,
        mutability: Mutability,
        span: Span,
    ) {
        let mut applicability = Applicability::MachineApplicable;
        let snippet = match *vec_args {
            higher::VecArgs::Repeat(elem, len) => {
                if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
                    #[allow(clippy::cast_possible_truncation)]
                    if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
                        return;
                    }

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!(
                                "&[{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                    }
                } else {
                    return;
                }
            },
            higher::VecArgs::Vec(args) => {
                if let Some(last) = args.iter().last() {
                    #[allow(clippy::cast_possible_truncation)]
                    if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
                        return;
                    }
                    let span = args[0].span.to(last.span);

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}]",
                                snippet_with_applicability(cx, span, "..", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
                        },
                    }
                } else {
                    match mutability {
                        Mutability::Mut => "&mut []".into(),
                        Mutability::Not => "&[]".into(),
                    }
                }
            },
        };

        span_lint_and_sugg(
            cx,
            USELESS_VEC,
            span,
            "useless use of `vec!`",
            "you can use a slice directly",
            snippet,
            applicability,
        );
    }
}

fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
    let ty = cx.typeck_results().expr_ty_adjusted(expr);
    cx.layout_of(ty).map_or(0, |l| l.size.bytes())
}

/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
fn vec_type(ty: Ty<'_>) -> Ty<'_> {
    if let ty::Adt(_, substs) = ty.kind() {
        substs.type_at(0)
    } else {
        panic!("The type of `vec!` is a not a struct?");
    }
}
<commit_msg>Fix clippy with for loop span change<commit_after>use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

#[allow(clippy::module_name_repetitions)]
#[derive(Copy, Clone)]
pub struct UselessVec {
    pub too_large_for_stack: u64,
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for usage of `&vec![..]` when using `&[..]` would
    /// be possible.
    ///
    /// ### Why is this bad?
    /// This is less efficient.
    ///
    /// ### Example
    /// ```rust
    /// # fn foo(my_vec: &[u8]) {}
    ///
    /// // Bad
    /// foo(&vec![1, 2]);
    ///
    /// // Good
    /// foo(&[1, 2]);
    /// ```
    pub USELESS_VEC,
    perf,
    "useless `vec!`"
}

impl_lint_pass!(UselessVec => [USELESS_VEC]);

impl<'tcx> LateLintPass<'tcx> for UselessVec {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
        if_chain! {
            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
            if let ty::Slice(..) = ty.kind();
            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
            if let Some(vec_args) = higher::VecArgs::hir(cx, addressee);
            then {
                self.check_vec_macro(cx, &vec_args, mutability, expr.span);
            }
        }

        // search for `for _ in vec![…]`
        if_chain! {
            if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr);
            if let Some(vec_args) = higher::VecArgs::hir(cx, arg);
            if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
            then {
                // report the error around the `vec!` not inside `<std macros>:`
                let span = arg.span.ctxt().outer_expn_data().call_site;
                self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
            }
        }
    }
}

impl UselessVec {
    fn check_vec_macro<'tcx>(
        self,
        cx: &LateContext<'tcx>,
        vec_args: &higher::VecArgs<'tcx>,
        mutability: Mutability,
        span: Span,
    ) {
        let mut applicability = Applicability::MachineApplicable;
        let snippet = match *vec_args {
            higher::VecArgs::Repeat(elem, len) => {
                if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
                    #[allow(clippy::cast_possible_truncation)]
                    if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
                        return;
                    }

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!(
                                "&[{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                    }
                } else {
                    return;
                }
            },
            higher::VecArgs::Vec(args) => {
                if let Some(last) = args.iter().last() {
                    #[allow(clippy::cast_possible_truncation)]
                    if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
                        return;
                    }
                    let span = args[0].span.to(last.span);

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}]",
                                snippet_with_applicability(cx, span, "..", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
                        },
                    }
                } else {
                    match mutability {
                        Mutability::Mut => "&mut []".into(),
                        Mutability::Not => "&[]".into(),
                    }
                }
            },
        };

        span_lint_and_sugg(
            cx,
            USELESS_VEC,
            span,
            "useless use of `vec!`",
            "you can use a slice directly",
            snippet,
            applicability,
        );
    }
}

fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
    let ty = cx.typeck_results().expr_ty_adjusted(expr);
    cx.layout_of(ty).map_or(0, |l| l.size.bytes())
}

/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
fn vec_type(ty: Ty<'_>) -> Ty<'_> {
    if let ty::Adt(_, substs) = ty.kind() {
        substs.type_at(0)
    } else {
        panic!("The type of `vec!` is a not a struct?");
    }
}
<|endoftext|>


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

use std::io;
use std::mem;
use std::ptr;
use std::slice;

use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;

use util::io_err;

extern crate libc;
extern crate winapi;
use self::winapi::*;

#[link(name = "setupapi")]
extern "stdcall" {
    fn SetupDiGetClassDevsW(
        ClassGuid: *const GUID,
        Enumerator: PCSTR,
        hwndParent: HWND,
        flags: DWORD,
    ) -> HDEVINFO;

    fn SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO) -> BOOL;

    fn SetupDiEnumDeviceInterfaces(
        DeviceInfoSet: HDEVINFO,
        DeviceInfoData: PSP_DEVINFO_DATA,
        InterfaceClassGuid: *const GUID,
        MemberIndex: DWORD,
        DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA,
    ) -> BOOL;

    fn SetupDiGetDeviceInterfaceDetailW(
        DeviceInfoSet: HDEVINFO,
        DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA,
        DeviceInterfaceDetailData: PSP_DEVICE_INTERFACE_DETAIL_DATA_W,
        DeviceInterfaceDetailDataSize: DWORD,
        RequiredSize: PDWORD,
        DeviceInfoData: PSP_DEVINFO_DATA,
    ) -> BOOL;
}

#[link(name = "hid")]
extern "stdcall" {
    fn HidD_GetPreparsedData(
        HidDeviceObject: HANDLE,
        PreparsedData: *mut PHIDP_PREPARSED_DATA,
    ) -> BOOLEAN;

    fn HidD_FreePreparsedData(PreparsedData: PHIDP_PREPARSED_DATA) -> BOOLEAN;

    fn HidP_GetCaps(PreparsedData: PHIDP_PREPARSED_DATA, Capabilities: PHIDP_CAPS) -> NTSTATUS;
}

macro_rules! offset_of {
    ($ty:ty, $field:ident) => {
        unsafe { &(*(0 as *const $ty)).$field as *const _ as usize }
    }
}

fn from_wide_ptr(ptr: *const u16, len: usize) -> String {
    assert!(!ptr.is_null() && len % 2 == 0);
    let slice = unsafe { slice::from_raw_parts(ptr, len / 2) };
    OsString::from_wide(slice).to_string_lossy().into_owned()
}

pub struct DeviceInfoSet {
    set: HDEVINFO,
}

impl DeviceInfoSet {
    pub fn new() -> io::Result<Self> {
        let flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
        let set = unsafe {
            SetupDiGetClassDevsW(
                &GUID_DEVINTERFACE_HID,
                ptr::null_mut(),
                ptr::null_mut(),
                flags,
            )
        };
        if set == INVALID_HANDLE_VALUE {
            return Err(io_err("SetupDiGetClassDevsW failed!"));
        }

        Ok(Self { set })
    }

    pub fn get(&self) -> HDEVINFO {
        self.set
    }

    pub fn devices(&self) -> DeviceInfoSetIter {
        DeviceInfoSetIter::new(self)
    }
}

impl Drop for DeviceInfoSet {
    fn drop(&mut self) {
        let _ = unsafe { SetupDiDestroyDeviceInfoList(self.set) };
    }
}

pub struct DeviceInfoSetIter<'a> {
    set: &'a DeviceInfoSet,
    index: DWORD,
}

impl<'a> DeviceInfoSetIter<'a> {
    fn new(set: &'a DeviceInfoSet) -> Self {
        Self { set, index: 0 }
    }
}

impl<'a> Iterator for DeviceInfoSetIter<'a> {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        let mut device_interface_data = unsafe { mem::uninitialized::<SP_DEVICE_INTERFACE_DATA>() };
        device_interface_data.cbSize = mem::size_of::<SP_DEVICE_INTERFACE_DATA>() as UINT;

        let rv = unsafe {
            SetupDiEnumDeviceInterfaces(
                self.set.get(),
                ptr::null_mut(),
                &GUID_DEVINTERFACE_HID,
                self.index,
                &mut device_interface_data,
            )
        };
        if rv == 0 {
            return None; // We're past the last device index.
        }

        // Determine the size required to hold a detail struct.
        let mut required_size = 0;
        unsafe {
            SetupDiGetDeviceInterfaceDetailW(
                self.set.get(),
                &mut device_interface_data,
                ptr::null_mut(),
                required_size,
                &mut required_size,
                ptr::null_mut(),
            )
        };
        if required_size == 0 {
            return None; // An error occurred.
        }

        let detail = DeviceInterfaceDetailData::new(required_size as usize);
        if detail.is_none() {
            return None; // malloc() failed.
        }

        let detail = detail.unwrap();
        let rv = unsafe {
            SetupDiGetDeviceInterfaceDetailW(
                self.set.get(),
                &mut device_interface_data,
                detail.get(),
                required_size,
                ptr::null_mut(),
                ptr::null_mut(),
            )
        };
        if rv == 0 {
            return None; // An error occurred.
        }

        self.index += 1;
        Some(detail.path())
    }
}

struct DeviceInterfaceDetailData {
    data: PSP_DEVICE_INTERFACE_DETAIL_DATA_W,
    path_len: usize,
}

impl DeviceInterfaceDetailData {
    fn new(size: usize) -> Option<Self> {
        let mut cb_size = mem::size_of::<SP_DEVICE_INTERFACE_DETAIL_DATA_W>();
        if cfg!(target_pointer_width = "32") {
            cb_size = 4 + 2; // 4-byte uint + default TCHAR size. size_of is inaccurate.
        }

        if size < cb_size {
            warn!("DeviceInterfaceDetailData is too small. {}", size);
            return None;
        }

        let mut data = unsafe { libc::malloc(size) as PSP_DEVICE_INTERFACE_DETAIL_DATA_W };
        if data.is_null() {
            return None;
        }

        // Set total size of the structure.
        unsafe { (*data).cbSize = cb_size as UINT };

        // Compute offset of `SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath`.
        let offset = offset_of!(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath);

        Some(Self {
            data,
            path_len: size - offset,
        })
    }

    fn get(&self) -> PSP_DEVICE_INTERFACE_DETAIL_DATA_W {
        self.data
    }

    fn path(&self) -> String {
        unsafe { from_wide_ptr((*self.data).DevicePath.as_ptr(), self.path_len - 2) }
    }
}

impl Drop for DeviceInterfaceDetailData {
    fn drop(&mut self) {
        unsafe { libc::free(self.data as *mut libc::c_void) };
    }
}

pub struct DeviceCapabilities {
    caps: HIDP_CAPS,
}

impl DeviceCapabilities {
    pub fn new(handle: HANDLE) -> io::Result<Self> {
        let mut preparsed_data = ptr::null_mut();
        let rv = unsafe { HidD_GetPreparsedData(handle, &mut preparsed_data) };
        if rv == 0 || preparsed_data.is_null() {
            return Err(io_err("HidD_GetPreparsedData failed!"));
        }

        let mut caps: HIDP_CAPS = unsafe { mem::uninitialized() };

        unsafe {
            let rv = HidP_GetCaps(preparsed_data, &mut caps);
            HidD_FreePreparsedData(preparsed_data);

            if rv != HIDP_STATUS_SUCCESS {
                return Err(io_err("HidP_GetCaps failed!"));
            }
        }

        Ok(Self { caps })
    }

    pub fn usage(&self) -> USAGE {
        self.caps.Usage
    }

    pub fn usage_page(&self) -> USAGE {
        self.caps.UsagePage
    }
}
<commit_msg>Remove unnescary `mut`<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io;
use std::mem;
use std::ptr;
use std::slice;

use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;

use util::io_err;

extern crate libc;
extern crate winapi;
use self::winapi::*;

#[link(name = "setupapi")]
extern "stdcall" {
    fn SetupDiGetClassDevsW(
        ClassGuid: *const GUID,
        Enumerator: PCSTR,
        hwndParent: HWND,
        flags: DWORD,
    ) -> HDEVINFO;

    fn SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO) -> BOOL;

    fn SetupDiEnumDeviceInterfaces(
        DeviceInfoSet: HDEVINFO,
        DeviceInfoData: PSP_DEVINFO_DATA,
        InterfaceClassGuid: *const GUID,
        MemberIndex: DWORD,
        DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA,
    ) -> BOOL;

    fn SetupDiGetDeviceInterfaceDetailW(
        DeviceInfoSet: HDEVINFO,
        DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA,
        DeviceInterfaceDetailData: PSP_DEVICE_INTERFACE_DETAIL_DATA_W,
        DeviceInterfaceDetailDataSize: DWORD,
        RequiredSize: PDWORD,
        DeviceInfoData: PSP_DEVINFO_DATA,
    ) -> BOOL;
}

#[link(name = "hid")]
extern "stdcall" {
    fn HidD_GetPreparsedData(
        HidDeviceObject: HANDLE,
        PreparsedData: *mut PHIDP_PREPARSED_DATA,
    ) -> BOOLEAN;

    fn HidD_FreePreparsedData(PreparsedData: PHIDP_PREPARSED_DATA) -> BOOLEAN;

    fn HidP_GetCaps(PreparsedData: PHIDP_PREPARSED_DATA, Capabilities: PHIDP_CAPS) -> NTSTATUS;
}

macro_rules! offset_of {
    ($ty:ty, $field:ident) => {
        unsafe { &(*(0 as *const $ty)).$field as *const _ as usize }
    }
}

fn from_wide_ptr(ptr: *const u16, len: usize) -> String {
    assert!(!ptr.is_null() && len % 2 == 0);
    let slice = unsafe { slice::from_raw_parts(ptr, len / 2) };
    OsString::from_wide(slice).to_string_lossy().into_owned()
}

pub struct DeviceInfoSet {
    set: HDEVINFO,
}

impl DeviceInfoSet {
    pub fn new() -> io::Result<Self> {
        let flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
        let set = unsafe {
            SetupDiGetClassDevsW(
                &GUID_DEVINTERFACE_HID,
                ptr::null_mut(),
                ptr::null_mut(),
                flags,
            )
        };
        if set == INVALID_HANDLE_VALUE {
            return Err(io_err("SetupDiGetClassDevsW failed!"));
        }

        Ok(Self { set })
    }

    pub fn get(&self) -> HDEVINFO {
        self.set
    }

    pub fn devices(&self) -> DeviceInfoSetIter {
        DeviceInfoSetIter::new(self)
    }
}

impl Drop for DeviceInfoSet {
    fn drop(&mut self) {
        let _ = unsafe { SetupDiDestroyDeviceInfoList(self.set) };
    }
}

pub struct DeviceInfoSetIter<'a> {
    set: &'a DeviceInfoSet,
    index: DWORD,
}

impl<'a> DeviceInfoSetIter<'a> {
    fn new(set: &'a DeviceInfoSet) -> Self {
        Self { set, index: 0 }
    }
}

impl<'a> Iterator for DeviceInfoSetIter<'a> {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        let mut device_interface_data = unsafe { mem::uninitialized::<SP_DEVICE_INTERFACE_DATA>() };
        device_interface_data.cbSize = mem::size_of::<SP_DEVICE_INTERFACE_DATA>() as UINT;

        let rv = unsafe {
            SetupDiEnumDeviceInterfaces(
                self.set.get(),
                ptr::null_mut(),
                &GUID_DEVINTERFACE_HID,
                self.index,
                &mut device_interface_data,
            )
        };
        if rv == 0 {
            return None; // We're past the last device index.
        }

        // Determine the size required to hold a detail struct.
        let mut required_size = 0;
        unsafe {
            SetupDiGetDeviceInterfaceDetailW(
                self.set.get(),
                &mut device_interface_data,
                ptr::null_mut(),
                required_size,
                &mut required_size,
                ptr::null_mut(),
            )
        };
        if required_size == 0 {
            return None; // An error occurred.
        }

        let detail = DeviceInterfaceDetailData::new(required_size as usize);
        if detail.is_none() {
            return None; // malloc() failed.
        }

        let detail = detail.unwrap();
        let rv = unsafe {
            SetupDiGetDeviceInterfaceDetailW(
                self.set.get(),
                &mut device_interface_data,
                detail.get(),
                required_size,
                ptr::null_mut(),
                ptr::null_mut(),
            )
        };
        if rv == 0 {
            return None; // An error occurred.
        }

        self.index += 1;
        Some(detail.path())
    }
}

struct DeviceInterfaceDetailData {
    data: PSP_DEVICE_INTERFACE_DETAIL_DATA_W,
    path_len: usize,
}

impl DeviceInterfaceDetailData {
    fn new(size: usize) -> Option<Self> {
        let mut cb_size = mem::size_of::<SP_DEVICE_INTERFACE_DETAIL_DATA_W>();
        if cfg!(target_pointer_width = "32") {
            cb_size = 4 + 2; // 4-byte uint + default TCHAR size. size_of is inaccurate.
        }

        if size < cb_size {
            warn!("DeviceInterfaceDetailData is too small. {}", size);
            return None;
        }

        let data = unsafe { libc::malloc(size) as PSP_DEVICE_INTERFACE_DETAIL_DATA_W };
        if data.is_null() {
            return None;
        }

        // Set total size of the structure.
        unsafe { (*data).cbSize = cb_size as UINT };

        // Compute offset of `SP_DEVICE_INTERFACE_DETAIL_DATA_W.DevicePath`.
        let offset = offset_of!(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath);

        Some(Self {
            data,
            path_len: size - offset,
        })
    }

    fn get(&self) -> PSP_DEVICE_INTERFACE_DETAIL_DATA_W {
        self.data
    }

    fn path(&self) -> String {
        unsafe { from_wide_ptr((*self.data).DevicePath.as_ptr(), self.path_len - 2) }
    }
}

impl Drop for DeviceInterfaceDetailData {
    fn drop(&mut self) {
        unsafe { libc::free(self.data as *mut libc::c_void) };
    }
}

pub struct DeviceCapabilities {
    caps: HIDP_CAPS,
}

impl DeviceCapabilities {
    pub fn new(handle: HANDLE) -> io::Result<Self> {
        let mut preparsed_data = ptr::null_mut();
        let rv = unsafe { HidD_GetPreparsedData(handle, &mut preparsed_data) };
        if rv == 0 || preparsed_data.is_null() {
            return Err(io_err("HidD_GetPreparsedData failed!"));
        }

        let mut caps: HIDP_CAPS = unsafe { mem::uninitialized() };

        unsafe {
            let rv = HidP_GetCaps(preparsed_data, &mut caps);
            HidD_FreePreparsedData(preparsed_data);

            if rv != HIDP_STATUS_SUCCESS {
                return Err(io_err("HidP_GetCaps failed!"));
            }
        }

        Ok(Self { caps })
    }

    pub fn usage(&self) -> USAGE {
        self.caps.Usage
    }

    pub fn usage_page(&self) -> USAGE {
        self.caps.UsagePage
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::{generated::css_classes::C, Msg};
use chrono::{offset::Local, Datelike};
use iml_wire_types::{Branding, Conf};
use seed::{prelude::*, *};

pub fn view(conf: &Conf) -> impl View<Msg> {
    let year = Local::now().year();

    let footer_string = match conf.branding {
        Branding::Whamcloud => format!(
            "Integrated Manager for Lustre software {} is Copyright © ",
            conf.version
        ),
        _ => {
            if let Some(version) = &conf.exa_version {
                format!("DDN EXAScaler v{} ", version)
            } else {
                "DDN EXAScaler ".to_string()
            }
        }
    };

    let footer_text =  match conf.branding {
        Branding::Whamcloud => div![
            footer_string,
            year.to_string(),
            " DDN. All rights reserved.".to_string(),
        ],
        _ => div![footer_string]
    };

    footer![
        class![C.h_5, C.flex, C.justify_center],
        div![
            class![C.px_5, C.text_sm, C.items_center,],
            footer_text
        ]
    ]
}
<commit_msg>- Add copyright to footer for exascaler. (#2021)<commit_after>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::{generated::css_classes::C, Msg};
use chrono::{offset::Local, Datelike};
use iml_wire_types::{Branding, Conf};
use seed::{prelude::*, *};

pub fn view(conf: &Conf) -> impl View<Msg> {
    let year = Local::now().year();

    let footer_string = match conf.branding {
        Branding::Whamcloud => format!(
            "Integrated Manager for Lustre software {} is Copyright © ",
            conf.version
        ),
        _ => {
            if let Some(version) = &conf.exa_version {
                format!("© 2020 - DDN EXAScaler v{} ", version)
            } else {
                "© 2020 - DDN EXAScaler ".to_string()
            }
        }
    };

    let footer_text =  match conf.branding {
        Branding::Whamcloud => div![
            footer_string,
            year.to_string(),
            " DDN. All rights reserved.".to_string(),
        ],
        _ => div![footer_string]
    };

    footer![
        class![C.h_5, C.flex, C.justify_center],
        div![
            class![C.px_5, C.text_sm, C.items_center,],
            footer_text
        ]
    ]
}
<|endoftext|>