<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! `manticore-tool` is a simple command-line tool for manipulating Manticore
//! data types.

#![deny(missing_docs)]
#![deny(warnings)]
#![deny(unused)]
#![deny(unsafe_code)]

use manticore::crypto::ring;
use manticore::crypto::rsa::Builder as _;
use manticore::crypto::rsa::Keypair as _;
use manticore::crypto::rsa::SignerBuilder as _;
use manticore::io::write::StdWrite;
use manticore::manifest;
use manticore::manifest::container::Container;
use manticore::manifest::container::Containerizer;
use manticore::manifest::container::Metadata;
use manticore::manifest::fpm::Fpm;
use manticore::manifest::provenance;
use manticore::manifest::ManifestType;
use manticore::mem::BumpArena;
use manticore::protocol::firmware_version;
use manticore::protocol::wire::FromWire;
use manticore::protocol::wire::ToWire;
use manticore::protocol::CommandType;
use manticore::protocol::Header;

use serde::de::Deserialize;

use structopt::StructOpt;

use std::fs;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::Read;
use std::io::Write;
use std::path::PathBuf;

/// Opens the given input and output files.
///
/// If either file is missing, it is replaced with stdin or stdout, respectively.
fn open_files(
    input_file: Option<PathBuf>,
    output_file: Option<PathBuf>,
) -> (Box<dyn Read>, Box<dyn Write>) {
    let input: Box<dyn Read> = match input_file {
        Some(path) => {
            let file = File::open(path).expect("failed to open input file");
            Box::new(BufReader::new(file))
        }
        None => Box::new(io::stdin()),
    };

    let output: Box<dyn Write> = match output_file {
        Some(path) => {
            let file = File::create(path).expect("failed to open output file");
            Box::new(file)
        }
        None => Box::new(io::stdout()),
    };

    (input, output)
}

/// Deserializes a message in JSON format from `reader` and then serializes the
/// message in wire format to `writer`.
fn from_json_to_wire<'de, T, R, W>(reader: R, writer: W)
where
    T: ToWire + Deserialize<'de>,
    R: Read,
    W: manticore::io::Write,
{
    let mut de = serde_json::Deserializer::from_reader(reader);
    let msg = T::deserialize(&mut de).expect("failed to deserialize JSON");
    msg.to_wire(writer).expect("failed to write request");
}

/// Converts a JSON object into a Manticore command.
///
/// This function deserializes a message in JSON format from `input_file` and
/// then serializes a header + message in wire format to.`output_file`.
///
/// Uses `cmd_type` and `is_request` to determine the message type since the
/// JSON format does not include the message header.
fn from_json(
    cmd_type: CommandType,
    is_request: bool,
    input: impl Read,
    mut output: impl Write,
) {
    let mut stdwrite = StdWrite(&mut output);

    Header {
        is_request: is_request,
        command: cmd_type,
    }
    .to_wire(&mut stdwrite)
    .expect("failed to write header");

    match (is_request, cmd_type) {
        (true, CommandType::FirmwareVersion) => {
            from_json_to_wire::<firmware_version::FirmwareVersionRequest, _, _>(
                input, stdwrite,
            )
        }
        (false, CommandType::FirmwareVersion) => {
            from_json_to_wire::<firmware_version::FirmwareVersionResponse, _, _>(
                input, stdwrite,
            )
        }
        _ => panic!("Unsupported message type"),
    }
}

/// Macro to deserialize wire format from an input file and then run an
/// operation on the deserialized message.
///
/// This macro is a temporary workaround some Serde limiatations.
///
/// Arguments:
/// * `input_file`: Identifier to get the input file name from.
/// * `body`: A "generic" closure to run with the results of the parse.
macro_rules! read_wire_and_operate {
    ($input:ident, $body:expr) => {
        let mut input = $input;
        let mut read_buf = Vec::new();
        input
            .read_to_end(&mut read_buf)
            .expect("couldn't read from file");

        let mut arena = vec![0u8; 1024];
        let arena = BumpArena::new(&mut arena);

        let mut read_buf_slice = read_buf.as_slice();
        let header = Header::from_wire(&mut read_buf_slice, &arena)
            .expect("failed to read header");
        match (header.is_request, header.command) {
            (true, CommandType::FirmwareVersion) => {
                let message =
                    firmware_version::FirmwareVersionRequest::from_wire(
                        &mut read_buf_slice,
                        &arena,
                    )
                    .expect("failed to read response");
                let body = $body;
                body(message)
            }
            (false, CommandType::FirmwareVersion) => {
                let message =
                    firmware_version::FirmwareVersionResponse::from_wire(
                        &mut read_buf_slice,
                        &arena,
                    )
                    .expect("failed to read response");
                let body = $body;
                body(message)
            }
            _ => panic!("unsupported response type {:?}", header.command),
        }
    };
}

/// Converts a Manticore command into a JSON object.
///
/// This funciton deserializes a header + message in wire format from `input`
/// and then serialize the message as JSON to `output`.
fn to_json(pretty: bool, input: impl Read, output: impl Write) {
    read_wire_and_operate!(input, |msg| {
        if pretty {
            serde_json::to_writer_pretty(output, &msg)
        } else {
            serde_json::to_writer(output, &msg)
        }
        .expect("failed to serialize to JSON")
    });
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "manticore-tool",
    author = "lowRISC contributors",
    about = "Command-line tool for working with Manticore data"
)]
enum CliCommand {
    FromJson {
        /// The command type for the message.
        #[structopt(short = "t", long)]
        cmd_type: CommandType,

        /// Whether this message is a request.
        #[structopt(short = "r", long)]
        is_request: bool,

        /// JSON file containing the message; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// Binary output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
    ToJson {
        /// Whether to pretty-print the resulting JSON.
        #[structopt(short = "p", long)]
        pretty: bool,

        /// Binary file containing the message; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// JSON output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
    SignManifest {
        /// PKCS#8-encoded RSA signing key to sign with.
        #[structopt(short = "k", long, parse(from_os_str))]
        key: PathBuf,

        /// The manifest type for this operation.
        #[structopt(short = "t", long)]
        manifest_type: ManifestType,

        /// The version to encode into the manifest container.
        #[structopt(short = "v", long)]
        manifest_version: u32,

        /// JSON file containing the manifest to sign; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// Binary output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
    ShowManifest {
        /// PKCS#8-encoded RSA public key to optionally verify the signature
        #[structopt(short = "k", long, parse(from_os_str))]
        key: Option<PathBuf>,

        /// Whether to pretty-print the resulting JSON.
        #[structopt(short = "p", long)]
        pretty: bool,

        /// Binary file containing the manifest to parse; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// JSON output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
}

fn main() {
    match CliCommand::from_args() {
        CliCommand::FromJson {
            cmd_type,
            is_request,
            input,
            output,
        } => {
            let (input, output) = open_files(input, output);
            from_json(cmd_type, is_request, input, output);
        }
        CliCommand::ToJson {
            pretty,
            input,
            output,
        } => {
            let (input, output) = open_files(input, output);
            to_json(pretty, input, output);
        }
        CliCommand::SignManifest {
            key,
            manifest_type,
            manifest_version,
            input,
            output,
        } => {
            let (mut input, mut output) = open_files(input, output);

            let key = fs::read(key).expect("failed to open file");
            let keypair = ring::rsa::Keypair::from_pkcs8(&key)
                .expect("failed to parse key");
            let mut signer = ring::rsa::Builder::new()
                .new_signer(keypair)
                .expect("failed to create signing engine");

            let mut manifest_buf = vec![0; 0x2000];
            let mut container = Containerizer::new(&mut manifest_buf)
                .expect("failed to create containerizer")
                .with_type(manifest_type)
                .expect("failed to set manifest type")
                .with_metadata(&Metadata {
                    version_id: manifest_version,
                })
                .expect("failed to set manifest metadata");

            match manifest_type {
                ManifestType::Fpm => {
                    let mut buf = Vec::new();
                    input.read_to_end(&mut buf).expect("failed to read file");

                    let fpm: Fpm<provenance::Adhoc> =
                        serde_json::from_slice(&buf)
                            .expect("failed to parse JSON");
                    fpm.unparse(&mut container)
                        .expect("failed to serialize manifest");
                }
            }

            let manifest = container
                .sign(&mut signer)
                .expect("failed to sign manifest");
            output
                .write_all(manifest)
                .expect("failed to write manifest");
        }
        CliCommand::ShowManifest {
            key,
            pretty,
            input,
            output,
        } => {
            let (mut input, output) = open_files(input, output);

            let engine = key.map(|key| {
                let key = fs::read(key).expect("failed to open file");
                let keypair = ring::rsa::Keypair::from_pkcs8(&key)
                    .expect("failed to parse key");
                ring::rsa::Builder::new()
                    .new_engine(keypair.public())
                    .expect("failed to create signature verification engine")
            });
            let mut buf = Vec::new();
            input.read_to_end(&mut buf).expect("failed to read file");

            let container = match engine {
                Some(mut engine) => {
                    match Container::parse_and_verify(&buf, &mut engine) {
                        Ok(c) => c,
                        Err(manifest::Error::SignatureFailure) => {
                            panic!("failed to verify signature")
                        }
                        Err(_) => panic!("failed to parse manifest container"),
                    }
                    .downgrade()
                }
                None => Container::parse(&buf)
                    .expect("failed to parse manifest container"),
            };

            match container.manifest_type() {
                ManifestType::Fpm => {
                    let fpm = Fpm::parse(container)
                        .expect("failed to parse manifest");
                    if pretty {
                        serde_json::to_writer_pretty(output, &fpm)
                            .expect("failed to write file");
                    } else {
                        serde_json::to_writer(output, &fpm)
                            .expect("failed to write file");
                    }
                }
            }
        }
    }
}
<commit_msg>[tool] Make sure the entire cli is documented<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! `manticore-tool` is a simple command-line tool for manipulating Manticore
//! data types.

#![deny(missing_docs)]
#![deny(warnings)]
#![deny(unused)]
#![deny(unsafe_code)]

use manticore::crypto::ring;
use manticore::crypto::rsa::Builder as _;
use manticore::crypto::rsa::Keypair as _;
use manticore::crypto::rsa::SignerBuilder as _;
use manticore::io::write::StdWrite;
use manticore::manifest;
use manticore::manifest::container::Container;
use manticore::manifest::container::Containerizer;
use manticore::manifest::container::Metadata;
use manticore::manifest::fpm::Fpm;
use manticore::manifest::provenance;
use manticore::manifest::ManifestType;
use manticore::mem::BumpArena;
use manticore::protocol::firmware_version;
use manticore::protocol::wire::FromWire;
use manticore::protocol::wire::ToWire;
use manticore::protocol::CommandType;
use manticore::protocol::Header;

use serde::de::Deserialize;

use structopt::StructOpt;

use std::fs;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::Read;
use std::io::Write;
use std::path::PathBuf;

/// Opens the given input and output files.
///
/// If either file is missing, it is replaced with stdin or stdout, respectively.
fn open_files(
    input_file: Option<PathBuf>,
    output_file: Option<PathBuf>,
) -> (Box<dyn Read>, Box<dyn Write>) {
    let input: Box<dyn Read> = match input_file {
        Some(path) => {
            let file = File::open(path).expect("failed to open input file");
            Box::new(BufReader::new(file))
        }
        None => Box::new(io::stdin()),
    };

    let output: Box<dyn Write> = match output_file {
        Some(path) => {
            let file = File::create(path).expect("failed to open output file");
            Box::new(file)
        }
        None => Box::new(io::stdout()),
    };

    (input, output)
}

/// Deserializes a message in JSON format from `reader` and then serializes the
/// message in wire format to `writer`.
fn from_json_to_wire<'de, T, R, W>(reader: R, writer: W)
where
    T: ToWire + Deserialize<'de>,
    R: Read,
    W: manticore::io::Write,
{
    let mut de = serde_json::Deserializer::from_reader(reader);
    let msg = T::deserialize(&mut de).expect("failed to deserialize JSON");
    msg.to_wire(writer).expect("failed to write request");
}

/// Converts a JSON object into a Manticore command.
///
/// This function deserializes a message in JSON format from `input_file` and
/// then serializes a header + message in wire format to.`output_file`.
///
/// Uses `cmd_type` and `is_request` to determine the message type since the
/// JSON format does not include the message header.
fn from_json(
    cmd_type: CommandType,
    is_request: bool,
    input: impl Read,
    mut output: impl Write,
) {
    let mut stdwrite = StdWrite(&mut output);

    Header {
        is_request: is_request,
        command: cmd_type,
    }
    .to_wire(&mut stdwrite)
    .expect("failed to write header");

    match (is_request, cmd_type) {
        (true, CommandType::FirmwareVersion) => {
            from_json_to_wire::<firmware_version::FirmwareVersionRequest, _, _>(
                input, stdwrite,
            )
        }
        (false, CommandType::FirmwareVersion) => {
            from_json_to_wire::<firmware_version::FirmwareVersionResponse, _, _>(
                input, stdwrite,
            )
        }
        _ => panic!("Unsupported message type"),
    }
}

/// Macro to deserialize wire format from an input file and then run an
/// operation on the deserialized message.
///
/// This macro is a temporary workaround some Serde limiatations.
///
/// Arguments:
/// * `input_file`: Identifier to get the input file name from.
/// * `body`: A "generic" closure to run with the results of the parse.
macro_rules! read_wire_and_operate {
    ($input:ident, $body:expr) => {
        let mut input = $input;
        let mut read_buf = Vec::new();
        input
            .read_to_end(&mut read_buf)
            .expect("couldn't read from file");

        let mut arena = vec![0u8; 1024];
        let arena = BumpArena::new(&mut arena);

        let mut read_buf_slice = read_buf.as_slice();
        let header = Header::from_wire(&mut read_buf_slice, &arena)
            .expect("failed to read header");
        match (header.is_request, header.command) {
            (true, CommandType::FirmwareVersion) => {
                let message =
                    firmware_version::FirmwareVersionRequest::from_wire(
                        &mut read_buf_slice,
                        &arena,
                    )
                    .expect("failed to read response");
                let body = $body;
                body(message)
            }
            (false, CommandType::FirmwareVersion) => {
                let message =
                    firmware_version::FirmwareVersionResponse::from_wire(
                        &mut read_buf_slice,
                        &arena,
                    )
                    .expect("failed to read response");
                let body = $body;
                body(message)
            }
            _ => panic!("unsupported response type {:?}", header.command),
        }
    };
}

/// Converts a Manticore command into a JSON object.
///
/// This funciton deserializes a header + message in wire format from `input`
/// and then serialize the message as JSON to `output`.
fn to_json(pretty: bool, input: impl Read, output: impl Write) {
    read_wire_and_operate!(input, |msg| {
        if pretty {
            serde_json::to_writer_pretty(output, &msg)
        } else {
            serde_json::to_writer(output, &msg)
        }
        .expect("failed to serialize to JSON")
    });
}

#[deny(missing_docs)]
#[derive(Debug, StructOpt)]
#[structopt(
    author,
    about = "Command-line tool for working with Manticore data"
)]
enum CliCommand {
    /// Construct a Cerberus message from a JSON representation.
    FromJson {
        /// The command type for the message.
        #[structopt(short = "t", long)]
        cmd_type: CommandType,

        /// Whether this message is a request.
        #[structopt(short = "r", long)]
        is_request: bool,

        /// JSON file containing the message; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// Binary output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
    /// Display a Cerberus message as its JSON representation.
    ToJson {
        /// Whether to pretty-print the resulting JSON.
        #[structopt(short = "p", long)]
        pretty: bool,

        /// Binary file containing the message; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// JSON output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
    /// Create a new signed manifest.
    SignManifest {
        /// PKCS#8-encoded RSA signing key to sign with.
        #[structopt(short = "k", long, parse(from_os_str))]
        key: PathBuf,

        /// The manifest type for this operation.
        #[structopt(short = "t", long)]
        manifest_type: ManifestType,

        /// The version to encode into the manifest container.
        #[structopt(short = "v", long)]
        manifest_version: u32,

        /// JSON file containing the manifest to sign; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// Binary output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
    /// Inspect an existing manifest.
    ShowManifest {
        /// PKCS#8-encoded RSA public key to optionally verify the signature
        #[structopt(short = "k", long, parse(from_os_str))]
        key: Option<PathBuf>,

        /// Whether to pretty-print the resulting JSON.
        #[structopt(short = "p", long)]
        pretty: bool,

        /// Binary file containing the manifest to parse; defaults to stdin.
        #[structopt(short = "i", long, parse(from_os_str))]
        input: Option<PathBuf>,

        /// JSON output file; defaults to stdout.
        #[structopt(short = "o", long, parse(from_os_str))]
        output: Option<PathBuf>,
    },
}

fn main() {
    match CliCommand::from_args() {
        CliCommand::FromJson {
            cmd_type,
            is_request,
            input,
            output,
        } => {
            let (input, output) = open_files(input, output);
            from_json(cmd_type, is_request, input, output);
        }
        CliCommand::ToJson {
            pretty,
            input,
            output,
        } => {
            let (input, output) = open_files(input, output);
            to_json(pretty, input, output);
        }
        CliCommand::SignManifest {
            key,
            manifest_type,
            manifest_version,
            input,
            output,
        } => {
            let (mut input, mut output) = open_files(input, output);

            let key = fs::read(key).expect("failed to open file");
            let keypair = ring::rsa::Keypair::from_pkcs8(&key)
                .expect("failed to parse key");
            let mut signer = ring::rsa::Builder::new()
                .new_signer(keypair)
                .expect("failed to create signing engine");

            let mut manifest_buf = vec![0; 0x2000];
            let mut container = Containerizer::new(&mut manifest_buf)
                .expect("failed to create containerizer")
                .with_type(manifest_type)
                .expect("failed to set manifest type")
                .with_metadata(&Metadata {
                    version_id: manifest_version,
                })
                .expect("failed to set manifest metadata");

            match manifest_type {
                ManifestType::Fpm => {
                    let mut buf = Vec::new();
                    input.read_to_end(&mut buf).expect("failed to read file");

                    let fpm: Fpm<provenance::Adhoc> =
                        serde_json::from_slice(&buf)
                            .expect("failed to parse JSON");
                    fpm.unparse(&mut container)
                        .expect("failed to serialize manifest");
                }
            }

            let manifest = container
                .sign(&mut signer)
                .expect("failed to sign manifest");
            output
                .write_all(manifest)
                .expect("failed to write manifest");
        }
        CliCommand::ShowManifest {
            key,
            pretty,
            input,
            output,
        } => {
            let (mut input, output) = open_files(input, output);

            let engine = key.map(|key| {
                let key = fs::read(key).expect("failed to open file");
                let keypair = ring::rsa::Keypair::from_pkcs8(&key)
                    .expect("failed to parse key");
                ring::rsa::Builder::new()
                    .new_engine(keypair.public())
                    .expect("failed to create signature verification engine")
            });
            let mut buf = Vec::new();
            input.read_to_end(&mut buf).expect("failed to read file");

            let container = match engine {
                Some(mut engine) => {
                    match Container::parse_and_verify(&buf, &mut engine) {
                        Ok(c) => c,
                        Err(manifest::Error::SignatureFailure) => {
                            panic!("failed to verify signature")
                        }
                        Err(_) => panic!("failed to parse manifest container"),
                    }
                    .downgrade()
                }
                None => Container::parse(&buf)
                    .expect("failed to parse manifest container"),
            };

            match container.manifest_type() {
                ManifestType::Fpm => {
                    let fpm = Fpm::parse(container)
                        .expect("failed to parse manifest");
                    if pretty {
                        serde_json::to_writer_pretty(output, &fpm)
                            .expect("failed to write file");
                    } else {
                        serde_json::to_writer(output, &fpm)
                            .expect("failed to write file");
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Ignore dotfiles in tree traversal<commit_after><|endoftext|>


<commit_before>use std::process::{Command, exit};
use std::fs::{OpenOptions, File};
use std::io::prelude::*;
use std::io::{BufReader,BufRead};
use std::error::Error;
use std::path::Path;

fn main() {
    let keys:Vec<String> =
        vec!["AEFB411B072836CD48FF0381AE252C284B5DBA5D".to_string(),
             "9E4F11C6A072942A7B3FD3B0B81EB14A09A25EB0".to_string(),
             "35F52A02854DCCAEC9DD5CC410443C7F54B00041".to_string()];
    let keys_clone:Vec<String> = keys.clone();
    //let mut contents:Vec<String> = vec![];
    gpg_import_keys(keys);
    let init_check:bool = gpg_init();
    if !init_check{
        println!("Update has failed, after gpg keys have been imported.");
        println!("Ensure you run update with \"sudo\", or super user privileges");
        exit(1);
    }else {
        println!("GPG Init: Task Completed Successfully!");
    }
    gpg_remove_keys(keys_clone);
    let mut contents:Vec<String> = check_pacman_conf();
    create_pacman_conf_old();
    create_new_pacman_conf(contents);
    archlabs_keyring();
    key_populate();
    contents = pacman_conf_final();
    create_new_pacman_conf(contents);

    println!("The automated update portion of the process has completed!");
    println!("Please visit the ArchLABs Forums:");
    println!("https://www.tapatalk.com/groups/archlabs\
    /upgrade-guide-for-existing-installations-t432.html");
    println!("To continue with the manual steps in the process...");
}

fn gpg_import_keys(k:Vec<String>) {

    let mut check:i8 = 0;
    for item in k.iter(){
        let keys:String =
            item.to_string();

        let output = Command::new("gpg")
            .arg("--receive-keys")
            .arg(keys.to_string())
            .output()
            .expect("Process Failed to Execute!");
        if output.stderr.is_empty(){
            println!("{}", String::from_utf8(output.stdout).unwrap());
            check +=1 ; //or default of true
        }else {
            println!("{}", String::from_utf8(output.stderr).unwrap());
            check -= 1;
        }
    }
    if check != 3{
        // One or more keys were not imported.
        print!("{} ", (check*-1));
        println!("keys were not imported");
    }else if check == 3 {
        print!("{} ", (check));
        println!("keys were imported successfully.");
    }
}

fn gpg_init() -> bool{
    let check:bool;
    let output = Command::new("pacman-key")
        .arg("--init")
        .output()
        .expect("Process Failed to Execute!");
    if output.stderr.is_empty(){
        print!("Success: ");
        println!("{}", String::from_utf8(output.stdout).unwrap());
        check = true;
    }else {
        print!("Error: ");
        println!("{}", String::from_utf8(output.stderr).unwrap());
        check = false;
    }
    return check;
}

fn gpg_remove_keys(k:Vec<String>) {

    let mut check:i8 = 0;
    for item in k.iter() {
        let keys:String =
            item.to_string();

        let output =
            Command::new("pacman-key")
            .arg("-r")
            .arg(keys.to_string())
            .output()
            .expect("Process Failed to Execute!");

        if output.stderr.is_empty(){
            println!("{}", String::from_utf8(output.stdout).unwrap());
            check +=1 ; //or default of true
        }else {
            println!("{}", String::from_utf8(output.stderr).unwrap());
            check -= 1;
        }
    }
    if check != 3{
        // One or more keys were not imported.
        print!("{} ", (check*-1));
        println!("keys were not removed!");
    }else if check == 3 {
        print!("{} ", (check));
        println!("keys were removed successfully.");
    }
}

fn create_pacman_conf_old(){
    let output = Command::new("mv")
        .arg("/etc/pacman.conf")
        .arg("/etc/pacman.conf.old")
        .output()
        .expect("Process Failed to Execute!");
    if output.stderr.is_empty(){
        println!("{}", String::from_utf8(output.stdout).unwrap());
        println!("Back up of \"pacman.conf\" complete!");
    }else {
        println!("{}", String::from_utf8(output.stderr).unwrap());
    }
}
//This function will be called on two separate iterations
fn create_new_pacman_conf(x:Vec<String>) {
    let path = Path::new("/etc/pacman.conf");
    let display = path.display();
    // Open a file in write-only mode, returns `io::Result<File>`
    let _file = match File::create(&path) {
        Err(why) => panic!("couldn't create {}: {}",
                           display,
                           why.description()),
        Ok(_file) => _file,
    };

    let mut f = OpenOptions::new()
        .write(true)
        .append(true)
        .open("/etc/pacman.conf")
        .unwrap();
    for item in x.iter(){
        if let Err(e) =
        writeln!(f, "{}",item.to_string()){
            println!("{}", e);
        }
    }
}

fn check_pacman_conf() ->Vec<String> {

    let mut contents:Vec<String> = vec![];
    let check_str_one:String =
        "#[archlabs_repo]".to_string();
    let check_str_two:String =
        "[archlabs_repo]".to_string();
    let check_str_three:String =
        "#SigLevel = Never".to_string();
    let check_str_four:String =
        "SigLevel = Never".to_string();
    let check_str_five:String =
        "#Server = https://archlabs.github.io/archlabs_repo/$arch".to_string();
    let check_str_six:String =
        "Server = https://archlabs.github.io/archlabs_repo/$arch".to_string();
    let check_str_seven:String =
        "#Server = https://downloads.sourceforge.net/project/\
        archlabs-repo/archlabs_repo/$arch".to_string();
    let check_str_eight:String =
        "Server = https://downloads.sourceforge.net/project/\
        archlabs-repo/archlabs_repo/$arch".to_string();

    let filename = r"/etc/pacman.conf";
    let f =
        BufReader::new(File::open(filename).unwrap());
    for line in f.lines() {
        match line {
            Ok(line) => if line.contains(&check_str_one) {
                let str_replace =
                    line.replace(&check_str_one, &check_str_two);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_three) {
                let str_replace =
                    line.replace(&check_str_three, &check_str_four);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_five) {
                let str_replace =
                    line.replace(&check_str_five, &check_str_six);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_seven) {
                let str_replace =
                    line.replace(&check_str_seven, &check_str_eight);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else {
                contents.push(line.to_string());
                //println!("{}", line.to_string());
            }
            //Error logic is flawed.. need to workout error check
            //to determine if pacman.conf needs to be modified.
            Err(_) => if check_str_two.eq(line.unwrap().as_str()) {
                println!("No change needed");
            } else {
                println!("Something Happened");
            }
        };
    };
    return contents;
}

fn archlabs_keyring() {
    let output =
        Command::new("pacman")
            .arg("-S")
            .arg("archlabs-keyring")
            .output()
            .expect("Process Failed To Execute!");
    if output.stderr.is_empty(){
        println!("{}", String::from_utf8(output.stdout).unwrap());

    }else {
        println!("{}", String::from_utf8(output.stdout).unwrap());
    }
}

fn key_populate() {
    let output =
        Command::new("pacman-key")
            .arg("--populate")
            .arg("archlabs")
            .output()
            .expect("Process Failed To Execute!");
    if output.stderr.is_empty(){
        println!("{}", String::from_utf8(output.stdout).unwrap());
    }else {
        println!("{}", String::from_utf8(output.stderr).unwrap());
    }
}

fn pacman_conf_final() -> Vec<String>{

    let mut contents:Vec<String> = vec![];
    let check_str_one:String =
        "[archlabs_repo]".to_string();
    let check_str_two:String =
        "SigLevel = Never".to_string();
    let check_str_three:String =
        "SigLevel = Optional TrustAll".to_string();
    let filename = r"/etc/pacman.conf";
    let f =
        BufReader::new(File::open(filename).unwrap());
    for line in f.lines() {
        match line {
            Ok(line) => if line.contains(&check_str_one) {
                let str_replace =
                    line.replace(&check_str_one, &check_str_one);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_two) {
                let str_replace =
                    line.replace(&check_str_two, &check_str_three);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else {
                contents.push(line.to_string());
                //println!("{}", line.to_string());
            }
            //Error logic is flawed.. need to workout error check
            //to determine if pacman.conf needs to be modified.
            Err(_) => if check_str_two.eq(line.unwrap().as_str()) {
                println!("No change needed");
            } else {
                println!("Something Happened");
            }
        };
    };
    return contents;
}<commit_msg>Change Two Primary FNs<commit_after>use std::process::{Command, exit};
use std::fs::{OpenOptions, File};
use std::io::prelude::*;
use std::io::{BufReader,BufRead};
use std::error::Error;
use std::path::Path;

fn main() {
    let keys:Vec<String> =
        vec!["AEFB411B072836CD48FF0381AE252C284B5DBA5D".to_string(),
             "9E4F11C6A072942A7B3FD3B0B81EB14A09A25EB0".to_string(),
             "35F52A02854DCCAEC9DD5CC410443C7F54B00041".to_string()];
    let keys_clone:Vec<String> = keys.clone();

    gpg_import_keys(keys);
    let init_check:bool = gpg_init();
    if !init_check{
        println!("Update has failed, after gpg keys have been imported.");
        println!("Ensure you run update with \"sudo\", or super user privileges");
        exit(1);
    }else {
        println!("GPG Init: Task Completed Successfully!");
    }
    gpg_remove_keys(keys_clone);
    let mut contents:Vec<String> = check_pacman_conf();
    create_pacman_conf_old();
    create_new_pacman_conf(contents);
    archlabs_keyring();
    key_populate();
    contents = pacman_conf_final();
    create_new_pacman_conf(contents);

    println!("The automated update portion of the process has completed!");
    println!("Please visit the ArchLABs Forums:");
    println!("https://www.tapatalk.com/groups/archlabs\
    /upgrade-guide-for-existing-installations-t432.html");
    println!("To continue with the manual steps in the process...");
}

fn gpg_import_keys(k:Vec<String>) {

    let mut check:i8 = 0;
    for item in k.iter(){
        let keys:String =
            item.to_string();

        let output = Command::new("gpg")
            .arg("--receive-keys")
            .arg(keys.to_string())
            .output()
            .expect("Process Failed to Execute!");
        if output.stderr.is_empty(){
            println!("{}", String::from_utf8(output.stdout).unwrap());
            check +=1 ; //or default of true
        }else {
            println!("{}", String::from_utf8(output.stderr).unwrap());
            check -= 1;
        }
    }
    if check != 3{
        // One or more keys were not imported.
        print!("{} ", (check*-1));
        println!("keys were not imported");
    }else if check == 3 {
        print!("{} ", (check));
        println!("keys were imported successfully.");
    }
}

fn gpg_init() -> bool{
    let check:bool;
    let output = Command::new("pacman-key")
        .arg("--init")
        .output()
        .expect("Process Failed to Execute!");
    if output.stderr.is_empty(){
        print!("Success: ");
        println!("{}", String::from_utf8(output.stdout).unwrap());
        check = true;
    }else {
        print!("Error: ");
        println!("{}", String::from_utf8(output.stderr).unwrap());
        check = false;
    }
    return check;
}

fn gpg_remove_keys(k:Vec<String>) {

    let mut check:i8 = 0;
    for item in k.iter() {
        let keys:String =
            item.to_string();

        let output =
            Command::new("pacman-key")
            .arg("-r")
            .arg(keys.to_string())
            .output()
            .expect("Process Failed to Execute!");

        if output.stderr.is_empty(){
            println!("{}", String::from_utf8(output.stdout).unwrap());
            check +=1 ; //or default of true
        }else {
            println!("{}", String::from_utf8(output.stderr).unwrap());
            check -= 1;
        }
    }
    if check != 3{
        // One or more keys were not imported.
        print!("{} ", (check*-1));
        println!("keys were not removed!");
    }else if check == 3 {
        print!("{} ", (check));
        println!("keys were removed successfully.");
    }
}

fn create_pacman_conf_old(){
    let output = Command::new("mv")
        .arg("/etc/pacman.conf")
        .arg("/etc/pacman.conf.old")
        .output()
        .expect("Process Failed to Execute!");
    if output.stderr.is_empty(){
        println!("{}", String::from_utf8(output.stdout).unwrap());
        println!("Back up of \"pacman.conf\" complete!");
    }else {
        println!("{}", String::from_utf8(output.stderr).unwrap());
    }
}
//This function will be called on two separate iterations
fn create_new_pacman_conf(x:Vec<String>) {
    let path = Path::new("/etc/pacman.conf");
    let display = path.display();
    // Open a file in write-only mode, returns `io::Result<File>`
    let _file = match File::create(&path) {
        Err(why) => panic!("couldn't create {}: {}",
                           display,
                           why.description()),
        Ok(_file) => _file,
    };

    let mut f = OpenOptions::new()
        .write(true)
        .append(true)
        .open("/etc/pacman.conf")
        .unwrap();
    for item in x.iter(){
        if let Err(e) =
        writeln!(f, "{}",item.to_string()){
            println!("{}", e);
        }
    }
}

fn check_pacman_conf() ->Vec<String> {

    let mut contents:Vec<String> = vec![];
    let check_str_one:String =
        "#[archlabs_repo]".to_string();
    let check_str_two:String =
        "[archlabs_repo]".to_string();
    let check_str_three:String =
        "#SigLevel = Never".to_string();
    let check_str_four:String =
        "SigLevel = Never".to_string();
    let check_str_five:String =
        "#Server = https://archlabs.github.io/archlabs_repo/$arch".to_string();
    let check_str_six:String =
        "Server = https://archlabs.github.io/archlabs_repo/$arch".to_string();
    let check_str_seven:String =
        "#Server = https://downloads.sourceforge.net/project/\
        archlabs-repo/archlabs_repo/$arch".to_string();
    let check_str_eight:String =
        "Server = https://downloads.sourceforge.net/project/\
        archlabs-repo/archlabs_repo/$arch".to_string();

    let filename = r"/etc/pacman.conf";
    let f =
        BufReader::new(File::open(filename).unwrap());
    for line in f.lines() {
        match line {
            Ok(line) => if line.contains(&check_str_one) {
                let str_replace =
                    line.replace(&check_str_one, &check_str_two);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_three) {
                let str_replace =
                    line.replace(&check_str_three, &check_str_four);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_five) {
                let str_replace =
                    line.replace(&check_str_five, &check_str_six);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_seven) {
                let str_replace =
                    line.replace(&check_str_seven, &check_str_eight);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else {
                contents.push(line.to_string());
                //println!("{}", line.to_string());
            }
            /* Logic is untested, but should work.
               Fail Trigger contained below. See
               comment above fn restore_pacman_conf
               for a final description of task.
            */
            Err(_) => if line.is_err() { // check_str_two.eq(line.unwrap().as_str())
                let output = Command::new("rm")
                    .arg("-v")
                    .arg("/etc/pacman.conf")
                    .output()
                    .expect("Process Failed To Execute!");
                if output.stderr.is_empty(){
                    println!("Restoring \"pacman.conf\" from .old");
                    println!("{}", String::from_utf8(output.stdout).unwrap());
                    let check:bool = restore_pacman_conf();
                    println!("Restoration compeleted: {}", check);
                }else {
                    println!("Failed to restore \"pacman.conf\" from .old");
                    println!("{}", String::from_utf8(output.stderr).unwrap());
                }
            }
        };
    };
    return contents;
}

fn archlabs_keyring() {
    let output =
        Command::new("pacman")
            .arg("-S")
            .arg("archlabs-keyring")
            .output()
            .expect("Process Failed To Execute!");
    if output.stderr.is_empty(){
        println!("{}", String::from_utf8(output.stdout).unwrap());

    }else {
        println!("{}", String::from_utf8(output.stdout).unwrap());
    }
}

fn key_populate() {
    let output =
        Command::new("pacman-key")
            .arg("--populate")
            .arg("archlabs")
            .output()
            .expect("Process Failed To Execute!");
    if output.stderr.is_empty(){
        println!("{}", String::from_utf8(output.stdout).unwrap());
    }else {
        println!("{}", String::from_utf8(output.stderr).unwrap());
    }
}

fn pacman_conf_final() -> Vec<String>{

    let mut contents:Vec<String> = vec![];
    let check_str_one:String =
        "[archlabs_repo]".to_string();
    let check_str_two:String =
        "SigLevel = Never".to_string();
    let check_str_three:String =
        "SigLevel = Optional TrustAll".to_string();
    let filename = r"/etc/pacman.conf";
    let f =
        BufReader::new(File::open(filename).unwrap());
    for line in f.lines() {
        match line {
            Ok(line) => if line.contains(&check_str_one) {
                let str_replace =
                    line.replace(&check_str_one, &check_str_one);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else if line.contains(&check_str_two) {
                let str_replace =
                    line.replace(&check_str_two, &check_str_three);
                contents.push(str_replace.to_string());
                //println!("{}", str_replace);
            } else {
                contents.push(line.to_string());
                //println!("{}", line.to_string());
            }
            /* Logic is untested, but should work.
               Fail Trigger contained below. See
               comment above fn restore_pacman_conf
               for a final description of task.
            */
            Err(_) => if line.is_err() { // check_str_three.eq(line.unwrap().as_str())
                let output = Command::new("rm")
                    .arg("-v")
                    .arg("/etc/pacman.conf")
                    .output()
                    .expect("Process Failed To Execute!");
                //println!("No change needed");
                if output.stderr.is_empty(){
                    println!("Restoring \"pacman.conf\" from .old");
                    println!("{}", String::from_utf8(output.stdout).unwrap());
                    let check:bool = restore_pacman_conf();
                    println!("Restoration compeleted: {}", check);
                }else {
                    println!("Failed to restore \"pacman.conf\" from .old");
                    println!("{}", String::from_utf8(output.stderr).unwrap());
                }
            }
        };
    };
    return contents;
}
/* Introduced simple restoration logic,
   when the file write encounters an error.
   This should not trigger in most cases,
   but it is a fail safe to restore pacman.conf.
*/
fn restore_pacman_conf() -> bool {
    let success:bool;
    let output = Command::new("mv")
        .arg("-v")
        .arg("/etc/pacman.conf.old /etc/pacman.conf")
        .output()
        .expect("Procress Failed to Execute!");
    if output.stderr.is_empty() {
        success = true;
    }else {
        success = false;
    }
    return success;
}<|endoftext|>


<commit_before><commit_msg>updates<commit_after><|endoftext|>


<commit_before>use clap::{AppSettings, Parser};
use std::fmt::{self, Display};
use std::path::PathBuf;
use std::str::FromStr;
use syn_select::Selector;

#[derive(Parser)]
#[clap(bin_name = "cargo", version, author)]
pub enum Opts {
    /// Show the result of macro expansion.
    #[clap(
        name = "expand",
        version,
        author,
        setting = AppSettings::DeriveDisplayOrder,
        setting = AppSettings::DontCollapseArgsInUsage
    )]
    Expand(Args),
}

#[derive(Parser, Debug)]
pub struct Args {
    /// Space-separated list of features to activate
    #[clap(long, value_name = "FEATURES")]
    pub features: Option<String>,

    /// Activate all available features
    #[clap(long)]
    pub all_features: bool,

    /// Do not activate the `default` feature
    #[clap(long)]
    pub no_default_features: bool,

    /// Expand only this package's library
    #[clap(long)]
    pub lib: bool,

    /// Expand only the specified binary
    #[clap(long, value_name = "NAME")]
    pub bin: Option<String>,

    /// Expand only the specified example
    #[clap(long, value_name = "NAME")]
    pub example: Option<String>,

    /// Expand only the specified test target
    #[clap(long, value_name = "NAME")]
    pub test: Option<String>,

    /// Include tests when expanding the lib or bin
    #[clap(long)]
    pub tests: bool,

    /// Expand only the specified bench target
    #[clap(long, value_name = "NAME")]
    pub bench: Option<String>,

    /// Target triple which compiles will be for
    #[clap(long, value_name = "TARGET")]
    pub target: Option<String>,

    /// Directory for all generated artifacts
    #[clap(long, value_name = "DIRECTORY", parse(from_os_str))]
    pub target_dir: Option<PathBuf>,

    /// Path to Cargo.toml
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to expand
    #[clap(short, long, value_name = "SPEC")]
    pub package: Option<String>,

    /// Build artifacts in release mode, with optimizations
    #[clap(long)]
    pub release: bool,

    /// Number of parallel jobs, defaults to # of CPUs
    #[clap(short, long, value_name = "N")]
    pub jobs: Option<u64>,

    /// Print command lines as they are executed
    #[clap(long)]
    pub verbose: bool,

    /// Coloring: auto, always, never
    #[clap(long, value_name = "WHEN")]
    pub color: Option<Coloring>,

    /// Require Cargo.lock and cache are up to date
    #[clap(long)]
    pub frozen: bool,

    /// Require Cargo.lock is up to date
    #[clap(long)]
    pub locked: bool,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Unstable (nightly-only) flags to Cargo
    #[clap(short = 'Z', value_name = "FLAG")]
    pub unstable_flags: Vec<String>,

    /// Do not attempt to run rustfmt
    #[clap(long)]
    pub ugly: bool,

    /// Select syntax highlighting theme
    #[clap(long, value_name = "NAME")]
    pub theme: Option<String>,

    /// Print available syntax highlighting theme names
    #[clap(long)]
    pub themes: bool,

    /// Local path to module or other named item to expand, e.g. os::unix::ffi
    #[clap(value_name = "ITEM", parse(try_from_str = parse_selector))]
    pub item: Option<Selector>,
}

#[derive(Debug, Clone, Copy)]
pub enum Coloring {
    Auto,
    Always,
    Never,
}

impl FromStr for Coloring {
    type Err = String;

    fn from_str(name: &str) -> Result<Self, Self::Err> {
        match name {
            "auto" => Ok(Coloring::Auto),
            "always" => Ok(Coloring::Always),
            "never" => Ok(Coloring::Never),
            other => Err(format!(
                "must be auto, always, or never, but found `{}`",
                other,
            )),
        }
    }
}

impl Display for Coloring {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Coloring::Auto => "auto",
            Coloring::Always => "always",
            Coloring::Never => "never",
        };
        formatter.write_str(name)
    }
}

fn parse_selector(s: &str) -> Result<Selector, <Selector as FromStr>::Err> {
    if s.starts_with("::") {
        s[2..].parse()
    } else {
        s.parse()
    }
}

#[test]
fn test_cli() {
    <Opts as clap::IntoApp>::into_app().debug_assert();
}
<commit_msg>Resolve clap deprecations<commit_after>use clap::{AppSettings, Parser};
use std::fmt::{self, Display};
use std::path::PathBuf;
use std::str::FromStr;
use syn_select::Selector;

#[derive(Parser)]
#[clap(bin_name = "cargo", version, author)]
pub enum Opts {
    /// Show the result of macro expansion.
    #[clap(
        name = "expand",
        version,
        author,
        setting = AppSettings::DeriveDisplayOrder,
        dont_collapse_args_in_usage = true
    )]
    Expand(Args),
}

#[derive(Parser, Debug)]
pub struct Args {
    /// Space-separated list of features to activate
    #[clap(long, value_name = "FEATURES")]
    pub features: Option<String>,

    /// Activate all available features
    #[clap(long)]
    pub all_features: bool,

    /// Do not activate the `default` feature
    #[clap(long)]
    pub no_default_features: bool,

    /// Expand only this package's library
    #[clap(long)]
    pub lib: bool,

    /// Expand only the specified binary
    #[clap(long, value_name = "NAME")]
    pub bin: Option<String>,

    /// Expand only the specified example
    #[clap(long, value_name = "NAME")]
    pub example: Option<String>,

    /// Expand only the specified test target
    #[clap(long, value_name = "NAME")]
    pub test: Option<String>,

    /// Include tests when expanding the lib or bin
    #[clap(long)]
    pub tests: bool,

    /// Expand only the specified bench target
    #[clap(long, value_name = "NAME")]
    pub bench: Option<String>,

    /// Target triple which compiles will be for
    #[clap(long, value_name = "TARGET")]
    pub target: Option<String>,

    /// Directory for all generated artifacts
    #[clap(long, value_name = "DIRECTORY", parse(from_os_str))]
    pub target_dir: Option<PathBuf>,

    /// Path to Cargo.toml
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to expand
    #[clap(short, long, value_name = "SPEC")]
    pub package: Option<String>,

    /// Build artifacts in release mode, with optimizations
    #[clap(long)]
    pub release: bool,

    /// Number of parallel jobs, defaults to # of CPUs
    #[clap(short, long, value_name = "N")]
    pub jobs: Option<u64>,

    /// Print command lines as they are executed
    #[clap(long)]
    pub verbose: bool,

    /// Coloring: auto, always, never
    #[clap(long, value_name = "WHEN")]
    pub color: Option<Coloring>,

    /// Require Cargo.lock and cache are up to date
    #[clap(long)]
    pub frozen: bool,

    /// Require Cargo.lock is up to date
    #[clap(long)]
    pub locked: bool,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Unstable (nightly-only) flags to Cargo
    #[clap(short = 'Z', value_name = "FLAG")]
    pub unstable_flags: Vec<String>,

    /// Do not attempt to run rustfmt
    #[clap(long)]
    pub ugly: bool,

    /// Select syntax highlighting theme
    #[clap(long, value_name = "NAME")]
    pub theme: Option<String>,

    /// Print available syntax highlighting theme names
    #[clap(long)]
    pub themes: bool,

    /// Local path to module or other named item to expand, e.g. os::unix::ffi
    #[clap(value_name = "ITEM", parse(try_from_str = parse_selector))]
    pub item: Option<Selector>,
}

#[derive(Debug, Clone, Copy)]
pub enum Coloring {
    Auto,
    Always,
    Never,
}

impl FromStr for Coloring {
    type Err = String;

    fn from_str(name: &str) -> Result<Self, Self::Err> {
        match name {
            "auto" => Ok(Coloring::Auto),
            "always" => Ok(Coloring::Always),
            "never" => Ok(Coloring::Never),
            other => Err(format!(
                "must be auto, always, or never, but found `{}`",
                other,
            )),
        }
    }
}

impl Display for Coloring {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Coloring::Auto => "auto",
            Coloring::Always => "always",
            Coloring::Never => "never",
        };
        formatter.write_str(name)
    }
}

fn parse_selector(s: &str) -> Result<Selector, <Selector as FromStr>::Err> {
    if s.starts_with("::") {
        s[2..].parse()
    } else {
        s.parse()
    }
}

#[test]
fn test_cli() {
    <Opts as clap::CommandFactory>::command().debug_assert();
}
<|endoftext|>


<commit_before>//! The Brainfuck interpreter executable.
//!
//! ```
//! USAGE:
//!     bfi [FLAGS] [OPTIONS] [--] [FILE]...
//!
//! FLAGS:
//!         --ast          Interpret the unoptimized AST
//!         --byte         Compile AST to bytecode
//!     -h, --help         Prints help information
//!         --jit          JIT to native x64 (default)
//!         --llvm         JIT using LLVM
//!         --peep         Interpret the peephole-optimized AST
//!         --rle          Interpret the run-length encoded the AST
//!     -u, --unchecked    Omit memory bounds checks in JIT
//!     -V, --version      Prints version information
//!
//! OPTIONS:
//!     -e, --expr <CODE>...    BF code to execute
//!     -s, --size <SIZE>       Memory size in bytes (default 30,000)
//!
//! ARGS:
//!     <FILE>...    The source file(s) to interpret
//! ```
//!
//! See [the library crate documentation](../bf/index.html) for more.

extern crate bf;
extern crate clap;

use std::io::{self, Read, Write};
use std::fs::File;
use std::process::exit;

use clap::{Arg, App};

use bf::ast;
use bf::traits::*;

const VERSION: &'static str = "0.4.3";

#[derive(Debug, Clone)]
struct Options {
    program_text:  Vec<u8>,
    memory_size:   Option<usize>,
    compiler_pass: Pass,
    unchecked:     bool,
}

#[derive(Debug, Clone, Copy)]
enum Pass {
    Ast,
    Rle,
    Bytecode,
    Peephole,
    #[cfg(feature = "jit")]
    Jit,
    #[cfg(feature = "llvm")]
    Llvm,
}

fn main() {
    let options = get_options();

    let program = parse(&options);

    match options.compiler_pass {
        Pass::Ast => {
            interpret(&*program, &options);
        }

        Pass::Rle => {
            let program = program.rle_compile();
            interpret(&*program, &options);
        }

        Pass::Peephole => {
            let program = program.peephole_compile();
            interpret(&*program, &options);
        }

        Pass::Bytecode => {
            let program = program.bytecode_compile();
            interpret(&*program, &options);
        }

        #[cfg(feature = "jit")]
        Pass::Jit => {
            let program = program.jit_compile(!options.unchecked);
            interpret(&program, &options);
        }

        #[cfg(feature = "llvm")]
        Pass::Llvm => {
            program.llvm_run(options.memory_size)
                .unwrap_or_else(|e| error_exit(3, format!("runtime error: {}.", e)));
        }
    }
}

fn parse(options: &Options) -> Box<ast::Program> {
    ast::parse_program(&options.program_text)
        .unwrap_or_else(|e| error_exit(2, format!("syntax error: {}.", e)))
}

fn interpret<P: Interpretable + ?Sized>(program: &P, options: &Options) {
    program.interpret_stdin(options.memory_size)
        .unwrap_or_else(|e| error_exit(3, format!("runtime error: {}.", e)))
}

#[cfg(feature = "jit")]
const DEFAULT_PASS: Pass = Pass::Jit;

#[cfg(all(feature = "llvm", not(feature = "jit")))]
const DEFAULT_PASS: Pass = Pass::Llvm;

#[cfg(not(any(feature = "jit", feature = "llvm")))]
const DEFAULT_PASS: Pass = Pass::Peephole;

fn get_options() -> Options {
    let mut result = Options {
        program_text:  Vec::new(),
        memory_size:   None,
        compiler_pass: DEFAULT_PASS,
        unchecked:     false,
    };

    let matches = build_clap_app().get_matches();

    if let Some(size) = matches.value_of("size") {
        let size = size.parse()
            .unwrap_or_else(|e|
                error_exit(1, format!("error: could not parse memory size: {}.", e)));
        if size == 0 {
            error_exit(1, "error: memory size must be at least 1.".to_owned());
        }
        result.memory_size = Some(size);
    }

    if matches.is_present("jit") {
        #[cfg(feature = "jit")]
        let _ = result.compiler_pass = Pass::Jit;
    } else if matches.is_present("llvm") {
        #[cfg(feature = "llvm")]
        let _ = result.compiler_pass = Pass::Llvm;
    } else if matches.is_present("byte") {
        result.compiler_pass = Pass::Bytecode;
    } else if matches.is_present("peep") {
        result.compiler_pass = Pass::Peephole;
    } else if matches.is_present("rle") {
        result.compiler_pass = Pass::Rle;
    } else if matches.is_present("ast") {
        result.compiler_pass = Pass::Ast;
    }

    if matches.is_present("unchecked") {
        result.unchecked = true;
    }

    if let Some(exprs) = matches.values_of("expr") {
        for e in exprs {
            result.program_text.extend(e.as_bytes());
        }
    } else if let Some(files) = matches.values_of("FILE") {
        for f in files {
            let mut file = File::open(f)
                .unwrap_or_else(|e| error_exit(1, format!("{}: ‘{}’.", e, f)));
            file.read_to_end(&mut result.program_text)
                .unwrap_or_else(|e| error_exit(1, format!("{}: ‘{}’.", e, f)));
        }
    } else {
        error_exit(1, "error: no program given.".to_owned());
    }

    result
}

fn build_clap_app() -> App<'static, 'static> {
    let app = App::new("bfi")
        .version(VERSION)
        .author("Jesse A. Tov <jesse.tov@gmail.com>")
        .about("A Brainfuck interpreter")
        .arg(Arg::with_name("expr")
            .short("e")
            .long("expr")
            .value_name("CODE")
            .help("BF code to execute")
            .multiple(true)
            .takes_value(true)
            .conflicts_with("FILE"))
        .arg(Arg::with_name("FILE")
            .help("The source file(s) to interpret")
            .multiple(true)
            .conflicts_with("expr")
            .index(1))
        .arg(Arg::with_name("size")
            .short("s")
            .long("size")
            .value_name("SIZE")
            .help("Memory size in bytes (default 30,000)")
            .takes_value(true))
        .arg(Arg::with_name("ast")
            .long("ast")
            .help("Interpret the unoptimized AST")
            .conflicts_with_all(&["rle", "peep", "byte", "jit", "llvm"]))
        .arg(Arg::with_name("rle")
            .long("rle")
            .help("Interpret the run-length encoded the AST")
            .conflicts_with_all(&["ast", "peep", "byte", "jit", "llvm"]))
        .arg(Arg::with_name("peep")
            .long("peep")
            .help(
                if cfg!(feature = "jit") || cfg!(feature = "llvm") {
                    "Interpret the peephole-optimized AST"
                } else {
                    "Interpret the peephole-optimized AST (default)"
                })
            .conflicts_with_all(&["ast", "rle", "byte", "jit", "llvm"]))
        .arg(Arg::with_name("byte")
            .long("byte")
            .help("Compile AST to bytecode")
            .conflicts_with_all(&["ast", "rle", "peep", "jit", "llvm"]));

    #[cfg(feature = "llvm")]
    let app = app
        .arg(Arg::with_name("llvm")
            .long("llvm")
            .help(
                if cfg!(feature = "jit") {
                    "JIT using LLVM (default)"
                } else {
                    "JIT using LLVM"
                })
            .conflicts_with_all(&["ast", "rle", "peep", "byte", "jit"]));

    #[cfg(feature = "jit")]
    let app = app
        .arg(Arg::with_name("jit")
            .long("jit")
            .help("JIT to native x64 (default)")
            .conflicts_with_all(&["ast", "rle", "peep", "byte", "llvm"]));

    #[cfg(any(feature = "jit", feature = "llvm"))]
    let app = app
        .arg(Arg::with_name("unchecked")
            .short("u")
            .long("unchecked")
            .help("Omit memory bounds checks in JIT")
            .conflicts_with_all(&["ast", "rle", "peep", "byte"]));

    app
}

fn error_exit(code: i32, msg: String) -> ! {
    writeln!(io::stderr(), "bfi: {}", msg).unwrap();
    exit(code)
}

<commit_msg>Modified bfi to not use llvm by default.<commit_after>//! The Brainfuck interpreter executable.
//!
//! ```
//! USAGE:
//!     bfi [FLAGS] [OPTIONS] [--] [FILE]...
//!
//! FLAGS:
//!         --ast          Interpret the unoptimized AST
//!         --byte         Compile AST to bytecode
//!     -h, --help         Prints help information
//!         --jit          JIT to native x64 (default)
//!         --llvm         JIT using LLVM
//!         --peep         Interpret the peephole-optimized AST
//!         --rle          Interpret the run-length encoded the AST
//!     -u, --unchecked    Omit memory bounds checks in JIT
//!     -V, --version      Prints version information
//!
//! OPTIONS:
//!     -e, --expr <CODE>...    BF code to execute
//!     -s, --size <SIZE>       Memory size in bytes (default 30,000)
//!
//! ARGS:
//!     <FILE>...    The source file(s) to interpret
//! ```
//!
//! See [the library crate documentation](../bf/index.html) for more.

extern crate bf;
extern crate clap;

use std::io::{self, Read, Write};
use std::fs::File;
use std::process::exit;

use clap::{Arg, App};

use bf::ast;
use bf::traits::*;

const VERSION: &'static str = "0.4.3";

#[derive(Debug, Clone)]
struct Options {
    program_text:  Vec<u8>,
    memory_size:   Option<usize>,
    compiler_pass: Pass,
    unchecked:     bool,
}

#[derive(Debug, Clone, Copy)]
enum Pass {
    Ast,
    Rle,
    Bytecode,
    Peephole,
    #[cfg(feature = "jit")]
    Jit,
    #[cfg(feature = "llvm")]
    Llvm,
}

fn main() {
    let options = get_options();

    let program = parse(&options);

    match options.compiler_pass {
        Pass::Ast => {
            interpret(&*program, &options);
        }

        Pass::Rle => {
            let program = program.rle_compile();
            interpret(&*program, &options);
        }

        Pass::Peephole => {
            let program = program.peephole_compile();
            interpret(&*program, &options);
        }

        Pass::Bytecode => {
            let program = program.bytecode_compile();
            interpret(&*program, &options);
        }

        #[cfg(feature = "jit")]
        Pass::Jit => {
            let program = program.jit_compile(!options.unchecked);
            interpret(&program, &options);
        }

        #[cfg(feature = "llvm")]
        Pass::Llvm => {
            program.llvm_run(options.memory_size)
                .unwrap_or_else(|e| error_exit(3, format!("runtime error: {}.", e)));
        }
    }
}

fn parse(options: &Options) -> Box<ast::Program> {
    ast::parse_program(&options.program_text)
        .unwrap_or_else(|e| error_exit(2, format!("syntax error: {}.", e)))
}

fn interpret<P: Interpretable + ?Sized>(program: &P, options: &Options) {
    program.interpret_stdin(options.memory_size)
        .unwrap_or_else(|e| error_exit(3, format!("runtime error: {}.", e)))
}

#[cfg(feature = "jit")]
const DEFAULT_PASS: Pass = Pass::Jit;

#[cfg(not(feature = "jit"))]
const DEFAULT_PASS: Pass = Pass::Peephole;

fn get_options() -> Options {
    let mut result = Options {
        program_text:  Vec::new(),
        memory_size:   None,
        compiler_pass: DEFAULT_PASS,
        unchecked:     false,
    };

    let matches = build_clap_app().get_matches();

    if let Some(size) = matches.value_of("size") {
        let size = size.parse()
            .unwrap_or_else(|e|
                error_exit(1, format!("error: could not parse memory size: {}.", e)));
        if size == 0 {
            error_exit(1, "error: memory size must be at least 1.".to_owned());
        }
        result.memory_size = Some(size);
    }

    if matches.is_present("jit") {
        #[cfg(feature = "jit")]
        let _ = result.compiler_pass = Pass::Jit;
    } else if matches.is_present("llvm") {
        #[cfg(feature = "llvm")]
        let _ = result.compiler_pass = Pass::Llvm;
    } else if matches.is_present("byte") {
        result.compiler_pass = Pass::Bytecode;
    } else if matches.is_present("peep") {
        result.compiler_pass = Pass::Peephole;
    } else if matches.is_present("rle") {
        result.compiler_pass = Pass::Rle;
    } else if matches.is_present("ast") {
        result.compiler_pass = Pass::Ast;
    }

    if matches.is_present("unchecked") {
        result.unchecked = true;
    }

    if let Some(exprs) = matches.values_of("expr") {
        for e in exprs {
            result.program_text.extend(e.as_bytes());
        }
    } else if let Some(files) = matches.values_of("FILE") {
        for f in files {
            let mut file = File::open(f)
                .unwrap_or_else(|e| error_exit(1, format!("{}: ‘{}’.", e, f)));
            file.read_to_end(&mut result.program_text)
                .unwrap_or_else(|e| error_exit(1, format!("{}: ‘{}’.", e, f)));
        }
    } else {
        error_exit(1, "error: no program given.".to_owned());
    }

    result
}

fn build_clap_app() -> App<'static, 'static> {
    let app = App::new("bfi")
        .version(VERSION)
        .author("Jesse A. Tov <jesse.tov@gmail.com>")
        .about("A Brainfuck interpreter")
        .arg(Arg::with_name("expr")
            .short("e")
            .long("expr")
            .value_name("CODE")
            .help("BF code to execute")
            .multiple(true)
            .takes_value(true)
            .conflicts_with("FILE"))
        .arg(Arg::with_name("FILE")
            .help("The source file(s) to interpret")
            .multiple(true)
            .conflicts_with("expr")
            .index(1))
        .arg(Arg::with_name("size")
            .short("s")
            .long("size")
            .value_name("SIZE")
            .help("Memory size in bytes (default 30,000)")
            .takes_value(true))
        .arg(Arg::with_name("ast")
            .long("ast")
            .help("Interpret the unoptimized AST")
            .conflicts_with_all(&["rle", "peep", "byte", "jit", "llvm"]))
        .arg(Arg::with_name("rle")
            .long("rle")
            .help("Interpret the run-length encoded the AST")
            .conflicts_with_all(&["ast", "peep", "byte", "jit", "llvm"]))
        .arg(Arg::with_name("peep")
            .long("peep")
            .help(
                if cfg!(feature = "jit") {
                    "Interpret the peephole-optimized AST"
                } else {
                    "Interpret the peephole-optimized AST (default)"
                })
            .conflicts_with_all(&["ast", "rle", "byte", "jit", "llvm"]))
        .arg(Arg::with_name("byte")
            .long("byte")
            .help("Compile AST to bytecode")
            .conflicts_with_all(&["ast", "rle", "peep", "jit", "llvm"]));

    #[cfg(feature = "llvm")]
    let app = app
        .arg(Arg::with_name("llvm")
            .long("llvm")
            .help("JIT using LLVM")
            .conflicts_with_all(&["ast", "rle", "peep", "byte", "jit"]));

    #[cfg(feature = "jit")]
    let app = app
        .arg(Arg::with_name("jit")
            .long("jit")
            .help("JIT to native x64 (default)")
            .conflicts_with_all(&["ast", "rle", "peep", "byte", "llvm"]));

    #[cfg(any(feature = "jit"))]
    let app = app
        .arg(Arg::with_name("unchecked")
            .short("u")
            .long("unchecked")
            .help("Omit memory bounds checks in JIT")
            .conflicts_with_all(&["ast", "rle", "peep", "byte", "llvm"]));

    app
}

fn error_exit(code: i32, msg: String) -> ! {
    writeln!(io::stderr(), "bfi: {}", msg).unwrap();
    exit(code)
}

<|endoftext|>


<commit_before>use yoga_wrapper;

pub struct Text<'text> {
    node: yoga_wrapper::Node,
    text: &'text str,
}

impl<'text> Text<'text> {
    pub fn new(text: &'text str) -> Text<'text> {
        Text {
            node: yoga_wrapper::Node::new(),
            text: text,
        }
    }
}

#[cfg(test)]
mod tests {
    use yoga_wrapper;

    use Text;
    use Backend;
    use Renders;

    struct Renderer {}

    impl Renders for Renderer {
        fn render(&self, node: &yoga_wrapper::Node) {}
    }

    struct Measurer {}

    impl yoga_wrapper::Measures for Measurer {
        fn measure(&self, text: &str) -> yoga_wrapper::Size {
            yoga_wrapper::Size {
                width: text.len() as f32,
                height: 1.0,
            }
        }
    }

    struct TestBackend {
        renderer: Renderer,
        measurer: Measurer,
    }

    impl TestBackend {
        pub fn new() -> TestBackend {
            TestBackend {
                renderer: Renderer {},
                measurer: Measurer {},
            }
        }
    }

    impl<'meas> Backend<'meas> for TestBackend {
        type Color = i32;
        type Renderer = Renderer;
        type Measurer = Measurer;

        fn render(&self, node: &yoga_wrapper::Node) {}

        fn get_renderer(&self) -> &Self::Renderer {
            &self.renderer
        }

        fn create_context<'text>(&'meas self,
                                 text: &'text str)
                                 -> yoga_wrapper::Context<'text, 'meas> {
            yoga_wrapper::Context::new(text, &self.measurer)
        }
    }

    #[test]
    fn it_works() {
        let be = TestBackend::new();
        let _ = Text::new("yo!");
    }
}
<commit_msg>chore(Backend): update to be mut<commit_after>use yoga_wrapper;

pub struct Text<'text> {
    node: yoga_wrapper::Node,
    text: &'text str,
}

impl<'text> Text<'text> {
    pub fn new(text: &'text str) -> Text<'text> {
        Text {
            node: yoga_wrapper::Node::new(),
            text: text,
        }
    }
}

#[cfg(test)]
mod tests {
    use yoga_wrapper;

    use Text;
    use Backend;
    use Renders;

    struct Renderer {}

    impl Renders for Renderer {
        fn render(&mut self, node: &yoga_wrapper::Node) {}
    }

    struct Measurer {}

    impl yoga_wrapper::Measures for Measurer {
        fn measure(&self, text: &str) -> yoga_wrapper::Size {
            yoga_wrapper::Size {
                width: text.len() as f32,
                height: 1.0,
            }
        }
    }

    struct TestBackend {
        renderer: Renderer,
        measurer: Measurer,
    }

    impl TestBackend {
        pub fn new() -> TestBackend {
            TestBackend {
                renderer: Renderer {},
                measurer: Measurer {},
            }
        }
    }

    impl<'meas> Backend<'meas> for TestBackend {
        type Color = i32;
        type Renderer = Renderer;
        type Measurer = Measurer;

        fn render(&mut self, node: &yoga_wrapper::Node) {}

        fn get_renderer(&mut self) -> &mut Self::Renderer {
            &mut self.renderer
        }

        fn create_context<'text>(&'meas self,
                                 text: &'text str)
                                 -> yoga_wrapper::Context<'text, 'meas> {
            yoga_wrapper::Context::new(text, &self.measurer)
        }
    }

    #[test]
    fn it_works() {
        let be = TestBackend::new();
        let _ = Text::new("yo!");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use num_traits::*;
use std::fmt::{Debug, Display};
use std::mem::{size_of, MaybeUninit};

//TODO: Nice to have (although I wasn't able to find a way to do it yet in rust): zero-fill arrays that are
// shorter than required.  Need const fn (Rust Issue #24111) or const generics (Rust RFC #2000)
macro_rules! cdf {
    ($($x:expr),+) =>  {[$(32768 - $x),+, 0, 0]}
}

macro_rules! cdf_size {
  ($x:expr) => {
    $x + 1
  };
}

#[repr(align(32))]
pub struct Align32;

// A 16 byte aligned array.
// # Examples
// ```
// let mut x: AlignedArray<[i16; 64 * 64]> = AlignedArray([0; 64 * 64]);
// assert!(x.array.as_ptr() as usize % 16 == 0);
//
// let mut x: AlignedArray<[i16; 64 * 64]> = UninitializedAlignedArray();
// assert!(x.array.as_ptr() as usize % 16 == 0);
// ```
pub struct AlignedArray<ARRAY> {
  _alignment: [Align32; 0],
  pub array: ARRAY,
}

#[allow(non_snake_case)]
pub const fn AlignedArray<ARRAY>(array: ARRAY) -> AlignedArray<ARRAY> {
  AlignedArray { _alignment: [], array }
}

#[allow(non_snake_case)]
pub fn UninitializedAlignedArray<ARRAY>() -> AlignedArray<ARRAY> {
  AlignedArray(unsafe { MaybeUninit::uninit().assume_init() })
}

#[test]
fn sanity() {
  fn is_aligned<T>(ptr: *const T, n: usize) -> bool {
    ((ptr as usize) & ((1 << n) - 1)) == 0
  }

  let a: AlignedArray<_> = AlignedArray([0u8; 3]);
  assert!(is_aligned(a.array.as_ptr(), 4));
}

pub trait Fixed {
  fn floor_log2(&self, n: usize) -> usize;
  fn ceil_log2(&self, n: usize) -> usize;
  fn align_power_of_two(&self, n: usize) -> usize;
  fn align_power_of_two_and_shift(&self, n: usize) -> usize;
}

impl Fixed for usize {
  #[inline]
  fn floor_log2(&self, n: usize) -> usize {
    self & !((1 << n) - 1)
  }
  #[inline]
  fn ceil_log2(&self, n: usize) -> usize {
    (self + (1 << n) - 1).floor_log2(n)
  }
  #[inline]
  fn align_power_of_two(&self, n: usize) -> usize {
    self.ceil_log2(n)
  }
  #[inline]
  fn align_power_of_two_and_shift(&self, n: usize) -> usize {
    (self + (1 << n) - 1) >> n
  }
}

pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
  if input < min {
    min
  } else if input > max {
    max
  } else {
    input
  }
}

pub trait CastFromPrimitive<T>: Copy + 'static {
  fn cast_from(v: T) -> Self;
}

macro_rules! impl_cast_from_primitive {
  ( $T:ty => $U:ty ) => {
    impl CastFromPrimitive<$U> for $T {
      #[inline(always)]
      fn cast_from(v: $U) -> Self { v as Self }
    }
  };
  ( $T:ty => { $( $U:ty ),* } ) => {
    $( impl_cast_from_primitive!($T => $U); )*
  };
}

// casts to { u8, u16 } are implemented separately using Pixel, so that the
// compiler understands that CastFromPrimitive<T: Pixel> is always implemented
impl_cast_from_primitive!(u8 => { u32, u64, usize });
impl_cast_from_primitive!(u8 => { i8, i16, i32, i64, isize });
impl_cast_from_primitive!(u16 => { u32, u64, usize });
impl_cast_from_primitive!(u16 => { i8, i16, i32, i64, isize });
impl_cast_from_primitive!(i16 => { u32, u64, usize });
impl_cast_from_primitive!(i16 => { i8, i16, i32, i64, isize });
impl_cast_from_primitive!(i32 => { u32, u64, usize });
impl_cast_from_primitive!(i32 => { i8, i16, i32, i64, isize });

pub enum PixelType {
  U8,
  U16,
}

pub trait Pixel:
  PrimInt
  + Into<u32>
  + Into<i32>
  + AsPrimitive<u8>
  + AsPrimitive<i16>
  + AsPrimitive<u16>
  + AsPrimitive<i32>
  + AsPrimitive<u32>
  + AsPrimitive<usize>
  + CastFromPrimitive<u8>
  + CastFromPrimitive<i16>
  + CastFromPrimitive<u16>
  + CastFromPrimitive<i32>
  + CastFromPrimitive<u32>
  + CastFromPrimitive<usize>
  + Debug
  + Display
  + Send
  + Sync
  + 'static
{
  fn type_enum() -> PixelType;

  fn to_asm_stride(in_stride: usize) -> isize {
    (in_stride * size_of::<Self>()) as isize
  }
}

impl Pixel for u8 {
  fn type_enum() -> PixelType {
    PixelType::U8
  }
}

impl Pixel for u16 {
  fn type_enum() -> PixelType {
    PixelType::U16
  }
}

macro_rules! impl_cast_from_pixel_to_primitive {
  ( $T:ty ) => {
    impl<T: Pixel> CastFromPrimitive<T> for $T {
      #[inline(always)]
      fn cast_from(v: T) -> Self {
        v.as_()
      }
    }
  };
}

impl_cast_from_pixel_to_primitive!(u8);
impl_cast_from_pixel_to_primitive!(i16);
impl_cast_from_pixel_to_primitive!(u16);
impl_cast_from_pixel_to_primitive!(i32);
impl_cast_from_pixel_to_primitive!(u32);

pub trait ILog: PrimInt {
  // Integer binary logarithm of an integer value.
  // Returns floor(log2(self)) + 1, or 0 if self == 0.
  // This is the number of bits that would be required to represent self in two's
  //  complement notation with all of the leading zeros stripped.
  // TODO: Mark const once trait functions can be constant
  fn ilog(self) -> usize {
    size_of::<Self>() * 8 - self.leading_zeros() as usize
  }
}

impl<T> ILog for T where T: PrimInt {}

#[inline(always)]
pub fn msb(x: i32) -> i32 {
  debug_assert!(x > 0);
  31 ^ (x.leading_zeros() as i32)
}

#[inline(always)]
pub fn round_shift(value: i32, bit: usize) -> i32 {
  (value + (1 << bit >> 1)) >> bit
}
<commit_msg>Document CastFromPrimitive<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use num_traits::*;
use std::fmt::{Debug, Display};
use std::mem::{size_of, MaybeUninit};

//TODO: Nice to have (although I wasn't able to find a way to do it yet in rust): zero-fill arrays that are
// shorter than required.  Need const fn (Rust Issue #24111) or const generics (Rust RFC #2000)
macro_rules! cdf {
    ($($x:expr),+) =>  {[$(32768 - $x),+, 0, 0]}
}

macro_rules! cdf_size {
  ($x:expr) => {
    $x + 1
  };
}

#[repr(align(32))]
pub struct Align32;

// A 16 byte aligned array.
// # Examples
// ```
// let mut x: AlignedArray<[i16; 64 * 64]> = AlignedArray([0; 64 * 64]);
// assert!(x.array.as_ptr() as usize % 16 == 0);
//
// let mut x: AlignedArray<[i16; 64 * 64]> = UninitializedAlignedArray();
// assert!(x.array.as_ptr() as usize % 16 == 0);
// ```
pub struct AlignedArray<ARRAY> {
  _alignment: [Align32; 0],
  pub array: ARRAY,
}

#[allow(non_snake_case)]
pub const fn AlignedArray<ARRAY>(array: ARRAY) -> AlignedArray<ARRAY> {
  AlignedArray { _alignment: [], array }
}

#[allow(non_snake_case)]
pub fn UninitializedAlignedArray<ARRAY>() -> AlignedArray<ARRAY> {
  AlignedArray(unsafe { MaybeUninit::uninit().assume_init() })
}

#[test]
fn sanity() {
  fn is_aligned<T>(ptr: *const T, n: usize) -> bool {
    ((ptr as usize) & ((1 << n) - 1)) == 0
  }

  let a: AlignedArray<_> = AlignedArray([0u8; 3]);
  assert!(is_aligned(a.array.as_ptr(), 4));
}

pub trait Fixed {
  fn floor_log2(&self, n: usize) -> usize;
  fn ceil_log2(&self, n: usize) -> usize;
  fn align_power_of_two(&self, n: usize) -> usize;
  fn align_power_of_two_and_shift(&self, n: usize) -> usize;
}

impl Fixed for usize {
  #[inline]
  fn floor_log2(&self, n: usize) -> usize {
    self & !((1 << n) - 1)
  }
  #[inline]
  fn ceil_log2(&self, n: usize) -> usize {
    (self + (1 << n) - 1).floor_log2(n)
  }
  #[inline]
  fn align_power_of_two(&self, n: usize) -> usize {
    self.ceil_log2(n)
  }
  #[inline]
  fn align_power_of_two_and_shift(&self, n: usize) -> usize {
    (self + (1 << n) - 1) >> n
  }
}

pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
  if input < min {
    min
  } else if input > max {
    max
  } else {
    input
  }
}

/// Trait for casting between primitive types.
pub trait CastFromPrimitive<T>: Copy + 'static {
  /// Casts the given value into `Self`.
  fn cast_from(v: T) -> Self;
}

macro_rules! impl_cast_from_primitive {
  ( $T:ty => $U:ty ) => {
    impl CastFromPrimitive<$U> for $T {
      #[inline(always)]
      fn cast_from(v: $U) -> Self { v as Self }
    }
  };
  ( $T:ty => { $( $U:ty ),* } ) => {
    $( impl_cast_from_primitive!($T => $U); )*
  };
}

// casts to { u8, u16 } are implemented separately using Pixel, so that the
// compiler understands that CastFromPrimitive<T: Pixel> is always implemented
impl_cast_from_primitive!(u8 => { u32, u64, usize });
impl_cast_from_primitive!(u8 => { i8, i16, i32, i64, isize });
impl_cast_from_primitive!(u16 => { u32, u64, usize });
impl_cast_from_primitive!(u16 => { i8, i16, i32, i64, isize });
impl_cast_from_primitive!(i16 => { u32, u64, usize });
impl_cast_from_primitive!(i16 => { i8, i16, i32, i64, isize });
impl_cast_from_primitive!(i32 => { u32, u64, usize });
impl_cast_from_primitive!(i32 => { i8, i16, i32, i64, isize });

pub enum PixelType {
  U8,
  U16,
}

pub trait Pixel:
  PrimInt
  + Into<u32>
  + Into<i32>
  + AsPrimitive<u8>
  + AsPrimitive<i16>
  + AsPrimitive<u16>
  + AsPrimitive<i32>
  + AsPrimitive<u32>
  + AsPrimitive<usize>
  + CastFromPrimitive<u8>
  + CastFromPrimitive<i16>
  + CastFromPrimitive<u16>
  + CastFromPrimitive<i32>
  + CastFromPrimitive<u32>
  + CastFromPrimitive<usize>
  + Debug
  + Display
  + Send
  + Sync
  + 'static
{
  fn type_enum() -> PixelType;

  fn to_asm_stride(in_stride: usize) -> isize {
    (in_stride * size_of::<Self>()) as isize
  }
}

impl Pixel for u8 {
  fn type_enum() -> PixelType {
    PixelType::U8
  }
}

impl Pixel for u16 {
  fn type_enum() -> PixelType {
    PixelType::U16
  }
}

macro_rules! impl_cast_from_pixel_to_primitive {
  ( $T:ty ) => {
    impl<T: Pixel> CastFromPrimitive<T> for $T {
      #[inline(always)]
      fn cast_from(v: T) -> Self {
        v.as_()
      }
    }
  };
}

impl_cast_from_pixel_to_primitive!(u8);
impl_cast_from_pixel_to_primitive!(i16);
impl_cast_from_pixel_to_primitive!(u16);
impl_cast_from_pixel_to_primitive!(i32);
impl_cast_from_pixel_to_primitive!(u32);

pub trait ILog: PrimInt {
  // Integer binary logarithm of an integer value.
  // Returns floor(log2(self)) + 1, or 0 if self == 0.
  // This is the number of bits that would be required to represent self in two's
  //  complement notation with all of the leading zeros stripped.
  // TODO: Mark const once trait functions can be constant
  fn ilog(self) -> usize {
    size_of::<Self>() * 8 - self.leading_zeros() as usize
  }
}

impl<T> ILog for T where T: PrimInt {}

#[inline(always)]
pub fn msb(x: i32) -> i32 {
  debug_assert!(x > 0);
  31 ^ (x.leading_zeros() as i32)
}

#[inline(always)]
pub fn round_shift(value: i32, bit: usize) -> i32 {
  (value + (1 << bit >> 1)) >> bit
}
<|endoftext|>